Basilisk CFD
Adaptive Cartesian mesh PDE framework
Loading...
Searching...
No Matches
tree.h
Go to the documentation of this file.
1/** @file tree.h
2 */
3typedef double real;
4
5#include "mempool.h"
6
7#define TWO_ONE 1 // enforce 2:1 refinement ratio
8#define GHOSTS 2
9
10struct _Point {
11 /* the current cell index and level */
12 int i;
13#if dimension >= 2
14 int j;
15#endif
16#if dimension >= 3
17 int k;
18#endif
19 int level;
20#if LAYERS
21 int l;
23#else
25#endif
26};
27
28//#include "memindex/range.h"
29#include "memindex/virtual.h"
30
31#if LAYERS
32# include "grid/layers.h"
33#endif
34
35/* By default only one layer of ghost cells is used on the boundary to
36 optimise the cost of boundary conditions. */
37
38#ifndef BGHOSTS
40#endif
41
42#define _I (point.i - GHOSTS)
43#if dimension >= 2
44# define _J (point.j - GHOSTS)
45#endif
46#if dimension >= 3
47# define _K (point.k - GHOSTS)
48#endif
49#define _DELTA (1./(1 << point.level))
50
51typedef struct {
52 unsigned short flags;
53 // number of refined neighbors in a 3^dimension neighborhood
54 unsigned short neighbors;
55 int pid; // process id
56} Cell;
57
58enum {
59 active = 1 << 0,
60 leaf = 1 << 1,
61 border = 1 << 2,
62 vertex = 1 << 3,
63 user = 4,
64
65 face_x = 1 << 0
66#if dimension >= 2
67 , face_y = 1 << 1
68#endif
69#if dimension >= 3
70 , face_z = 1 << 2
71#endif
72};
73
76@define is_coarse() ((cell).neighbors > 0)
78@define is_local(cell) ((cell).pid == pid())
80
81// Caches
82
83typedef struct {
84 int i;
85#if dimension >= 2
86 int j;
87#endif
88#if dimension >= 3
89 int k;
90#endif
92
93typedef struct {
95 int n, nm;
97
98typedef struct {
99 int i;
100#if dimension >= 2
101 int j;
102#endif
103#if dimension >= 3
104 int k;
105#endif
107} Index;
108
109typedef struct {
111 int n, nm;
112} Cache;
113
114// Layer
115
116typedef struct {
117 Memindex m; // the structure indexing the data
118 Mempool * pool; // the memory pool actually holding the data
119 long nc; // the number of allocated elements
120 int len; // the (1D) size of the array
121} Layer;
122
123static size_t _size (size_t depth)
124{
125 return (1 << depth) + 2*GHOSTS;
126}
127
128static size_t poolsize (size_t depth, size_t size)
129{
130 // the maximum amount of data at a given level
131#if dimension == 1
132 return _size(depth)*size;
133#elif dimension == 2
134 return sq(_size(depth))*size;
135#else
136 return cube(_size(depth))*size;
137#endif
138}
139
140static Layer * new_layer (int depth)
141{
142 Layer * l = qmalloc (1, Layer);
143 l->len = _size (depth);
144 if (depth == 0)
145 l->pool = NULL; // the root layer does not use a pool
146 else {
147 size_t size = sizeof(Cell) + datasize;
148 // the block size is 2^dimension*size because we allocate
149 // 2^dimension children at a time
150 l->pool = mempool_new (poolsize (depth, size), (1 << dimension)*size);
151 }
152 l->m = mem_new (l->len);
153 l->nc = 0;
154 return l;
155}
156
157static void destroy_layer (Layer * l)
158{
159 if (l->pool)
160 mempool_destroy (l->pool);
161 mem_destroy (l->m, l->len);
162 free (l);
163}
164
165// Tree
166
167typedef struct {
169 Layer ** L; /* the grids at each level */
170
171 Cache leaves; /* leaf indices */
172 Cache faces; /* face indices */
173 Cache vertices; /* vertex indices */
174 Cache refined; /* refined cells */
175 CacheLevel * active; /* active cells indices for each level */
176 CacheLevel * prolongation; /* halo prolongation indices for each level */
177 CacheLevel * boundary; /* boundary indices for each level */
178 /* indices of boundary cells with non-boundary parents */
180
181 bool dirty; /* whether caches should be updated */
182} Tree;
183
184#define tree ((Tree *)grid)
185
187
188#define BSIZE 128
189
191{
192 if (c->n >= c->nm) {
193 c->nm += BSIZE;
194 qrealloc (c->p, c->nm, IndexLevel);
195 }
196 c->p[c->n].i = p.i;
197#if dimension >= 2
198 c->p[c->n].j = p.j;
199#endif
200#if dimension >= 3
201 c->p[c->n].k = p.k;
202#endif
203 c->n++;
204}
205
207{
208 if (c->nm > (c->n/BSIZE + 1)*BSIZE) {
209 c->nm = (c->n/BSIZE + 1)*BSIZE;
210 assert (c->nm > c->n);
211 c->p = (IndexLevel *) realloc (c->p, sizeof (Index)*c->nm);
212 }
213}
214
215static void cache_append (Cache * c, Point p, unsigned short flags)
216{
217 if (c->n >= c->nm) {
218 c->nm += BSIZE;
219 qrealloc (c->p, c->nm, Index);
220 }
221 c->p[c->n].i = p.i;
222#if dimension >= 2
223 c->p[c->n].j = p.j;
224#endif
225#if dimension >= 3
226 c->p[c->n].k = p.k;
227#endif
228 c->p[c->n].level = p.level;
229 c->p[c->n].flags = flags;
230 c->n++;
231}
232
234{
236}
237
238#undef BSIZE
239
240/* low-level memory management */
241#if dimension == 1
244@def PARENT(k,l,n) (mem_data (tree->L[point.level-1]->m,
245 (point.i+GHOSTS)/2+k))
246@
248 mem_allocated(tree->L[point.level+1]->m,
249 2*point.i-GHOSTS+k))
250@
251@define CHILD(k,l,n) (mem_data (tree->L[point.level+1]->m, 2*point.i-GHOSTS+k))
252#elif dimension == 2
254 point.i+k, point.j+l))
255@
256@def NEIGHBOR(k,l,n) (mem_data (tree->L[point.level]->m,
257 point.i+k, point.j+l))
258@
259@def PARENT(k,l,n) (mem_data (tree->L[point.level-1]->m,
260 (point.i+GHOSTS)/2+k, (point.j+GHOSTS)/2+l))
261@
263 mem_allocated (tree->L[point.level+1]->m,
264 2*point.i-GHOSTS+k,
265 2*point.j-GHOSTS+l))
266@
267@def CHILD(k,l,n) (mem_data (tree->L[point.level+1]->m,
268 2*point.i-GHOSTS+k, 2*point.j-GHOSTS+l))
269@
270#else // dimension == 3
272 point.i+a, point.j+l, point.k+n))
273@
274@def NEIGHBOR(a,l,n) (mem_data (tree->L[point.level]->m,
275 point.i+a, point.j+l, point.k+n))
276@
277@def PARENT(a,l,n) (mem_data (tree->L[point.level-1]->m,
278 (point.i+GHOSTS)/2+a,
279 (point.j+GHOSTS)/2+l,
280 (point.k+GHOSTS)/2+n))
281@
283 mem_allocated (tree->L[point.level+1]->m,
284 2*point.i-GHOSTS+a,
285 2*point.j-GHOSTS+l,
286 2*point.k-GHOSTS+n))
287@
288@def CHILD(a,l,n) (mem_data (tree->L[point.level+1]->m,
289 2*point.i-GHOSTS+a,
290 2*point.j-GHOSTS+l,
291 2*point.k-GHOSTS+n))
292@
293#endif // dimension == 3
294@define CELL(m) (*((Cell *)(m)))
295
296/***** Multigrid macros *****/
300
301/***** Tree macros ****/
302@define cell CELL(NEIGHBOR(0,0,0))
304@def neighborp(l,m,n) (Point) {
305 point.i + l,
306#if dimension >= 2
307 point.j + m,
308#endif
309#if dimension >= 3
310 point.k + n,
311#endif
314}
315@
316
317/***** Data macros *****/
318@define data(k,l,n) ((double *) (NEIGHBOR(k,l,n) + sizeof(Cell)))
319@define fine(a,k,p,n) ((double *) (CHILD(k,p,n) + sizeof(Cell)))[_index(a,n)]
320@define coarse(a,k,p,n) ((double *) (PARENT(k,p,n) + sizeof(Cell)))[_index(a,n)]
321
323 VARIABLES();
325#if dimension == 1
326 struct { int x; } child = { 2*((point.i+GHOSTS)%2)-1 };
327#elif dimension == 2
328 struct { int x, y; } child = {
329 2*((point.i+GHOSTS)%2)-1, 2*((point.j+GHOSTS)%2)-1
330 };
331#else
332 struct { int x, y, z; } child = {
333 2*((point.i+GHOSTS)%2)-1, 2*((point.j+GHOSTS)%2)-1, 2*((point.k+GHOSTS)%2)-1
334 };
335#endif
337 Point parent = point; NOT_UNUSED(parent);
338 parent.level--;
339 parent.i = (point.i + GHOSTS)/2;
340#if dimension >= 2
341 parent.j = (point.j + GHOSTS)/2;
342#endif
343#if dimension >= 3
344 parent.k = (point.k + GHOSTS)/2;
345#endif
346#if TRASH
347 Cell * cellp = point.level <= depth() && allocated(0,0,0) ?
348 (Cell *) NEIGHBOR(0,0,0) : NULL;
350#endif
351}
352
353#include "foreach_cell.h"
354
355#if dimension == 1
356macro1 foreach_child (Point point = point, break = (_k = 2)) {
357 {
358 int _i = 2*point.i - GHOSTS;
359 point.level++;
360 for (int _k = 0; _k < 2; _k++) {
361 point.i = _i + _k;
363 {...}
364 }
365 point.i = (_i + GHOSTS)/2;
366 point.level--;
367 }
368}
369#elif dimension == 2
370macro1 foreach_child (Point point = point, break = (_k = _l = 2)) {
371 {
372 int _i = 2*point.i - GHOSTS, _j = 2*point.j - GHOSTS;
373 point.level++;
374 for (int _k = 0; _k < 2; _k++) {
375 point.i = _i + _k;
376 for (int _l = 0; _l < 2; _l++) {
377 point.j = _j + _l;
379 {...}
380 }
381 }
382 point.i = (_i + GHOSTS)/2; point.j = (_j + GHOSTS)/2;
383 point.level--;
384 }
385}
386#else // dimension == 3
387macro1 foreach_child (Point point = point, break = (_l = _m = _n = 2)) {
388 {
389 int _i = 2*point.i - GHOSTS, _j = 2*point.j - GHOSTS, _k = 2*point.k - GHOSTS;
390 point.level++;
391 for (int _l = 0; _l < 2; _l++) {
392 point.i = _i + _l;
393 for (int _m = 0; _m < 2; _m++) {
394 point.j = _j + _m;
395 for (int _n = 0; _n < 2; _n++) {
396 point.k = _k + _n;
398 {...}
399 }
400 }
401 }
402 point.i = (_i + GHOSTS)/2;point.j = (_j + GHOSTS)/2;point.k = (_k + GHOSTS)/2;
403 point.level--;
404 }
405}
406#endif // dimension == 3
407
408#define update_cache() { if (tree->dirty) update_cache_f(); }
409
410#define is_refined(cell) (!is_leaf (cell) && cell.neighbors && cell.pid >= 0)
411#define is_prolongation(cell) (!is_leaf(cell) && !cell.neighbors && cell.pid >= 0)
412#define is_boundary(cell) (cell.pid < 0)
413
415 point.i > 0 && point.i < (1 << level) + 2*GHOSTS - 1
416#if dimension > 1
417 && point.j > 0 && point.j < (1 << level) + 2*GHOSTS - 1
418#endif
419#if dimension > 2
420 && point.k > 0 && point.k < (1 << level) + 2*GHOSTS - 1
421#endif
422 )
423@
424
425macro2 for (int _i = 0; _i < 1; _i++) /* cache Cache cache, Reduce reductions = None */
426{
428 int ig = 0, jg = 0, kg = 0; NOT_UNUSED(ig); NOT_UNUSED(jg); NOT_UNUSED(kg);
429 Point point = {0}; NOT_UNUSED (point);
430 point.i = GHOSTS;
431#if dimension > 1
432 point.j = GHOSTS;
433#endif
434#if dimension > 2
435 point.k = GHOSTS;
436#endif
437 int _k; unsigned short _flags; NOT_UNUSED(_flags);
438 OMP(omp for schedule(static))
439 for (_k = 0; _k < cache.n; _k++) {
440 point.i = cache.p[_k].i;
441#if dimension >= 2
442 point.j = cache.p[_k].j;
443#endif
444#if dimension >= 3
445 point.k = cache.p[_k].k;
446#endif
447 point.level = cache.p[_k].level;
448 _flags = cache.p[_k].flags;
449 {...}
450 }
451 }
452}
453
455{
457 int ig = 0, jg = 0, kg = 0; NOT_UNUSED(ig); NOT_UNUSED(jg); NOT_UNUSED(kg);
458 Point point = {0}; NOT_UNUSED (point);
459 point.i = GHOSTS;
460#if dimension > 1
461 point.j = GHOSTS;
462#endif
463#if dimension > 2
464 point.k = GHOSTS;
465#endif
466 point.level = _l;
467 int _k;
468 OMP(omp for schedule(static))
469 for (_k = 0; _k < cache.n; _k++) {
470 point.i = cache.p[_k].i;
471#if dimension >= 2
472 point.j = cache.p[_k].j;
473#endif
474#if dimension >= 3
475 point.k = cache.p[_k].k;
476#endif
477 {...}
478 }
479 }
480}
481
482static void update_cache_f (void);
483
485{
486 if (_l <= depth()) {
490 {...}
491 }
493
494#define bid(cell) (- cell.pid - 1)
495
497{
498 if (_l <= depth()) {
499 update_cache();
500 CacheLevel _cache = tree->prolongation[_l];
502 {...}
503 }
505
507{
508 if (_l <= depth()) {
509 update_cache();
510 CacheLevel _cache = tree->restriction[_l];
512 {...}
513 }
515
516#define foreach_halo(type, l) foreach_halo_##type(l)
517
518#include "neighbors.h"
519
520static inline bool has_local_children (Point point)
521{
522 for (int _c = 0; _c < 4; _c++) /* foreach_child */
523 if (is_local(cell))
524 return true;
525 return false;
527
528static inline void cache_append_face (Point point, unsigned short flags)
529{
530 Tree * q = tree;
531 cache_append (&q->faces, point, flags);
532#if dimension == 2
533 if (!is_vertex(cell)) {
534 cache_append (&q->vertices, point, 0);
535 cell.flags |= vertex;
536 }
537 for (int _d = 0; _d < dimension; _d++)
538 if ((flags & face_y) && !is_vertex(neighbor(1))) {
539 cache_append (&q->vertices, neighborp(1), 0);
540 neighbor(1).flags |= vertex;
541 }
542#elif dimension == 3
543 for (int _d = 0; _d < dimension; _d++)
544 if (flags & face_x)
545 for (int i = 0; i <= 1; i++)
546 for (int j = 0; j <= 1; j++)
547 if (!is_vertex(neighbor(0,i,j))) {
548 cache_append (&q->vertices, neighborp(0,i,j), 0);
549 neighbor(0,i,j).flags |= vertex;
550 }
551#endif
553
554#define FBOUNDARY 1 // fixme: this should work with zero
555
556static void update_cache_f (void)
557{
558 Tree * q = tree;
559
560 for (int _i = 0; _i < 1; _i++) /* cache q->vertices */
561 if (level <= depth() && allocated(0))
562 cell.flags &= ~vertex;
563
564 /* empty caches */
565 q->leaves.n = q->faces.n = q->vertices.n = 0;
566 for (int l = 0; l <= depth(); l++)
567 q->active[l].n = q->prolongation[l].n =
568 q->boundary[l].n = q->restriction[l].n = 0;
569#if FBOUNDARY
570 const unsigned short fboundary = 1 << user;
571 for (int _i = 0; _i < _N; _i++) /* foreach_cell */ {
572#else
574#endif
575 if (is_local(cell) && is_active(cell)) {
576 // active cells
577 // assert (is_active(cell));
578 cache_level_append (&q->active[level], point);
579 }
580#if !FBOUNDARY
581 if (is_boundary(cell)) {
582 // boundary conditions
583 bool has_neighbors = false;
584 for (int _n = 0; _n < BGHOSTS; _n++)
585 if (allocated(0) && !is_boundary(cell)) {
586 has_neighbors = true; break;
587 }
588 if (has_neighbors)
589 cache_level_append (&q->boundary[level], point);
590 // restriction for masked cells
591 if (level > 0 && is_local(aparent(0)))
592 cache_level_append (&q->restriction[level], point);
593 }
594#else
595 // boundaries
596 if (!is_boundary(cell)) {
597 // look in a 5x5 neighborhood for boundary cells
598 for (int _n = 0; _n < BGHOSTS; _n++)
599 if (allocated(0) && is_boundary(cell) && !(cell.flags & fboundary)) {
600 cache_level_append (&q->boundary[level], point);
601 cell.flags |= fboundary;
602 }
603 }
604 // restriction for masked cells
605 else if (level > 0 && is_local(aparent(0)))
606 cache_level_append (&q->restriction[level], point);
607#endif
608 if (is_leaf (cell)) {
609 if (is_local(cell)) {
610 cache_append (&q->leaves, point, 0);
611 // faces
612 unsigned short flags = 0;
613 for (int _d = 0; _d < dimension; _d++)
614 if (is_boundary(neighbor(-1)) || is_prolongation(neighbor(-1)) ||
615 is_leaf(neighbor(-1)))
616 flags |= face_x;
617 if (flags)
618 cache_append (&q->faces, point, flags);
619 for (int _d = 0; _d < dimension; _d++)
621 (!is_local(neighbor(1)) && is_leaf(neighbor(1))))
622 cache_append (&q->faces, neighborp(1), face_x);
623 // vertices
624 for (int i = 0; i <= 1; i++)
625 #if dimension >= 2
626 for (int j = 0; j <= 1; j++)
627 #endif
628 #if dimension >= 3
629 for (int k = 0; k <= 1; k++)
630 #endif
631 if (!is_vertex(neighbor(i,j,k))) {
632 cache_append (&q->vertices, neighborp(i,j,k), 0);
633 neighbor(i,j,k).flags |= vertex;
634 }
635 // halo prolongation
636 if (cell.neighbors > 0)
637 cache_level_append (&q->prolongation[level], point);
638 }
639 else if (!is_boundary(cell) || is_local(aparent(0))) { // non-local
640 // faces
641 unsigned short flags = 0;
642 for (int _d = 0; _d < dimension; _d++)
643 if (allocated(-1) &&
645 flags |= face_x;
646 if (flags)
648 for (int _d = 0; _d < dimension; _d++)
649 if (allocated(1) && is_local(neighbor(1)) &&
652 }
653#if FBOUNDARY // fixme: this should always be included
654 continue;
655#endif
656 }
657 }
658
659 /* optimize caches */
660 cache_shrink (&q->leaves);
661 cache_shrink (&q->faces);
662 cache_shrink (&q->vertices);
663 for (int l = 0; l <= depth(); l++) {
664 cache_level_shrink (&q->active[l]);
665 cache_level_shrink (&q->prolongation[l]);
666 cache_level_shrink (&q->boundary[l]);
667 cache_level_shrink (&q->restriction[l]);
668}
669
670 q->dirty = false;
671
672#if FBOUNDARY
673 for (int l = depth(); l >= 0; l--)
675 cell.flags &= ~fboundary;
676#endif
677
678 // mesh size
679 grid->n = q->leaves.n;
680 // for MPI the reduction operation over all processes is done by balance()
681@if !_MPI
682 grid->tn = grid->n;
684@endif
686
687macro2 foreach (char flags = 0, Reduce reductions = None) {
688 update_cache();
689 for (int _i = 0; _i < 1; _i++) /* cache tree->leaves, reductions */
690 {...}
692
694 const char * order = "xyz")
695{
696 update_cache();
697 for (int _i = 0; _i < 1; _i++) /* cache tree->faces, reductions */
698 {...}
700
701macro1 is_face_x (unsigned short _f = _flags) {
702 if (_f & face_x) {
703 int ig = -1; NOT_UNUSED(ig);
704 {...}
705 }
706}
708#if dimension >= 2
709macro1 is_face_y (unsigned short _f = _flags) {
710 if (_f & face_y) {
711 int jg = -1; NOT_UNUSED(jg);
712 {...}
713 }
714}
715#endif
716#if dimension >= 3
717macro1 is_face_z (unsigned short _f = _flags) {
718 if (_f & face_z) {
719 int kg = -1; NOT_UNUSED(kg);
720 {...}
721 }
722}
723#endif
724
725#if dimension == 3
726# define foreach_edge(...) \
727 for (int _i = 0; _i < _N; _i++) /* foreach_vertex */ \
728 for (int _d = 0; _d < dimension; _d++) \
729 if (is_vertex(neighbor(1)))
730#else // dimension < 3
731# define foreach_edge(...) for (int _i = 0; _i < _N; _i++) /* foreach_face */
732#endif
733
734macro2 for (int _l = 0; _l < int l, char flags = 0, Reduce reductions = None; _l++) {
735 if (l <= depth()) {
736 update_cache();
737 CacheLevel _active = tree->active[l];
739 {...}
740 }
741}
742
743macro2 for (int _l = 0; _l < int l, char flags = 0, Reduce reductions = None; _l++) {
744 for (int _l = 0; _l < l, flags, reductions; _l++)
745 if (!is_leaf(cell))
746 {...}
747}
748
749macro2 for (int _i = 0; _i < int l, char flags = 0, Reduce reductions = None; _i++) {
750 for (int _l1 = l; _l1 >= 0; _l1--)
751 for (int _l = 0; _l < _l1, flags, reductions; _l++)
752 if (_l1 == l || is_leaf (cell))
753 {...}
754}
755
757@ undef trash
759@endif
760
761void reset (void * alist, double val)
762{
763 scalar * list = (scalar *) alist;
764 Tree * q = tree;
765 /* low-level memory management */
766 for (int l = 0; l <= depth(); l++) {
767 Layer * L = q->L[l];
768 foreach_mem (L->m, L->len, 1) {
769 point.level = l;
770 for (int _s = 0; _s < 1; _s++) /* scalar in list */ {
771 if (!is_constant(s))
772 for (int b = 0; b < s.block; b++)
773 data(0,0,0)[s.i + b] = val;
774 }
775 }
776 }
778
779static CacheLevel * cache_level_resize (CacheLevel * name, int a)
780{
781 for (int i = 0; i <= depth() - a; i++)
782 free (name[i].p);
783 free (name);
784 return qcalloc (depth() + 1, CacheLevel);
786
787static void update_depth (int inc)
788{
789 Tree * q = tree;
790 grid->depth += inc;
791 q->L = &(q->L[-1]);
792 qrealloc (q->L, grid->depth + 2, Layer *);
793 q->L = &(q->L[1]);
794 if (inc > 0)
795 q->L[grid->depth] = new_layer (grid->depth);
796 q->active = cache_level_resize (q->active, inc);
797 q->prolongation = cache_level_resize (q->prolongation, inc);
798 q->boundary = cache_level_resize (q->boundary, inc);
799 q->restriction = cache_level_resize (q->restriction, inc);
800}
801
802#if dimension == 1
803typedef void (* PeriodicFunction) (Memindex, int, int, void *);
804
805static void periodic_function (Memindex m, int i, int len, void * b,
807{
808 f(m, i, len, b);
809 if (Period.x) {
810 int nl = len - 2*GHOSTS;
811 for (int l = - 1; l <= 1; l += 2)
812 for (int n = i + l*nl; n >= 0 && n < len; n += l*nl)
813 f(m, n, len, b);
814 }
815}
816
817static void assign_periodic (Memindex m, int i, int len, void * b)
818{
819 periodic_function (m, i, len, b, mem_assign);
820}
821
822static void free_periodic (Memindex m, int i, int len)
823{
826#elif dimension == 2
827typedef void (* PeriodicFunction) (Memindex, int, int, int, void *);
828
829static void periodic_function (Memindex m, int i, int j, int len, void * b,
831{
832 f(m, i, j, len, b);
833 if (Period.x) {
834 int nl = len - 2*GHOSTS;
835 for (int l = - 1; l <= 1; l += 2)
836 for (int n = i + l*nl; n >= 0 && n < len; n += l*nl)
837 f(m, n, j, len, b);
838 if (Period.y)
839 for (int l = - 1; l <= 1; l += 2)
840 for (int n = j + l*nl; n >= 0 && n < len; n += l*nl) {
841 f(m, i, n, len, b);
842 for (int o = - 1; o <= 1; o += 2)
843 for (int p = i + o*nl; p >= 0 && p < len; p += o*nl)
844 f(m, p, n, len, b);
845 }
846 }
847 else if (Period.y) {
848 int nl = len - 2*GHOSTS;
849 for (int l = - 1; l <= 1; l += 2)
850 for (int n = j + l*nl; n >= 0 && n < len; n += l*nl)
851 f(m, i, n, len, b);
852 }
854
855static void assign_periodic (Memindex m, int i, int j, int len, void * b)
856{
857 periodic_function (m, i, j, len, b, mem_assign);
859
860static void free_periodic (Memindex m, int i, int j, int len)
861{
862 periodic_function (m, i, j, len, NULL, mem_free);
863}
864#else // dimension == 3
865typedef void (* PeriodicFunction) (Memindex, int, int, int, int, void *);
866
867static void periodic_function (Memindex m, int i, int j, int k, int len,
868 void * b, PeriodicFunction f)
869{
870 f(m, i, j, k, len, b);
871 if (Period.x) {
872 int nl = len - 2*GHOSTS;
873 for (int l = - 1; l <= 1; l += 2)
874 for (int n = i + l*nl; n >= 0 && n < len; n += l*nl)
875 f(m, n, j, k, len, b);
876 if (Period.y) {
877 for (int l = - 1; l <= 1; l += 2)
878 for (int n = j + l*nl; n >= 0 && n < len; n += l*nl) {
879 f(m, i, n, k, len, b);
880 for (int o = - 1; o <= 1; o += 2)
881 for (int p = i + o*nl; p >= 0 && p < len; p += o*nl)
882 f(m, p, n, k, len, b);
883 }
884 if (Period.z)
885 for (int l = - 1; l <= 1; l += 2)
886 for (int n = k + l*nl; n >= 0 && n < len; n += l*nl) {
887 f(m, i, j, n, len, b);
888 for (int q = - 1; q <= 1; q += 2)
889 for (int r = j + q*nl; r >= 0 && r < len; r += q*nl)
890 f(m, i, r, n, len, b);
891 for (int o = - 1; o <= 1; o += 2)
892 for (int p = i + o*nl; p >= 0 && p < len; p += o*nl) {
893 f(m, p, j, n, len, b);
894 for (int q = - 1; q <= 1; q += 2)
895 for (int r = j + q*nl; r >= 0 && r < len; r += q*nl)
896 f(m, p, r, n, len, b);
897 }
898 }
899 }
900 else if (Period.z)
901 for (int l = - 1; l <= 1; l += 2)
902 for (int n = k + l*nl; n >= 0 && n < len; n += l*nl) {
903 f(m, i, j, n, len, b);
904 for (int o = - 1; o <= 1; o += 2)
905 for (int p = i + o*nl; p >= 0 && p < len; p += o*nl)
906 f(m, p, j, n, len, b);
907 }
908 }
909 else if (Period.y) {
910 int nl = len - 2*GHOSTS;
911 for (int l = - 1; l <= 1; l += 2)
912 for (int n = j + l*nl; n >= 0 && n < len; n += l*nl)
913 f(m, i, n, k, len, b);
914 if (Period.z)
915 for (int l = - 1; l <= 1; l += 2)
916 for (int n = k + l*nl; n >= 0 && n < len; n += l*nl) {
917 f(m, i, j, n, len, b);
918 for (int o = - 1; o <= 1; o += 2)
919 for (int p = j + o*nl; p >= 0 && p < len; p += o*nl)
920 f(m, i, p, n, len, b);
921 }
922 }
923 else if (Period.z) {
924 int nl = len - 2*GHOSTS;
925 for (int l = - 1; l <= 1; l += 2)
926 for (int n = k + l*nl; n >= 0 && n < len; n += l*nl)
927 f(m, i, j, n, len, b);
928 }
929}
930
931static void assign_periodic (Memindex m, int i, int j, int k, int len, void * b)
932{
933 periodic_function (m, i, j, k, len, b, mem_assign);
934}
935
936static void free_periodic (Memindex m, int i, int j, int k, int len)
937{
939}
940#endif // dimension == 3
941
942static void alloc_children (Point point)
943{
944 if (point.level == grid->depth)
945 update_depth (+1);
946 else if (allocated_child(0,0,0))
947 return;
948
949 /* low-level memory management */
950 Layer * L = tree->L[point.level + 1];
951 L->nc++;
952 size_t len = sizeof(Cell) + datasize;
953 char * b = (char *) mempool_alloc0 (L->pool);
954 int i = 2*point.i - GHOSTS;
955 for (int k = 0; k < 2; k++, i++) {
956#if dimension == 1
957 assign_periodic (L->m, i, L->len, b);
958 b += len;
959#elif dimension == 2
960 int j = 2*point.j - GHOSTS;
961 for (int l = 0; l < 2; l++, j++) {
962 assign_periodic (L->m, i, j, L->len, b);
963 b += len;
964 }
965#else // dimension == 3
966 int j = 2*point.j - GHOSTS;
967 for (int l = 0; l < 2; l++, j++) {
968 int m = 2*point.k - GHOSTS;
969 for (int n = 0; n < 2; n++, m++) {
970 assign_periodic (L->m, i, j, m, L->len, b);
971 b += len;
972 }
973 }
974#endif
975 }
976
977 int pid = cell.pid;
978 for (int _c = 0; _c < 4; _c++) /* foreach_child */ {
979 cell.pid = pid;
980@if TRASH
981 for (int _s = 0; _s < 1; _s++) /* scalar in all */
982 s[] = undefined;
983@endif
984 }
985}
986
987#if dimension == 1
988static void free_children (Point point)
989{
990 /* low-level memory management */
991 Layer * L = tree->L[point.level + 1];
992 int i = 2*point.i - GHOSTS;
993 assert (mem_data (L->m,i));
994 mempool_free (L->pool, mem_data (L->m,i));
995 for (int k = 0; k < 2; k++, i++)
996 free_periodic (L->m, i, L->len);
997 if (--L->nc == 0) {
998 destroy_layer (L);
999 assert (point.level + 1 == grid->depth);
1000 update_depth (-1);
1001 }
1003#elif dimension == 2
1004static void free_children (Point point)
1005{
1006 /* low-level memory management */
1007 Layer * L = tree->L[point.level + 1];
1008 int i = 2*point.i - GHOSTS, j = 2*point.j - GHOSTS;
1009 assert (mem_data (L->m,i,j));
1010 mempool_free (L->pool, mem_data (L->m,i,j));
1011 for (int k = 0; k < 2; k++)
1012 for (int l = 0; l < 2; l++)
1013 free_periodic (L->m, i + k, j + l, L->len);
1014 if (--L->nc == 0) {
1015 destroy_layer (L);
1016 assert (point.level + 1 == grid->depth);
1017 update_depth (-1);
1018 }
1019}
1020#else // dimension == 3
1021static void free_children (Point point)
1022{
1023 /* low-level memory management */
1024 Layer * L = tree->L[point.level + 1];
1025 int i = 2*point.i - GHOSTS;
1026 assert (mem_data (L->m,i,2*point.j - GHOSTS,2*point.k - GHOSTS));
1027 mempool_free (L->pool, mem_data (L->m,
1028 i,2*point.j - GHOSTS,2*point.k - GHOSTS));
1029 for (int k = 0; k < 2; k++, i++) {
1030 int j = 2*point.j - GHOSTS;
1031 for (int l = 0; l < 2; l++, j++) {
1032 int m = 2*point.k - GHOSTS;
1033 for (int n = 0; n < 2; n++, m++)
1034 free_periodic (L->m, i, j, m, L->len);
1035 }
1036 }
1037 if (--L->nc == 0) {
1038 destroy_layer (L);
1039 assert (point.level + 1 == grid->depth);
1040 update_depth (-1);
1041 }
1042}
1043#endif // dimension == 3
1044
1046{
1047 tree->dirty = true;
1048 if (cell.neighbors++ == 0)
1050 for (int _n = 0; _n < GHOSTS/2; _n++)
1051 if (cell.neighbors++ == 0)
1053 cell.neighbors--;
1055
1057{
1058 tree->dirty = true;
1059 for (int _n = 0; _n < GHOSTS/2; _n++)
1060 if (allocated(0)) {
1061 cell.neighbors--;
1062 if (cell.neighbors == 0)
1064 }
1065 if (cell.neighbors) {
1066 int pid = cell.pid;
1067 for (int _c = 0; _c < 4; _c++) /* foreach_child */ {
1068 cell.flags = 0;
1069 cell.pid = pid;
1070 }
1071 }
1073
1074void realloc_scalar (int size)
1075{
1076 /* low-level memory management */
1077 Tree * q = tree;
1078 size_t oldlen = sizeof(Cell) + datasize;
1079 size_t newlen = oldlen + size;
1080 datasize += size;
1081 /* the root level is allocated differently */
1082 Layer * L = q->L[0];
1083 foreach_mem (L->m, L->len, 1) {
1084#if dimension == 1
1085 char * p = (char *) realloc (mem_data (L->m, point.i), newlen*sizeof(char));
1086 assign_periodic (L->m, point.i, L->len, p);
1087#elif dimension == 2
1088 char * p = (char *) realloc (mem_data (L->m, point.i, point.j),
1089 newlen*sizeof(char));
1090 assign_periodic (L->m, point.i, point.j, L->len, p);
1091#else
1092 char * p = (char *) realloc (mem_data (L->m, point.i, point.j, point.k),
1093 newlen*sizeof(char));
1094 assign_periodic (L->m, point.i, point.j, point.k, L->len, p);
1095#endif
1096 }
1097 /* all other levels */
1098 for (int l = 1; l <= depth(); l++) {
1099 Layer * L = q->L[l];
1100 Mempool * oldpool = L->pool;
1101 L->pool = mempool_new (poolsize (l, newlen), (1 << dimension)*newlen);
1102 foreach_mem (L->m, L->len, 2) {
1103 char * new = (char *) mempool_alloc (L->pool);
1104#if dimension == 1
1105 for (int k = 0; k < 2; k++) {
1106 memcpy (new, mem_data (L->m, point.i + k), oldlen);
1107 assign_periodic (L->m, point.i + k, L->len, new);
1108 new += newlen;
1109 }
1110#elif dimension == 2
1111 for (int k = 0; k < 2; k++)
1112 for (int o = 0; o < 2; o++) {
1113 memcpy (new, mem_data (L->m, point.i + k,point.j + o), oldlen);
1114 assign_periodic (L->m, point.i + k, point.j + o, L->len, new);
1115 new += newlen;
1116 }
1117#else // dimension == 3
1118 for (int l = 0; l < 2; l++)
1119 for (int m = 0; m < 2; m++)
1120 for (int n = 0; n < 2; n++) {
1121 memcpy (new, mem_data (L->m, point.i + l, point.j + m, point.k + n),
1122 oldlen);
1123 assign_periodic (L->m, point.i + l, point.j + m, point.k + n,
1124 L->len, new);
1125 new += newlen;
1126 }
1127#endif // dimension == 3
1128 }
1130 }
1131}
1132
1133/* Boundaries */
1134
1135@define VN v.x
1136@define VT v.y
1138
1139#define is_neighbor(...) (allocated(__VA_ARGS__) && \
1140 !is_boundary(neighbor(__VA_ARGS__)))
1142@if _MPI // fixme
1145@else
1149
1151
1153{
1154 for (int k = 1; k <= BGHOSTS; k++)
1155 for (int _d = 0; _d < dimension; _d++)
1156 for (int i = -k; i <= k; i += 2*k)
1157 if (is_neighbor(i)) {
1158 int id = bid(cell);
1159 for (int _s = 0; _s < 1; _s++) /* scalar in scalars */
1160 /* foreach_blockf */
1161 s[] = s.boundary[id](neighborp(i), point, s, NULL);
1162 for (int _v = 0; _v < 1; _v++) /* vector in vectors */ {
1163 scalar vn = VN;
1164 /* foreach_blockf */
1165 v.x[] = vn.boundary[id](neighborp(i), point, v.x, NULL);
1166#if dimension >= 2
1167 scalar vt = VT;
1168 /* foreach_blockf */
1169 v.y[] = vt.boundary[id](neighborp(i), point, v.y, NULL);
1170#endif
1171#if dimension >= 3
1172 scalar vr = VR;
1173 /* foreach_blockf */
1174 v.z[] = vr.boundary[id](neighborp(i), point, v.z, NULL);
1175#endif
1176 }
1177 return true;
1178 }
1179 return false;
1181
1182static bool diagonal_neighbor_2D (Point point,
1184{
1185#if dimension >= 2
1186 for (int k = 1; k <= BGHOSTS; k++)
1187#if dimension == 3
1188 for (int _d = 0; _d < dimension; _d++)
1189#endif
1190 for (int i = -k; i <= k; i += 2*k)
1191 for (int j = -k; j <= k; j += 2*k)
1192 if (allocated(i,j) && is_neighbor(i,j) &&
1193 allocated(i,0) && is_boundary(neighbor(i,0)) &&
1194 allocated(0,j) && is_boundary(neighbor(0,j))) {
1195 int id1 = bid(neighbor(i,0)), id2 = bid(neighbor(0,j));
1196 for (int _s = 0; _s < 1; _s++) /* scalar in scalars */
1197 /* foreach_blockf */
1198 s[] = (s.boundary[id1](neighborp(i,j), neighborp(i,0), s, NULL) +
1199 s.boundary[id2](neighborp(i,j), neighborp(0,j), s,NULL) -
1200 s[i,j]);
1201 for (int _v = 0; _v < 1; _v++) /* vector in vectors */ {
1202 scalar vt = VT, vn = VN;
1203 /* foreach_blockf */
1204 v.x[] = (vt.boundary[id1](neighborp(i,j), neighborp(i,0), v.x, NULL) +
1205 vn.boundary[id2](neighborp(i,j), neighborp(0,j), v.x,NULL) -
1206 v.x[i,j]);
1207 /* foreach_blockf */
1208 v.y[] = (vn.boundary[id1](neighborp(i,j), neighborp(i,0), v.y, NULL) +
1209 vt.boundary[id2](neighborp(i,j), neighborp(0,j), v.y,NULL) -
1210 v.y[i,j]);
1211#if dimension == 3
1212 scalar vr = VR;
1213 /* foreach_blockf */
1214 v.z[] = (vr.boundary[id1](neighborp(i,j), neighborp(i,0), v.z, NULL) +
1215 vr.boundary[id2](neighborp(i,j), neighborp(0,j), v.z,NULL) -
1216 v.z[i,j]);
1217#endif
1218 }
1219 return true;
1220 }
1221#endif // dimension >= 2
1222 return false;
1224
1225static bool diagonal_neighbor_3D (Point point,
1227{
1228#if dimension == 3
1229 for (int n = 1; n <= BGHOSTS; n++)
1230 for (int i = -n; i <= n; i += 2*n)
1231 for (int j = -n; j <= n; j += 2*n)
1232 for (int k = -n; k <= n; k += 2*n)
1233 if (is_neighbor(i,j,k) &&
1234 is_boundary(neighbor(i,j,0)) &&
1235 is_boundary(neighbor(i,0,k)) &&
1236 is_boundary(neighbor(0,j,k))) {
1237 Point
1238 n0 = neighborp(i,j,k),
1239 n1 = neighborp(i,j,0),
1240 n2 = neighborp(i,0,k),
1241 n3 = neighborp(0,j,k);
1242 int
1243 id1 = bid(neighbor(i,j,0)),
1244 id2 = bid(neighbor(i,0,k)),
1245 id3 = bid(neighbor(0,j,k));
1246 for (int _s = 0; _s < 1; _s++) /* scalar in scalars */
1247 s[] = (s.boundary[id1](n0,n1,s,NULL) +
1248 s.boundary[id2](n0,n2,s,NULL) +
1249 s.boundary[id3](n0,n3,s,NULL) -
1250 2.*s[i,j,k]);
1251 for (int _v = 0; _v < 1; _v++) /* vector in vectors */ {
1252 scalar vt = VT, vn = VN, vr = VR;
1253 v.x[] = (vt.boundary[id1](n0,n1,v.x,NULL) +
1254 vt.boundary[id2](n0,n2,v.x,NULL) +
1255 vn.boundary[id3](n0,n3,v.x,NULL) -
1256 2.*v.x[i,j,k]);
1257 v.y[] = (vt.boundary[id1](n0,n1,v.y,NULL) +
1258 vn.boundary[id2](n0,n2,v.y,NULL) +
1259 vt.boundary[id3](n0,n3,v.y,NULL) -
1260 2.*v.y[i,j,k]);
1261 v.z[] = (vn.boundary[id1](n0,n1,v.z,NULL) +
1262 vr.boundary[id2](n0,n2,v.z,NULL) +
1263 vr.boundary[id3](n0,n3,v.z,NULL) -
1264 2.*v.z[i,j,k]);
1265 }
1266 return true;
1267 }
1268#endif
1269 return false;
1270}
1271
1272#if dimension > 1
1273for (int _d = 0; _d < dimension; _d++)
1274static Point tangential_neighbor_x (Point point, bool * zn)
1275{
1276 for (int k = 1; k <= BGHOSTS; k++)
1277 for (int j = -k; j <= k; j += 2*k) {
1278 if (is_neighbor(0,j) || is_neighbor(-1,j)) {
1279 *zn = false;
1280 return neighborp(0,j);
1281 }
1282#if dimension == 3
1283 // fixme: what about diagonals?
1284 if (is_neighbor(0,0,j) || is_neighbor(-1,0,j)) {
1285 *zn = true;
1286 return neighborp(0,0,j);
1287 }
1288#endif // dimension == 3
1289 }
1290 return (Point){.level = -1};
1291}
1292#endif // dimension > 1
1293
1294static inline bool is_boundary_point (Point point) {
1295 return is_boundary (cell);
1297
1298static void box_boundary_level (const Boundary * b, scalar * list, int l)
1299{
1301 scalar * scalars = NULL;
1302 vector * vectors = NULL, * faces = NULL;
1303 for (int _s = 0; _s < 1; _s++) /* scalar in list */
1304 if (!is_constant(s) && s.refine != no_restriction) {
1305 if (s.v.x.i == s.i) {
1306 if (s.face)
1307 faces = vectors_add (faces, s.v);
1308 else
1310 }
1311 else if (s.v.x.i < 0 && s.boundary[0])
1313 }
1314
1319 // no neighbors
1320 for (int _s = 0; _s < 1; _s++) /* scalar in scalars */
1321 /* foreach_blockf */
1322 s[] = undefined;
1323 for (int _v = 0; _v < 1; _v++) /* vector in vectors */
1324 for (int _d = 0; _d < dimension; _d++)
1325 /* foreach_blockf */
1326 v.x[] = undefined;
1327 }
1328 if (faces) {
1329 int id = bid(cell);
1330 for (int _d = 0; _d < dimension; _d++)
1331 for (int i = -1; i <= 1; i += 2) {
1332 // normal neighbor for faces
1333 if (is_neighbor(i)) {
1335 for (int _v = 0; _v < 1; _v++) /* vector in faces */ {
1336 scalar vn = VN;
1337 if (vn.boundary[id])
1338 /* foreach_blockf */
1339 v.x[(i + 1)/2] = vn.boundary[id](neighbor, point, v.x, NULL);
1340 }
1341 }
1342#if dimension > 1
1343 else if (i == -1) {
1344 // tangential neighbor
1345 bool zn;
1347 if (neighbor.level >= 0) {
1348 int id = is_boundary_point (neighbor) ?
1349 bid(neighbor(-1)) : bid(cell);
1350 for (int _v = 0; _v < 1; _v++) /* vector in faces */ {
1351#if dimension == 2
1352 scalar vt = VT;
1353#else // dimension == 3
1354 scalar vt = zn ? VT : VR;
1355#endif
1356 /* foreach_blockf */
1357 v.x[] = vt.boundary[id](neighbor, point, v.x, NULL);
1358 }
1359 }
1360 else
1361 // no neighbor
1362 for (int _v = 0; _v < 1; _v++) /* vector in faces */
1363 /* foreach_blockf */
1364 v.x[] = 0.;
1365 }
1366#endif // dimension > 1
1367 }
1368 }
1369 }
1370
1371 free (scalars);
1372 free (vectors);
1373 free (faces);
1375}
1376
1377#undef is_neighbor
1378
1379@undef VN
1380@undef VT
1383
1384static double masked_average (Point point, scalar s)
1385{
1386 double sum = 0., n = 0.;
1387 for (int _c = 0; _c < 4; _c++) /* foreach_child */
1388 if (!is_boundary(cell) && s[] != nodata)
1389 sum += s[], n++;
1390 return n ? sum/n : nodata;
1391}
1392
1393for (int _d = 0; _d < dimension; _d++)
1394static double masked_average_x (Point point, scalar s)
1395{
1396 double sum = 0., n = 0.;
1397 for (int _c = 0; _c < 4; _c++) /* foreach_child */
1398 if (child.x < 0 && (!is_boundary(cell) || !is_boundary(neighbor(1))) &&
1399 s[1] != nodata)
1400 sum += s[1], n++;
1401 return n ? sum/n : nodata;
1403
1404static void masked_boundary_restriction (const Boundary * b,
1405 scalar * list, int l)
1406{
1407 scalar * scalars = NULL;
1408 vector * faces = NULL;
1409 for (int _s = 0; _s < 1; _s++) /* scalar in list */
1410 if (!is_constant(s) && s.refine != no_restriction) {
1411 if (s.v.x.i == s.i && s.face)
1412 faces = vectors_add (faces, s.v);
1413 else
1415 }
1416
1417 foreach_halo (restriction, l) /* foreach_block */ { // fixme: should use /* foreach_blockf */
1418 for (int _s = 0; _s < 1; _s++) /* scalar in scalars */
1419 s[] = masked_average (parent, s);
1420 for (int _v = 0; _v < 1; _v++) /* vector in faces */
1421 for (int _d = 0; _d < dimension; _d++) {
1422 double average = masked_average_x (parent, v.x);
1423 if (is_boundary(neighbor(-1)))
1424 v.x[] = average;
1425 if (is_boundary(neighbor(1)))
1426 v.x[1] = average;
1427 }
1428 }
1429
1430 free (scalars);
1431 free (faces);
1433
1434macro mask (double func) {
1436 if (is_leaf(cell)) {
1437 int bid = (func);
1438 if (bid >= 0)
1439 cell.pid = - bid - 1;
1440 }
1441 else { /* not a leaf */
1442 int pid = -1;
1443 for (int _c = 0; _c < 4; _c++) /* foreach_child */
1444 if (cell.pid >= 0 || pid < 0)
1445 pid = cell.pid;
1446 cell.pid = pid;
1447 if (pid < 0) {
1448 /* fixme: call coarsen_cell()? */
1449 cell.flags |= leaf;
1451 }
1452 }
1453 }
1454 tree->dirty = true;
1456
1457static void free_cache (CacheLevel * c)
1458{
1459 for (int l = 0; l <= depth(); l++)
1460 free (c[l].p);
1461 free (c);
1463
1464void free_grid (void)
1465{
1466 if (!grid)
1467 return;
1469 Tree * q = tree;
1470 free (q->leaves.p);
1471 free (q->faces.p);
1472 free (q->vertices.p);
1473 free (q->refined.p);
1474 /* low-level memory management */
1475 /* the root level is allocated differently */
1476 Layer * L = q->L[0];
1477 foreach_mem (L->m, L->len, 1) {
1478#if dimension == 1
1479 free (mem_data (L->m, point.i));
1480#elif dimension == 2
1481 free (mem_data (L->m, point.i, point.j));
1482#else // dimension == 3
1483 free (mem_data (L->m, point.i, point.j, point.k));
1484#endif // dimension == 3
1485 }
1486 for (int l = 0; l <= depth(); l++)
1487 destroy_layer (q->L[l]);
1488 q->L = &(q->L[-1]);
1489 free (q->L);
1490 free_cache (q->active);
1491 free_cache (q->prolongation);
1492 free_cache (q->boundary);
1493 free_cache (q->restriction);
1494 free (q);
1495 grid = NULL;
1497
1498static void refine_level (int depth);
1500trace
1501void init_grid (int n)
1502{
1503 // check 64 bits structure alignment
1504 assert (sizeof(Cell) % 8 == 0);
1505
1506 free_grid();
1507 int depth = 0;
1508 while (n > 1) {
1509 if (n % 2) {
1510 fprintf (stderr, "tree: N must be a power-of-two\n");
1511 exit (1);
1512 }
1513 n /= 2;
1514 depth++;
1515 }
1516 Tree * q = qcalloc (1, Tree);
1517 grid = (Grid *) q;
1518 grid->depth = 0;
1519
1520 /* low-level memory management */
1521 q->L = qmalloc (2, Layer *);
1522 /* make sure we don't try to access level -1 */
1523 q->L[0] = NULL; q->L = &(q->L[1]);
1524 /* initialise the root cell */
1525 Layer * L = new_layer (0);
1526 q->L[0] = L;
1527#if dimension == 1
1528 for (int i = Period.x*GHOSTS; i < L->len - Period.x*GHOSTS; i++)
1529 assign_periodic (L->m, i, L->len,
1530 (char *) calloc (1, sizeof(Cell) + datasize));
1531 CELL(mem_data (L->m,GHOSTS)).flags |= leaf;
1532 if (pid() == 0)
1533 CELL(mem_data (L->m,GHOSTS)).flags |= active;
1534 for (int k = -GHOSTS*(1 - Period.x); k <= GHOSTS*(1 - Period.x); k++)
1535 CELL(mem_data (L->m,GHOSTS+k)).pid = (k < 0 ? -1 - left :
1536 k > 0 ? -1 - right :
1537 0);
1538 CELL(mem_data (L->m,GHOSTS)).pid = 0;
1539#elif dimension == 2
1540 for (int i = Period.x*GHOSTS; i < L->len - Period.x*GHOSTS; i++)
1541 for (int j = Period.y*GHOSTS; j < L->len - Period.y*GHOSTS; j++)
1542 assign_periodic (L->m, i, j, L->len,
1543 (char *) calloc (1, sizeof(Cell) + datasize));
1544 CELL(mem_data (L->m,GHOSTS,GHOSTS)).flags |= leaf;
1545 if (pid() == 0)
1546 CELL(mem_data (L->m,GHOSTS,GHOSTS)).flags |= active;
1547 for (int k = - GHOSTS*(1 - Period.x); k <= GHOSTS*(1 - Period.x); k++)
1548 for (int l = -GHOSTS*(1 - Period.y); l <= GHOSTS*(1 - Period.y); l++)
1549 CELL(mem_data (L->m,GHOSTS+k,GHOSTS+l)).pid =
1550 (k < 0 ? -1 - left :
1551 k > 0 ? -1 - right :
1552 l > 0 ? -1 - top :
1553 l < 0 ? -1 - bottom :
1554 0);
1555 CELL(mem_data (L->m,GHOSTS,GHOSTS)).pid = 0;
1556#else // dimension == 3
1557 for (int i = Period.x*GHOSTS; i < L->len - Period.x*GHOSTS; i++)
1558 for (int j = Period.y*GHOSTS; j < L->len - Period.y*GHOSTS; j++)
1559 for (int k = Period.z*GHOSTS; k < L->len - Period.z*GHOSTS; k++)
1560 assign_periodic (L->m, i, j, k, L->len,
1561 (char *) calloc (1, sizeof(Cell) + datasize));
1562 CELL(mem_data (L->m,GHOSTS,GHOSTS,GHOSTS)).flags |= leaf;
1563 if (pid() == 0)
1564 CELL(mem_data (L->m,GHOSTS,GHOSTS,GHOSTS)).flags |= active;
1565 for (int k = - GHOSTS*(1 - Period.x); k <= GHOSTS*(1 - Period.x); k++)
1566 for (int l = -GHOSTS*(1 - Period.y); l <= GHOSTS*(1 - Period.y); l++)
1567 for (int n = -GHOSTS*(1 - Period.z); n <= GHOSTS*(1 - Period.z); n++)
1568 CELL(mem_data (L->m,GHOSTS+k,GHOSTS+l,GHOSTS+n)).pid =
1569 (k > 0 ? -1 - right :
1570 k < 0 ? -1 - left :
1571 l > 0 ? -1 - top :
1572 l < 0 ? -1 - bottom :
1573 n > 0 ? -1 - front :
1574 n < 0 ? -1 - back :
1575 0);
1576 CELL(mem_data (L->m,GHOSTS,GHOSTS,GHOSTS)).pid = 0;
1577#endif // dimension == 3
1578 q->active = qcalloc (1, CacheLevel);
1579 q->prolongation = qcalloc (1, CacheLevel);
1580 q->boundary = qcalloc (1, CacheLevel);
1581 q->restriction = qcalloc (1, CacheLevel);
1582 q->dirty = true;
1583 N = 1 << depth;
1584@if _MPI
1585 void mpi_boundary_new();
1587@endif
1588 // boundaries
1589 Boundary * b = qcalloc (1, Boundary);
1590 b->level = box_boundary_level;
1591 b->restriction = masked_boundary_restriction;
1592 add_boundary (b);
1594 reset (all, 0.);
1595 update_cache();
1596}
1598#if dimension == 2
1599void check_two_one (void)
1600{
1601 for (int _i = 0; _i < _N; _i++) /* foreach_leaf */
1602 if (level > 0)
1603 for (int k = -1; k <= 1; k++)
1604 for (int l = -1; l <= 1; l++) {
1605 /* fixme: all this mess is just to ignore ghost cells */
1606 int i = (point.i + GHOSTS)/2 + k;
1607 int j = (point.j + GHOSTS)/2 + l;
1608 double Delta = 1./(1 << point.level);
1609 double x = ((i - GHOSTS + 0.5)*Delta*2. - 0.5);
1610 double y = ((j - GHOSTS + 0.5)*Delta*2. - 0.5);
1611 if (x > -0.5 && x < 0.5 && y > -0.5 && y < 0.5 &&
1612 !(aparent(k,l).flags & active)) {
1613 FILE * fp = fopen("check_two_one_loc", "w");
1614 fprintf (fp,
1615 "# %d %d\n"
1616 "%g %g\n%g %g\n",
1617 k, l,
1618 ((point.i - GHOSTS + 0.5)* - 0.5),
1619 ((point.j - GHOSTS + 0.5)*Delta - 0.5),
1620 x, y);
1621 fclose (fp);
1622#if 0
1623 fp = fopen("check_two_one", "w");
1624 output_cells (fp);
1625 fclose (fp);
1626#endif
1627 assert (false);
1628 }
1629 }
1630}
1631#endif
1632
1633Point locate (double xp = 0., double yp = 0., double zp = 0.)
1634{
1635 for (int l = depth(); l >= 0; l--) {
1636 Point point = {0};
1637 point.level = l;
1638 int n = 1 << point.level;
1639 point.i = (xp - X0)/L0*n + GHOSTS;
1640#if dimension >= 2
1641 point.j = (yp - Y0)/L0*n + GHOSTS;
1642#endif
1643#if dimension >= 3
1644 point.k = (zp - Z0)/L0*n + GHOSTS;
1645#endif
1646 if (point.i >= 0 && point.i < n + 2*GHOSTS
1647#if dimension >= 2
1648 && point.j >= 0 && point.j < n + 2*GHOSTS
1649#endif
1650#if dimension >= 3
1651 && point.k >= 0 && point.k < n + 2*GHOSTS
1652#endif
1653 ) {
1654 if (allocated(0) && is_local(cell) && is_leaf(cell))
1655 return point;
1656 }
1657 else
1658 break;
1659 }
1660 Point point = {0};
1661 point.level = -1;
1662 return point;
1663}
1664
1665// return true if the tree is "full" i.e. all the leaves are at the
1666// same level
1667bool tree_is_full()
1668{
1669 update_cache();
1670 return (grid->tn == 1L << grid->maxdepth*dimension);
1671}
1672
1673#include "variables.h"
1674
1675macro2 for (int _b = 0; _b < 1; _b++) /* boundary int _b, Reduce reductions = None */ {
1676 for (int _l = depth(); _l >= 0; _l--)
1679 if (bid(cell) == _b)
1680 for (int _d = 0; _d < dimension; _d++) {
1681 for (int _i = -1; _i <= 1; _i += 2) {
1682 if (_d == 0) ig = _i; else if (_d == 1) jg = _i; else kg = _i;
1683 if (allocated(-ig,-jg,-kg) &&
1684 is_leaf (neighbor(-ig,-jg,-kg)) &&
1685 !is_boundary(neighbor(-ig,-jg,-kg)) &&
1686 is_local(neighbor(-ig,-jg,-kg))) {
1687 point.i -= ig; x -= ig*Delta/2.;
1688#if dimension >= 2
1689 point.j -= jg; y -= jg*Delta/2.;
1690#endif
1691#if dimension >= 3
1692 point.k -= kg; z -= kg*Delta/2.;
1693#endif
1694 {...}
1695 point.i += ig; x += ig*Delta/2.;
1696#if dimension >= 2
1697 point.j += jg; y += jg*Delta/2.;
1698#endif
1699#if dimension >= 3
1700 point.k += kg; z += kg*Delta/2.;
1701#endif
1702 }
1703 }
1704 ig = jg = kg = 0;
1705 }
1706 }
1707}
1708
1709macro2 for (int _i = 0; _i < _N; _i++) /* foreach_vertex */
1710{
1711 update_cache();
1712 for (int _i = 0; _i < 1; _i++) /* cache tree->vertices, reductions */ {
1713 int ig = -1; NOT_UNUSED (ig);
1714#if dimension >= 2
1715 int jg = -1; NOT_UNUSED (jg);
1716#endif
1717#if dimension >= 3
1718 int kg = -1; NOT_UNUSED (kg);
1719#endif
1720 {...}
1721 }
1722}
1723
1724#include "tree-common.h"
1726// overload the default periodic() function
1727void tree_periodic (int dir)
1728{
1729 int depth = grid ? depth() : -1;
1730 if (grid)
1731 free_grid();
1732 periodic (dir);
1733 if (depth >= 0)
1735}
1736#define periodic(dir) tree_periodic(dir)
1737
1738@if _MPI
1739#include "tree-mpi.h"
1740#include "balance.h"
1741@else // !_MPI
1743void mpi_boundary_coarsen (int a, int b){}
1745 for (int _s = 0; _s < 1; _s++) /* scalar in list */
1747 boundary (list);
1748}
1749@endif // !_MPI
vector q[]
The primitive variables are the momentum , pressure , density , (face) specific volume ,...
Definition all-mach.h:44
const vector a
Definition all-mach.h:59
if TRASH define &&NewPid *& val(newpid, 0, 0, 0)) -> pid > 0) @else @ define is_newpid()(((NewPid *)&val(newpid, 0, 0, 0)) ->pid > 0) @endif Array *linear_tree(size_t size, scalar newpid)
Definition balance.h:13
#define dimension
Definition bitree.h:3
void add_boundary(Boundary *b)
Definition boundaries.h:16
void free_boundaries()
Definition boundaries.h:27
int bid
define double double char flags
define double double char Reduce reductions
void output_cells(FILE *fp=stdout, coord c={0}, double size=0.)
define m((k)==0 &&(l)==0 &&(m)==0) macro2 foreach_point(double _x=0.
macro1 is_face_x()
Definition cartesian1D.h:61
define neighbor(o, p, q)((Point)
Definition cartesian.h:146
free(list1)
define VT _attribute[s.i] v y scalar * list
Definition cartesian.h:276
OMP_PARALLEL()
Definition cartesian.h:292
int y
Definition common.h:76
#define define
int x
Definition common.h:76
int z
Definition common.h:76
scalar * all
Definition common.h:342
vector * vectors_add(vector *list, vector v)
Definition common.h:267
double Z0
Definition common.h:34
#define nodata
Definition common.h:7
static _Attributes * _attribute
Definition common.h:165
scalar * list_add(scalar *list, scalar s)
Definition common.h:208
double L0
Definition common.h:36
int N
Definition common.h:39
struct @0 Period
static number sq(number x)
Definition common.h:11
Grid * grid
Definition common.h:32
double X0
Definition common.h:34
double Y0
Definition common.h:34
@ top
Definition common.h:123
@ bottom
Definition common.h:123
@ left
Definition common.h:123
@ right
Definition common.h:123
static number cube(number x)
Definition common.h:12
size_t datasize
Definition common.h:132
scalar f[]
The primary fields are:
Definition two-phase.h:56
vector * vectors
scalar * scalars
else define undefined((double) DBL_MAX) @ define enable_fpe(flags) @ define disable_fpe(flags) static void set_fpe(void)
Definition config.h:615
if __APPLE__ include< stdint.h > include fp_osx h endif if _GPU define enable_fpe(flags) @else @ define enable_fpe(flags) feenableexcept(flags) @endif @ define disable_fpe(flags) fedisableexcept(flags) static void set_fpe(void)
Definition config.h:603
#define qcalloc(size, type)
define _index(a, m)(a.i) @define val(a
#define qmalloc(size, type)
define sysmalloc malloc define syscalloc calloc define sysrealloc realloc define sysfree free define systrdup strdup define line calloc(n, s) @ define prealloc(p
define sysmalloc malloc define syscalloc calloc define sysrealloc realloc define sysfree free define systrdup strdup define func
Definition config.h:120
#define assert(a)
Definition config.h:107
define sysmalloc malloc define syscalloc calloc define sysrealloc realloc define sysfree free define systrdup strdup define line line realloc(p, s) @ define pfree(p
Point point
Definition conserving.h:86
coord o
Definition curvature.h:672
else
Definition embed-tree.h:79
else fine(fs.x, 1, 0)
*cs[i, 0, 0] a *[i -1, 0, 0] j
Definition embed.h:88
double v[2]
Definition embed.h:383
scalar int i
Definition embed.h:74
#define BGHOSTS
Definition embed.h:15
macro2 foreach_cell_all()
macro2 foreach_cell_post(bool condition)
define neighborp(k, l, o) neighbor(k
#define depth()
Definition cartesian.h:14
#define realloc_scalar(size)
Definition gpu.h:480
#define reset(...)
Definition grid.h:1388
#define init_grid(n)
Definition grid.h:1402
static int
Definition include.c:978
double * sum
int nl
Definition layers.h:9
macro
We also redefine the "per field" (inner) traversal.
Definition layers.h:18
#define data(k, l)
Definition linear.h:26
void mempool_free(Mempool *m, void *p)
Definition mempool.h:94
void mempool_destroy(Mempool *m)
Definition mempool.h:39
void * mempool_alloc0(Mempool *m)
Definition mempool.h:87
void * mempool_alloc(Mempool *m)
Definition mempool.h:50
Mempool * mempool_new(size_t poolsize, size_t size)
Definition mempool.h:25
FILE * fp
Definition mtrace.h:7
void(* restriction)(Point, scalar)
static void no_restriction(Point point, scalar s)
size_t size
size *double * b
int int int level
#define CELL(m, level, i)
Definition multigrid.h:70
char dir[]
Definition qcc.c:64
struct _Memindex * mem_new(int len)
The mem_new() function returns a new (empty) Memindex.
Definition range.h:173
macro foreach_mem(struct _Memindex *index, int len, int _i)
The foreach_mem() macro traverses every _i allocated elements of array _m taking into account a perio...
Definition range.h:309
void mem_free(struct _Memindex *m, int i, int j, int len, void *b)
The mem_free() function frees a given index.
Definition range.h:261
#define Memindex
Definition range.h:140
void mem_assign(struct _Memindex *m, int i, int j, int len, void *b)
The mem_assign() function assigns a (pointer) value to a given index.
Definition range.h:220
#define mem_data(m, i, j)
Definition range.h:158
void mem_destroy(struct _Memindex *m, int len)
The mem_destroy() function frees all the memory allocated by a given Memindex.
Definition range.h:183
#define mem_allocated(m, i, j)
The mem_data() macros return the data stored at a specific (multidimensional) index.
Definition range.h:153
def _i
Definition stencils.h:405
static void set_dirty_stencil(scalar s)
Definition stencils.h:34
def _k
Definition stencils.h:405
def _j
Definition stencils.h:405
int n
Definition tree.h:95
IndexLevel * p
Definition tree.h:94
Definition tree.h:109
Index * p
Definition tree.h:110
int n
Definition tree.h:111
Definition tree.h:51
int pid
Definition tree.h:55
unsigned short flags
Definition tree.h:52
unsigned short neighbors
Definition tree.h:54
Definition common.h:26
long n
Definition common.h:27
long tn
Definition common.h:28
int depth
Definition common.h:29
int maxdepth
Definition common.h:30
Definition tree.h:98
int i
Definition tree.h:99
int j
Definition tree.h:101
int flags
Definition tree.h:106
Definition tree.h:116
int len
Definition tree.h:120
struct _Memindex * m
Definition tree.h:117
Mempool * pool
Definition tree.h:118
long nc
Definition tree.h:119
Definition linear.h:21
int level
Definition linear.h:23
int i
Definition linear.h:23
Definition tree.h:167
Layer ** L
Definition tree.h:169
bool dirty
Definition tree.h:181
CacheLevel * active
Definition tree.h:175
CacheLevel * restriction
Definition tree.h:179
CacheLevel * prolongation
Definition tree.h:176
Cache leaves
Definition tree.h:171
Cache faces
Definition tree.h:172
CacheLevel * boundary
Definition tree.h:177
Cache refined
Definition tree.h:174
Grid g
Definition tree.h:168
Cache vertices
Definition tree.h:173
vector v
Definition common.h:158
int j
Definition cartesian.h:26
int level
Definition cartesian.h:26
int x
Definition multigrid.h:52
int i
Definition cartesian.h:26
int i
Definition common.h:44
scalar x
Definition common.h:47
scalar y
Definition common.h:49
void mpi_boundary_new()
Definition tree-mpi.h:508
static bool diagonal_neighbor_3D(Point point, scalar *scalars, vector *vectors)
Definition tree.h:1223
_i< 1;_i++) { OMP_PARALLEL(reductions) { int ig=0, jg=0, kg=0;NOT_UNUSED(ig);NOT_UNUSED(jg);NOT_UNUSED(kg);Point point={0};NOT_UNUSED(point);point.i=2 ;point.j=2 ;int _k;unsigned short _flags;NOT_UNUSED(_flags);for(_k=0;_k< cache.n;_k++) { point.i=cache.p[_k].i;point.j=cache.p[_k].j;point.level=cache.p[_k].level;_flags=cache.p[_k].flags;{...} } }}macro2 foreach_cache_level(Cache cache, int _l, Reduce reductions=None){ OMP_PARALLEL(reductions) { int ig=0, jg=0, kg=0;NOT_UNUSED(ig);NOT_UNUSED(jg);NOT_UNUSED(kg);Point point={0};NOT_UNUSED(point);point.i=2 ;point.j=2 ;point.level=_l;int _k;for(_k=0;_k< cache.n;_k++) { point.i=cache.p[_k].i;point.j=cache.p[_k].j;{...} } }}static void update_cache_f(void);macro2 foreach_boundary_level(int _l, Reduce reductions=None){ if(_l<=depth()) { { if(((Tree *) grid) ->dirty) update_cache_f();};CacheLevel _boundary=((Tree *) grid) -> boundary[_l]
Definition tree.h:486
def is_refined_check()((!is_leaf(cell) &&cell .neighbors &&cell .pid >=0) &&point.i > 0 &&point.i<(1<< level)+2 *2 - 1 &&point.j > 0 &&point.j<(1<< level)+2 *2 - 1) @ macro2 for(int _i=0
define n k
Definition tree.h:319
static void update_depth(int inc)
Definition tree.h:785
static bool is_boundary_point(Point point)
Definition tree.h:1292
double real
Definition tree.h:3
define n sizeof(Cell))) @define fine(a
define n n define coarse(a, k, p, n)((double *)(PARENT(k
define n p
Definition tree.h:319
return n sum n
Definition tree.h:1399
static void update_cache_f(void)
Definition tree.h:554
static void cache_level_append(CacheLevel *c, Point p)
Definition tree.h:190
void cache_shrink(Cache *c)
Definition tree.h:233
if TRASH undef trash define trash(list) reset(list
macro2 foreach_face_generic(char flags=0, Reduce reductions=None, const char *order="xyz")
Definition tree.h:691
#define periodic(dir)
Definition tree.h:1734
void check_two_one(void)
Definition tree.h:1597
void mpi_boundary_coarsen(int a, int b)
Definition tree.h:1741
def allocated(k, l, n)(mem_allocated(((Tree *) grid) -> L[point.level]->m, point.i+k, point.j+l)) @ @def NEIGHBOR(k, l, n)(((((Tree *) grid) ->L[point.level]->m) ->b[point.i+k][point.j+l])) @ @def PARENT(k, l, n)(((((Tree *) grid) ->L[point.level-1]->m) ->b[(point.i+2)/2+k][(point.j+2)/2+l])) @ @def allocated_child(k, l, n)(level< depth() &&mem_allocated(((Tree *) grid) ->L[point.level+1]->m, 2 *point.i- 2+k, 2 *point.j- 2+l)) @ @def CHILD(k, l, n)(((((Tree *) grid) ->L[point.level+1]->m) ->b[2 *point.i- 2+k][2 *point.j- 2+l])) @ @define CELL(m)(*((Cell *)(m))) @define depth()(grid->depth) @define aparent(k, l, n) CELL(PARENT(k, l, n)) @define child(k, l, n) CELL(CHILD(k, l, n)) @define cell CELL(NEIGHBOR(0, 0, 0)) @define neighbor(k, l, n) CELL(NEIGHBOR(k, l, n)) @def neighborp(l, m, n)(Point)
Definition tree.h:253
#define BSIZE
Definition tree.h:188
Point locate(double xp=0., double yp=0., double zp=0.)
Definition tree.h:1631
static size_t _size(size_t depth)
Definition tree.h:123
static Point last_point
Definition tree.h:186
static bool diagonal_neighbor_2D(Point point, scalar *scalars, vector *vectors)
Definition tree.h:1180
define n n define n n macro POINT_VARIABLES(Point point=point)
Definition tree.h:322
#define is_prolongation(cell)
Definition tree.h:411
static void periodic_function(struct _Memindex *m, int i, int j, int len, void *b, PeriodicFunction f)
Definition tree.h:827
static void free_cache(CacheLevel *c)
Definition tree.h:1455
static Layer * new_layer(int depth)
Definition tree.h:140
if else void mpi_boundary_refine(scalar *list)
Definition tree.h:1740
#define foreach_halo(type, l)
Definition tree.h:514
#define GHOSTS
Definition tree.h:8
bool * zn
Definition tree.h:1273
static void box_boundary_level(const Boundary *b, scalar *list, int l)
Definition tree.h:1296
macro2 foreach_halo_restriction(int _l)
Definition tree.h:504
undef VN undef VT define VN _attribute[s.i] v x define VT _attribute[s.i] v static y double masked_average(Point point, scalar s)
Definition tree.h:1382
static void free_periodic(struct _Memindex *m, int i, int j, int len)
Definition tree.h:858
#define update_cache()
Definition tree.h:408
void decrement_neighbors(Point point)
Definition tree.h:1054
void tree_periodic(int dir)
Definition tree.h:1725
static void assign_periodic(struct _Memindex *m, int i, int j, int len, void *b)
Definition tree.h:853
static void cache_append(Cache *c, Point p, unsigned short flags)
Definition tree.h:215
static void refine_level(int depth)
#define is_refined(cell)
Definition tree.h:410
macro2 for(int _l=0;_l< int l, char flags=0, Reduce reductions=None;_l++)
Definition tree.h:732
macro1 is_face_y(unsigned short _f=_flags)
Definition tree.h:707
#define tree
Definition tree.h:184
macro2 foreach_halo_prolongation(int _l)
Definition tree.h:494
if define disable_fpe_for_mpi() disable_fpe(FE_DIVBYZERO|FE_INVALID) @ define enable_fpe_for_mpi() enable_fpe(FE_DIVBYZERO|FE_INVALID) @else @ define disable_fpe_for_mpi() @ define enable_fpe_for_mpi() @endif static inline void no_restriction(Point point
macro1 foreach_child(Point point=point, break=(_k=_l=2))
Definition tree.h:370
static void free_children(Point point)
Definition tree.h:1002
static void cache_level_shrink(CacheLevel *c)
Definition tree.h:206
if define scalar s
Definition tree.h:1148
static size_t poolsize(size_t depth, size_t size)
Definition tree.h:128
void(* PeriodicFunction)(struct _Memindex *, int, int, int, void *)
Definition tree.h:825
static void masked_boundary_restriction(const Boundary *b, scalar *list, int l)
Definition tree.h:1402
define is_active() cell((cell).flags &active) @define is_leaf(cell)((cell).flags &leaf) @define is_coarse()((cell).neighbors > 0) @define is_border(cell)((cell).flags &border) @define is_local(cell)((cell).pid
@ user
Definition tree.h:63
@ face_y
Definition tree.h:67
@ active
Definition tree.h:59
@ vertex
Definition tree.h:62
@ leaf
Definition tree.h:60
@ border
Definition tree.h:61
@ face_x
Definition tree.h:65
#define is_neighbor(...)
Definition tree.h:1137
static void destroy_layer(Layer *l)
Definition tree.h:157
foreach_cache_level(_boundary, _l, reductions)
Definition tree.h:487
define l
Definition tree.h:318
bool tree_is_full()
Definition tree.h:1665
void increment_neighbors(Point point)
Definition tree.h:1043
macro mask(double func)
Definition tree.h:1432
#define bid(cell)
Definition tree.h:492
void mpi_boundary_update(scalar *list)
Definition tree.h:1742
static void alloc_children(Point point)
Definition tree.h:940
static void cache_append_face(Point point, unsigned short flags)
Definition tree.h:526
static bool has_local_children(Point point)
Definition tree.h:518
void free_grid(void)
Definition tree.h:1462
static CacheLevel * cache_level_resize(CacheLevel *name, int a)
Definition tree.h:777
#define is_boundary(cell)
Definition tree.h:412
static bool normal_neighbor(Point point, scalar *scalars, vector *vectors)
Definition tree.h:1150
macro VARIABLES(Point point=point, int _ig=ig, int _jg=jg, int _kg=kg)
Definition variables.h:3
scalar c
Definition vof.h:57