Basilisk CFD
Adaptive Cartesian mesh PDE framework
Loading...
Searching...
No Matches
stencils.h
Go to the documentation of this file.
1/** @file stencils.h
2 */
3/**
4# Automatic stencils and boundary conditions
5
6Basilisk automatically computes, at runtime, the access pattern
7(i.e. "stencils") of (basic) foreach loops (for (int _i = 0; _i < _N; _i++) /* foreach */, for (int _i = 0; _i < _N; _i++) /* foreach_face */,
8for (int _i = 0; _i < _N; _i++) /* foreach_vertex */).
9
11each foreach loop, a minimal version of the loop body.
12
15
16The `width` is the width of the access stencil. */
17
18enum {
19 s_centered = 1 << 0, // centered boundary conditions are up-to-date
20 s_face = 1 << 1, // face boundary conditions are up-to-date
21 s_restriction = 1 << 2, // restriction is up-to-date
22
23 s_input = 1 << 3, // field is used as input
24 s_output = 1 << 4, // field is used as output
25 s_nowarning = 1 << 5 // warning are switched off
27
29 struct {
30 int bc, io, width;
31 } stencil;
32}
33
35{
36 s.stencil.bc = 0;
37}
38
39typedef struct _External External;
40
41struct _External {
42 char * name; // the name of the variable
43 void * pointer; // a pointer to the data
44 int type; // the type of the variable
45 int nd; // the number of pointer dereferences or attribute offset or enum constant
46 char reduct; // the reduction operation
47 char global; // is it a global variable?
48 char constant; // is it a constant?
49 void * data; // the dimensions (int *) for arrays or the code (char *) for functions
50 scalar s; // used for reductions on GPUs
52 int used;
53};
54
55typedef struct {
56 const char * fname; // name of the source file
57 int line; // line number in the source
58 int first; // is this the first time the loop is called?
59 int face; // the face component(s) being traversed
60 bool vertex; // is this a vertex traversal?
61 int parallel; // is this a parallel loop? (0: no, 1: on CPU or GPU, 2: on CPU, 3: on GPU)
62 scalar * listc; // the scalar fields on which to apply boundary conditions
63 vectorl listf; // the vector fields on which to apply (flux) boundary conditions
64 scalar * dirty; // the dirty fields (i.e. write-accessed)
65 void * data; // user data
67
68/**
69## Automatic boundary conditions
70
71Boundary conditions need to be applied if `s` is dirty, or if any of
72the field `d` it depends on is dirty. */
73
74static inline bool scalar_is_dirty (scalar s)
75{
76 if (!(s.stencil.bc & s_centered))
77 return true;
78 scalar * depends = s.depends;
79 for (int _d = 0; _d < 1; _d++) /* scalar in depends */
80 if (!(d.stencil.bc & s_centered))
81 return true;
82 return false;
83}
84
85/**
86Does the boundary conditions on `a` depend on those on `b`? */
87
88static inline bool scalar_depends_from (scalar a, scalar b)
89{
90 scalar * depends = a.depends;
91 for (int _s = 0; _s < 1; _s++) /* scalar in depends */
92 if (s.i == b.i)
93 return true;
94 return false;
95}
96
97/**
98There are two types of boundary conditions: "full" boundary
99conditions, done by `boundary_internal()` and "flux" boundary
100conditions (i.e. normal components on faces only) done by
101`boundary_face()`. */
102
103void boundary_internal (scalar * list, const char * fname, int line);
105
106/**
107This function is called after the stencil access detection, just
108before the (real) foreach loop is executed. This is where we use the
109stencil access pattern to see whether boundary conditions need to be
110applied. */
111
113{
114 loop->listf = (vectorl){NULL};
115
116 /**
117 We check the accesses for each field... */
118
119 for (int _s = 0; _s < 1; _s++) /* scalar in baseblock */ {
120 bool write = (s.stencil.io & s_output), read = (s.stencil.io & s_input);
121
122#ifdef foreach_layer
123 if (_layer == 0 || s.block == 1)
124#endif
125 {
126
127 /**
128 If the field is read and dirty, we need to check if boundary
129 conditions need to be applied. */
130
131 if (read && scalar_is_dirty (s)) {
132
133 /**
134 If this is a face field, we check whether "full" BCs need to
135 be applied, or whether "face" BCs are sufficient. */
136
137 if (s.face) {
138 if (s.stencil.width > 0) // face, stencil wider than 0
139 loop->listc = list_append (loop->listc, s);
140 else if (!write) { // face, flux only
141 scalar sn = s.v.x.i >= 0 ? s.v.x : s;
142 for (int _d = 0; _d < dimension; _d++)
143 if (s.v.x.i == s.i) {
144
145 /* fixme: imposing BCs on fluxes should be done by
146 boundary_face() .*/
147
148 if (sn.boundary[left] || sn.boundary[right])
149 loop->listc = list_append (loop->listc, s);
150 else if (!(s.stencil.bc & s_face))
151 loop->listf.x = list_append (loop->listf.x, s);
152 }
153 }
154 }
155
156 /**
157 For dirty, centered fields BCs need to be applied if the
158 stencil is wider than zero. */
159
160 else if (s.stencil.width > 0)
161 loop->listc = list_append (loop->listc, s);
162 }
163
164 /**
165 Write accesses need to be consistent with the declared field
166 type (i.e. face or vertex). */
167
168 if (write) {
169 if (dimension > 1 && !loop->vertex && loop->first && !(s.stencil.io & s_nowarning)) {
170 bool vertex = true;
171 for (int _d = 0; _d < dimension; _d++)
172 if (s.d.x != -1)
173 vertex = false;
174 if (vertex)
176 "%s:%d: warning: scalar '%s' should be assigned with"
177 " a for (int _i = 0; _i < _N; _i++) /* foreach_vertex */ loop\n",
178 loop->fname, loop->line, s.name);
179 }
180 if (s.face) {
181 if (loop->face == 0 && loop->first && !(s.stencil.io & s_nowarning))
183 "%s:%d: warning: vector '%s' should be assigned with"
184 " a for (int _i = 0; _i < _N; _i++) /* foreach_face */ loop\n",
185 loop->fname, loop->line, s.name);
186 }
187 else if (loop->face) {
188 if (s.v.x.i < 0) { // scalar
189 int d = 1, i = 0;
190 for (int _d = 0; _d < dimension; _d++) {
191 if (loop->face == d) {
192 s.face = 2, s.v.x.i = s.i;
193 s.boundary[left] = s.boundary[right] = NULL;
194#if PRINTBOUNDARY
196 "%s:%d: turned %s into a vector %c-component\n",
197 loop->fname, loop->line, s.name, 'x' + i);
198#endif
199 }
200 d *= 2, i++;
201 }
202 if (!s.face && loop->first && !(s.stencil.io & s_nowarning))
204 "%s:%d: warning: scalar '%s' should be assigned with "
205 "a for (int _i = 0; _i < _N; _i++) /* foreach_face */ loop\n",
206 loop->fname, loop->line, s.name);
207 }
208 else { // vector
209 char * name = NULL;
210 if (s.name) {
211 name = strdup (s.name);
212 char * s = name + strlen(name) - 1;
213 while (s != name && *s != '.') s--;
214 if (s != name) *s = '\0';
215 }
216 struct { bool x, y, z; } input, output;
217 vector v = s.v;
218#if 1 // fixme: should not be necessary
219 for (int _d = 0; _d < dimension; _d++)
220 input.x = (v.x.stencil.io & s_input), output.x = (v.x.stencil.io & s_output);
221#endif
222 init_face_vector (v, name);
223#if 1 // fixme: should not be necessary
224 for (int _d = 0; _d < dimension; _d++) {
225 if (input.x) v.x.stencil.io |= s_input;
226 else v.x.stencil.io &= ~s_input;
227 if (output.x) v.x.stencil.io |= s_output;
228 else v.x.stencil.io &= ~s_output;
229 }
230#endif
231#if PRINTBOUNDARY
232 fprintf (stderr, "%s:%d: turned %s into a vector\n",
233 loop->fname, loop->line, name);
234#endif
235 free (name);
236 }
237 }
238 else if (loop->vertex) {
239 bool vertex = true;
240 for (int _d = 0; _d < dimension; _d++)
241 if (s.d.x != -1)
242 vertex = false;
243 if (!vertex) {
244 char * name = NULL;
245 if (s.name) name = strdup (s.name); // fixme: may not be necessary
246 init_vertex_scalar (s, name);
247 for (int _d = 0; _d < dimension; _d++)
248 s.v.x.i = -1;
249#if PRINTBOUNDARY
250 fprintf (stderr, "%s:%d: turned %s into a scalar\n",
251 loop->fname, loop->line, name);
252#endif
253 free (name);
254 }
255 }
256
257 /**
258 If the field is write-accessed, we add it to the 'dirty'
259 list. */
260
261 if (!list_lookup (loop->dirty, s))
262 loop->dirty = list_append (loop->dirty, s);
263 for (int _d = 0; _d < 1; _d++) /* scalar in baseblock */
264 if (scalar_depends_from (d, s) && !list_lookup (loop->dirty, d))
265 loop->dirty = list_append (loop->dirty, d);
266 }
267 }
268 }
269}
270
271/**
272This functions applies the boundary conditions, as defined by `check_stencil()`. */
273
275{
276 bool flux = false;
277 for (int _d = 0; _d < dimension; _d++)
278 if (loop->listf.x)
279 flux = true;
280 if (flux) {
281#if PRINTBOUNDARY
282 int i = 0;
283 for (int _d = 0; _d < dimension; _d++) {
284 if (loop->listf.x) {
285 fprintf (stderr, "%s:%d: flux %c:", loop->fname, loop->line, 'x' + i);
286 for (int _s = 0; _s < 1; _s++) /* scalar in loop->listf.x */
287 fprintf (stderr, " %d:%s", s.i, s.name);
288 fputc ('\n', stderr);
289 }
290 i++;
291 }
292#endif
293 boundary_face (loop->listf);
294 for (int _d = 0; _d < dimension; _d++)
295 free (loop->listf.x), loop->listf.x = NULL;
296 }
297
298 /**
299 We apply "full" boundary conditions. */
300
301 if (loop->listc) {
302#if PRINTBOUNDARY
303 fprintf (stderr, "%s:%d: listc:", loop->fname, loop->line);
304 for (int _s = 0; _s < 1; _s++) /* scalar in loop->listc */
305 fprintf (stderr, " %d:%s", s.i, s.name);
306 fputc ('\n', stderr);
307#endif
308 boundary_internal (loop->listc, loop->fname, loop->line);
309 free (loop->listc), loop->listc = NULL;
310 }
311
312 /**
313 We update the dirty status of fields which will be write-accessed by
314 the foreach loop. */
315
316 if (loop->dirty) {
317#if PRINTBOUNDARY
318 fprintf (stderr, "%s:%d: dirty:", loop->fname, loop->line);
319 for (int _s = 0; _s < 1; _s++) /* scalar in loop->dirty */
320 fprintf (stderr, " %d:%s", s.i, s.name);
321 fputc ('\n', stderr);
322#endif
323 for (int _s = 0; _s < 1; _s++) /* scalar in loop->dirty */
325 free (loop->dirty), loop->dirty = NULL;
326 }
327}
328
330{
331 {
332 static int _first = 1.;
334 .fname = S__FILE__, .line = S_LINENO, .first = _first
335 };
336 if (baseblock)
337 for (scalar s = baseblock[0], * i = baseblock; s.i >= 0; i++, s = *i) {
338 _attribute[s.i].stencil.io = 0;
339 _attribute[s.i].stencil.width = 0;
340 }
341 int ig = 0, jg = 0, kg = 0; NOT_UNUSED(ig); NOT_UNUSED(jg); NOT_UNUSED(kg);
342 Point point = {0}; NOT_UNUSED (point);
343
344 {...}
345
348 _first = 0;
349 }
350}
351
354 _loop.vertex = true;
355 {...}
356 }
357}
358
363
365 if (0) {
366 // automatic boundary conditions are not implemented yet so we don't do anything for the moment
367 int ig = 0, jg = 0, kg = 0; NOT_UNUSED(ig); NOT_UNUSED(jg); NOT_UNUSED(kg);
368 Point point = {0}; NOT_UNUSED (point);
369 {...}
370 }
371}
372
377
382
383macro2 foreach_point_stencil (double xp, double yp, double zp, char flags, Reduce reductions)
384{
386 {...}
387}
388
394
395macro2 _stencil_is_face_x (ForeachData l = _loop) { l.face |= (1 << 0); {...} }
396macro2 _stencil_is_face_y (ForeachData l = _loop) { l.face |= (1 << 1); {...} }
397macro2 _stencil_is_face_z (ForeachData l = _loop) { l.face |= (1 << 2); {...} }
398
399void stencil_val (Point p, scalar s, int i, int j, int k,
400 const char * file, int line, bool overflow);
401void stencil_val_a (Point p, scalar s, int i, int j, int k, bool input,
402 const char * file, int line);
403
406@
409@
412@
415@
416
421
425
428
434
436
438
439int _stencil_nop;
443
445
447
448/**
449## See also
450
451* [Stencil test case](/src/test/stencils.c)
452*/
#define dimension
Definition bitree.h:3
define k
#define boundary(...)
define double double char flags
define l
define double double char Reduce reductions
free(list1)
define VT _attribute[s.i] v y scalar * list
Definition cartesian.h:276
int y
Definition common.h:76
#define define
int x
Definition common.h:76
int z
Definition common.h:76
scalar(* init_vertex_scalar)(scalar, const char *)
Definition common.h:348
static _Attributes * _attribute
Definition common.h:165
int list_lookup(scalar *l, scalar s)
Definition common.h:216
scalar * baseblock
Definition common.h:343
vector(* init_face_vector)(vector, const char *)
Definition common.h:350
scalar * list_append(scalar *list, scalar s)
Definition common.h:188
@ left
Definition common.h:123
@ right
Definition common.h:123
#define p
Definition tree.h:320
define sysmalloc malloc define syscalloc calloc define sysrealloc realloc define sysfree free define systrdup strdup define file
Definition config.h:120
define sysmalloc malloc define syscalloc calloc define sysrealloc realloc define sysfree free define systrdup strdup define line line line line strdup(s) @ define tracing(...) @ define end_tracing(...) @define tid() 0 @define pid() 0 @define npe() 1 @define mpi_all_reduce(v
Point point
Definition conserving.h:86
else return n
Definition curvature.h:101
trace bool box(bool notics=false, float lc[3]={0}, float lw=1.)
Definition draw.h:1397
scalar s
Definition embed-tree.h:56
double v[2]
Definition embed.h:383
double d[2]
Definition embed.h:383
scalar int i
Definition embed.h:74
scalar scalar coord coord double bc
Definition embed.h:378
static int line
Definition errors.c:754
static char * fname
Definition errors.c:753
static int input(void)
Definition include.c:2085
which uses a global _layer index *int _layer
Definition layers.h:15
size *double * b
static bool which(const char *command)
Definition output.h:389
macro2 foreach_point_stencil(double xp, double yp, double zp, char flags, Reduce reductions)
Definition stencils.h:383
before each foreach a minimal version of the loop body The flags indicate the status of boundary conditions and whether the field is used as input or output within a given loop The width is the width of the access stencil *enum @11 StencilFlags
macro2 foreach_region_stencil(coord p, coord box[2], coord n, char flags, Reduce reductions)
Definition stencils.h:389
macro2 _stencil_is_face_z(ForeachData l=_loop)
Definition stencils.h:397
def false def true def S_LINENO def S_LINENO define _k define _k define _k define _k define _k define _k define _k define j
Definition stencils.h:429
def false def true def S_LINENO def S_LINENO define _k define _k define _k define _k define _k define _stencil_coarse_a(a, _i, _j, _k) _stencil_val_a(a
before each foreach loop
Definition stencils.h:11
void boundary_stencil(ForeachData *loop)
This functions applies the boundary conditions, as defined by check_stencil().
Definition stencils.h:274
def _stencil_val(a, _i, _j, _k) stencil_val(point
def S_LINENO
Definition stencils.h:405
def S__FILE__
Definition stencils.h:405
macro2 foreach_level_stencil(int l, char flags, Reduce reductions)
Definition stencils.h:364
def false def true def S_LINENO def S_LINENO define _k define _k define _k define _k define _k define _k define _k define k define k define _stencil_aparent_a(i, j, k) @define _stencil_aparent_r(i
macro2 _stencil_is_face_x(ForeachData l=_loop)
Definition stencils.h:395
void(* boundary_face)(vectorl)
Definition stencils.h:104
macro2 foreach_coarse_level_stencil(int l, char flags, Reduce reductions)
Definition stencils.h:373
macro2 _stencil_is_face_y(ForeachData l=_loop)
Definition stencils.h:396
def _i
Definition stencils.h:405
def false def true def S_LINENO def _stencil_val_r(a, _i, _j, _k) stencil_val_a(point
def false def true def S_LINENO def true
Definition stencils.h:414
macro2 foreach_stencil(char flags, Reduce reductions)
Definition stencils.h:329
def false def true def S_LINENO def S_LINENO define _k define _k define _k define _k define _k define _k define _stencil_coarse_r(a, _i, _j, _k) _stencil_val_r(a
void stencil_val_a(Point p, scalar s, int i, int j, int k, bool input, const char *file, int line)
macro2 foreach_face_stencil(char flags, Reduce reductions, const char *order)
Definition stencils.h:359
static void set_dirty_stencil(scalar s)
Definition stencils.h:34
attribute
Definition stencils.h:28
define _stencil_val_higher_dimension(_stencil_nop=1) @define _stencil__val_constant(a
def false def true def S_LINENO def S_LINENO define _stencil_fine(a, _i, _j, _k) _stencil_val(a
void stencil_val(Point p, scalar s, int i, int j, int k, const char *file, int line, bool overflow)
def false def true def S_LINENO def S_LINENO define _k define _k define _k define _k define _k define _k define _k define k define _stencil_child(i, j, k) @define _stencil_aparent(i
void boundary_internal(scalar *list, const char *fname, int line)
There are two types of boundary conditions: "full" boundary conditions, done by boundary_internal() a...
macro2 foreach_vertex_stencil(char flags, Reduce reductions)
Definition stencils.h:352
def false def true def _stencil_val_a(a, _i, _j, _k) stencil_val_a(point
def a
Definition stencils.h:405
def _k
Definition stencils.h:405
@ s_input
Definition stencils.h:23
@ s_restriction
Definition stencils.h:21
@ s_centered
Definition stencils.h:19
@ s_output
Definition stencils.h:24
@ s_nowarning
Definition stencils.h:25
@ s_face
Definition stencils.h:20
static bool scalar_is_dirty(scalar s)
Definition stencils.h:74
def false def true def S_LINENO def S_LINENO define _k define _k define _k define _k define _k define _k define _k define k define k define k define _stencil_allocated(i, j, k) true @define _stencil_neighborp(i
void check_stencil(ForeachData *loop)
This function is called after the stencil access detection, just before the (real) foreach loop is ex...
Definition stencils.h:112
def _j
Definition stencils.h:405
def false def true def S_LINENO def S_LINENO define _k define _k define _k define _k define _k define _k define _k define r_assign(x) @define _assign(x) @define _stencil_neighbor(i
def false def true def S_LINENO def S_LINENO define _k define _k define _k define _k define _stencil_coarse(a, _i, _j, _k) _stencil_val(a
macro2 foreach_level_or_leaf_stencil(int l, char flags, Reduce reductions)
Definition stencils.h:378
def false def _stencil_val_o(a, _i, _j, _k) stencil_val(point
def false def true def S_LINENO def S_LINENO define _k define _k define _stencil_fine_a(a, _i, _j, _k) _stencil_val_a(a
def false def true def false
Definition stencils.h:411
def false def true def S_LINENO def S_LINENO define _k define _k define _k define _stencil_fine_r(a, _i, _j, _k) _stencil_val_r(a
static bool scalar_depends_from(scalar a, scalar b)
Does the boundary conditions on a depend on those on b?
Definition stencils.h:88
def false def true def S_LINENO def S_LINENO define _k define _k define _k define _k define _k define _k define _k define k define k define k define k neighborp(i, j, k) int _stencil_nop
scalar * listc
Definition stencils.h:62
vectorl listf
Definition stencils.h:63
const char * fname
Definition stencils.h:56
void * data
Definition stencils.h:65
int parallel
Definition stencils.h:61
scalar * dirty
Definition stencils.h:64
bool vertex
Definition stencils.h:60
Definition linear.h:21
void * pointer
Definition stencils.h:43
void * data
Definition stencils.h:49
char global
Definition stencils.h:47
char * name
Definition stencils.h:42
char reduct
Definition stencils.h:46
External * externals
Definition stencils.h:51
scalar s
Definition stencils.h:50
char constant
Definition stencils.h:48
int type
Definition stencils.h:44
External * next
Definition stencils.h:51
int used
Definition stencils.h:52
Definition common.h:78
int i
Definition common.h:44
@ vertex
Definition tree.h:62
scalar flux[]
Definition vof.h:166