Basilisk CFD
Adaptive Cartesian mesh PDE framework
Loading...
Searching...
No Matches
utils.h
Go to the documentation of this file.
1/** @file utils.h
2 */
3/**
4# Various utility functions
5
6## Default parameters and variables
7
8The default maximum timestep and CFL number. */
9
10double DT = HUGE [0,1], CFL = 0.5 [0];
11
12/**
13Performance statistics are stored in this structure. */
14
15struct {
16 // total number of (leaf) cells advanced for this process
17 long nc;
18 // total number of (leaf) cells advanced for all processes
19 long tnc;
20 // real time elapsed since the start, time of the previous step
21 double t, tp;
22 // average computational speed (leaves/sec)
23 double speed;
24 // instantaneous computational speed (leaves/sec)
25 double ispeed;
26 // global timer
28} perf = {0};
29
30/**
31Performance statistics are gathered by this function, which is
32typically called by the run() loop. */
33
35 perf.nc += grid->n;
36 perf.tnc += grid->tn;
37 perf.t = timer_elapsed (perf.gt);
38 perf.speed = perf.tnc/perf.t;
39 perf.ispeed = grid->tn/(perf.t - perf.tp);
40 perf.tp = perf.t;
41}
42
43/**
44## Timing
45
46These functions can be used for profiling. */
47
48typedef struct {
49 double cpu; // CPU time (sec)
50 double real; // Wall-clock time (sec)
51 double speed; // Speed (points.steps/sec)
52 double min; // Minimum MPI time (sec)
53 double avg; // Average MPI time (sec)
54 double max; // Maximum MPI time (sec)
55 size_t tnc; // Number of grid points
56 long mem; // Maximum resident memory (kB)
57} timing;
58
59/**
60Given a timer, iteration count *i*, total number of cells *tnc* and
61array of MPI timings *mpi* (with a size equal to the number of
62processes), this function returns the statistics above. */
63
64timing timer_timing (timer t, int i, size_t tnc, double * mpi)
65{
66 timing s;
67#if _MPI
68 s.avg = mpi_time - t.tm;
69#endif
70 clock_t end = clock();
71 s.cpu = ((double) (end - t.c))/CLOCKS_PER_SEC;
72 s.real = timer_elapsed (t);
73 if (tnc == 0) {
74 double n = 0;
75 foreach(reduction(+:n)) n++;
76 s.tnc = n;
77 tnc = n*i;
78 }
79 else
80 s.tnc = tnc;
81#if _GNU_SOURCE
82 struct rusage usage;
84 s.mem = usage.ru_maxrss;
85#else
86 s.mem = 0;
87#endif
88#if _MPI
89 if (mpi)
91 s.max = s.min = s.avg;
97 s.real /= npe();
98 s.avg /= npe();
99 s.mem /= npe();
100#else
101 s.min = s.max = s.avg = 0.;
102#endif
103 s.speed = s.real > 0. ? tnc/s.real : -1.;
104 return s;
105}
106
107/**
108This function writes timing statistics on standard output. */
109
110void timer_print (timer t, int i, size_t tnc)
111{
112#if _GPU
113 glFinish(); // make sure rendering is done on the GPU
114#endif
115 timing s = timer_timing (t, i, tnc, NULL);
116 fprintf (fout,
117 "\n# " GRIDNAME
118 ", %d steps, %g CPU, %.4g real, %.3g points.step/s, %d var\n",
119 i, s.cpu, s.real, s.speed, (int) (datasize/sizeof(real)));
120#if _MPI
121 fprintf (fout,
122 "# %d procs, MPI: min %.2g (%.2g%%) "
123 "avg %.2g (%.2g%%) max %.2g (%.2g%%)\n",
124 npe(),
125 s.min, 100.*s.min/s.real,
126 s.avg, 100.*s.avg/s.real,
127 s.max, 100.*s.max/s.real);
128#endif
129 fflush (stdout);
130}
131
132/**
133## Simple field statistics
134
135The *normf()* function returns the (volume) average, RMS norm, max
136norm and volume for field *f*. */
137
138typedef struct {
139 double avg, rms, max, volume;
140} norm;
141
143{
144 double avg = 0., rms = 0., max = 0., volume = 0.;
145 foreach(reduction(max:max) reduction(+:avg)
146 reduction(+:rms) reduction(+:volume))
147 if (f[] != nodata && dv() > 0.) {
148 double v = fabs(f[]);
149 if (v > max) max = v;
150 volume += dv();
151 avg += dv()*v;
152 rms += dv()*sq(v);
153 }
154 norm n;
155 n.avg = volume ? avg/volume : 0.;
156 n.rms = volume ? sqrt(rms/volume) : 0.;
157 n.max = max;
158 n.volume = volume;
159 return n;
160}
161
162/**
163The *statsf()* function returns the minimum, maximum, volume sum,
164standard deviation and volume for field *f*. */
165
166typedef struct {
167 double min, max, sum, stddev, volume;
168} stats;
169
171{
172 double min = 1e100, max = -1e100, sum = 0., sum2 = 0., volume = 0.;
173 foreach(reduction(+:sum) reduction(+:sum2) reduction(+:volume)
175 if (dv() > 0. && f[] != nodata) {
176 volume += dv();
177 sum += dv()*f[];
178 sum2 += dv()*sq(f[]);
179 if (f[] > max) max = f[];
180 if (f[] < min) min = f[];
181 }
182 stats s;
183 s.min = min, s.max = max, s.sum = sum, s.volume = volume;
184 if (volume > 0.)
185 sum2 -= sum*sum/volume;
186 s.stddev = sum2 > 0. ? sqrt(sum2/volume) : 0.;
187 return s;
188}
189
190/**
191## Slope limiters
192
193Given three values, these [slope
194limiters](https://en.wikipedia.org/wiki/Flux_limiter#Limiter_functions)
195return the corresponding slope-limited gradient. */
196
197static double generic_limiter (double r, double beta)
198{
199 double v1 = min (r, beta), v2 = min (beta*r, 1.);
200 v1 = max (0., v1);
201 return max (v1, v2);
202}
203
204double minmod (double s0, double s1, double s2) {
205 return s1 == s0 ? 0. : generic_limiter ((s2 - s1)/(s1 - s0), 1.)*(s1 - s0);
206}
207
208double superbee (double s0, double s1, double s2) {
209 return s1 == s0 ? 0. : generic_limiter ((s2 - s1)/(s1 - s0), 2.)*(s1 - s0);
210}
211
212double sweby (double s0, double s1, double s2) {
213 return s1 == s0 ? 0. : generic_limiter ((s2 - s1)/(s1 - s0), 1.5)*(s1 - s0);
214}
215
216/**
217This is the [generalised minmod
218limiter](https://en.wikipedia.org/wiki/Flux_limiter#Generalised_minmod_limiter).
219The \f$\theta\f$ global variable can be used to tune the limiting
220(\f$\theta=1\f$ gives minmod, the most dissipative limiter and \f$\theta=2\f$
221gives superbee, the least dissipative). */
222
223double theta = 1.3 [0];
224
225double minmod2 (double s0, double s1, double s2)
226{
227 if (s0 < s1 && s1 < s2) {
228 double d1 = theta*(s1 - s0), d2 = (s2 - s0)/2., d3 = theta*(s2 - s1);
229 if (d2 < d1) d1 = d2;
230 return min(d1, d3);
231 }
232 if (s0 > s1 && s1 > s2) {
233 double d1 = theta*(s1 - s0), d2 = (s2 - s0)/2., d3 = theta*(s2 - s1);
234 if (d2 > d1) d1 = d2;
235 return max(d1, d3);
236 }
237 return 0.;
238}
239
240/**
241Given a list of scalar fields *f*, this function fills the gradient
242fields *g* with the corresponding gradients. If the *gradient*
243attribute of a field is set (typically to one of the limiting
244functions above), it is used to compute the gradient, otherwise simple
245centered differencing is used. */
246
248{
250 for (int _i = 0; _i < _N; _i++) /* foreach */ {
251 scalar s; vector v;
252 for (s,v in f,g) {
253 if (s.gradient)
254 for (int _d = 0; _d < dimension; _d++) {
255#if EMBED
256 if (!fs.x[] || !fs.x[1])
257 v.x[] = 0.;
258 else
259#endif
260 v.x[] = s.gradient (s[-1], s[], s[1])/Delta;
261 }
262 else // centered
263 for (int _d = 0; _d < dimension; _d++) {
264#if EMBED
265 if (!fs.x[] || !fs.x[1])
266 v.x[] = 0.;
267 else
268#endif
269 v.x[] = (s[1] - s[-1])/(2.*Delta);
270 }
271 }
272 }
273}
274
275/**
276## Other functions
277
278Given a velocity field \f$\mathbf{u}\f$, this function fills a scalar
279field \f$\omega\f$ with the vorticity field
280\f[
281\omega = \partial_x u_y - \partial_y u_x
282\f]
283To properly take the metric into account, \f$\omega\f$ is computed as an
284average over the (surface) element, which is easily obtained as
285the circulation of \f$\mathbf{u}\f$ along the boundary of the
286element. Using the definitions of the [metric
287factors](README#general-orthogonal-coordinates) `fm` and `cm`, this
288gives the expression below. */
289
291{
292 for (int _i = 0; _i < _N; _i++) /* foreach */
293 omega[] = ((fm.x[1] - fm.x[])*u.y[] +
294 fm.x[1]*u.y[1] - fm.x[]*u.y[-1] -
295 (fm.y[0,1] - fm.y[])*u.x[] +
296 fm.y[]*u.x[0,-1] - fm.y[0,1]*u.x[0,1])/(2.*(cm[] + SEPS)*Delta);
297}
298
299/**
300Given two scalar fields *s* and *sn* this function returns the maximum
301of their absolute difference. */
302
304{
305 double max = 0.;
306 foreach(reduction(max:max)) {
307 if (dv() > 0.) {
308 double ds = fabs (s[] - sn[]);
309 if (ds > max)
310 max = ds;
311 }
312 sn[] = s[];
313 }
314 return max;
315}
316
317/**
318These functions return the scalar/vector fields called *name*, or
319-1 if they don't exist. */
320
321scalar lookup_field (const char * name)
322{
323 if (name)
324 for (int _s = 0; _s < 1; _s++) /* scalar in all */
325 if (!strcmp (s.name, name))
326 return s;
327 return (scalar){-1};
328}
329
330vector lookup_vector (const char * name)
331{
332 if (name) {
333 char component[strlen(name) + 3];
334 strcpy (component, name);
335 strcat (component, ".x");
336 for (int _s = 0; _s < 1; _s++) /* scalar in all */
337 if (!strcmp (s.name, component))
338 return s.v;
339 }
340 return (vector){{-1}};
341}
342
343/**
344The macro below traverses the set of sub-segments intersecting the
345mesh and spanning the [A:B] segment. The pair of coordinates defining
346the sub-segment contained in each cell are defined by `p[0]` and
347`p[1]`. */
348
350{
351 double norm = sqrt(sq(S[1].x - S[0].x) + sq(S[1].y - S[0].y));
352 if (norm > 0.) {
353 coord t = {(S[1].x - S[0].x)/norm + 1e-6, (S[1].y - S[0].y)/norm - 1.5e-6};
354 double alpha = S[0].x*t.y - S[0].y*t.x;
355 foreach (reductions)
356 if (fabs(t.y*x - t.x*y - alpha) < 0.708*Delta_x) {
357 coord _o = {x,y}, p[2];
358 int _n = 0;
359 for (int _d = 0; _d < dimension; _d++)
360 if (t.x)
361 for (int _i = -1; _i <= 1 && _n < 2; _i += 2) {
362 p[_n].x = _o.x + _i*Delta_x/2.;
363 double a = (p[_n].x - S[0].x)/t.x;
364 p[_n].y = S[0].y + a*t.y;
365 if (fabs(p[_n].y - _o.y) <= Delta_x/2.) {
366 a = clamp (a, 0., norm);
367 p[_n].x = S[0].x + a*t.x, p[_n].y = S[0].y + a*t.y;
368 if (fabs(p[_n].x - _o.x) <= Delta_x/2. &&
369 fabs(p[_n].y - _o.y) <= Delta_x/2.)
370 _n++;
371 }
372 }
373 if (_n == 2)
374 {...}
375 }
376 }
377}
378
379/**
380This function returns a summary of the currently-defined fields. */
381
383{
384 fprintf (ferr, "# t = %g, fields = {", t);
385 for (int _s = 0; _s < 1; _s++) /* scalar in list */
386 fprintf (ferr, " %s", s.name);
387 fputs (" }\n", ferr);
388 fprintf (ferr, "# %12s: %12s %12s %12s %12s\n",
389 "name", "min", "avg", "stddev", "max");
390 for (int _s = 0; _s < 1; _s++) /* scalar in list */ {
391 stats ss = statsf (s);
392 fprintf (ferr, "# %12s: %12g %12g %12g %12g\n",
393 s.name, ss.min, ss.sum/ss.volume, ss.stddev, ss.max);
394 }
395}
396
397#include "output.h"
398
399#ifdef DISPLAY
400# include "display.h" // nodep
401#endif
#define u
Definition advection.h:30
vector g[]
We store the combined pressure gradient and acceleration field in g*.
Definition all-mach.h:65
const vector alpha
Definition all-mach.h:47
const vector a
Definition all-mach.h:59
int npe
Definition balance.h:195
int min
Definition balance.h:192
struct @5 mpi
#define GRIDNAME
Definition bitree.h:4
#define dimension
Definition bitree.h:3
define double double char Reduce reductions
double real
Definition cartesian.h:6
define VT _attribute[s.i] v y scalar * list
Definition cartesian.h:276
int y
Definition common.h:76
int x
Definition common.h:76
scalar * all
Definition common.h:342
const scalar cm[]
Definition common.h:397
#define nodata
Definition common.h:7
#define HUGE
Definition common.h:6
static number sq(number x)
Definition common.h:11
Grid * grid
Definition common.h:32
int list_len(scalar *list)
Definition common.h:180
double timer_elapsed(timer t)
Definition common.h:379
static number clamp(number x, number a, number b)
Definition common.h:15
#define dv()
Definition common.h:92
int vectors_len(vector *list)
Definition common.h:250
const vector fm[]
Definition common.h:396
size_t datasize
Definition common.h:132
#define SEPS
Definition common.h:402
scalar f[]
The primary fields are:
Definition two-phase.h:56
#define p
Definition tree.h:320
#define assert(a)
Definition config.h:107
else return n
Definition curvature.h:101
scalar s
Definition embed-tree.h:56
double v[2]
Definition embed.h:383
vector fs[]
Definition embed.h:22
scalar int i
Definition embed.h:74
#define glFinish
Definition glad.h:1945
vector beta[]
Definition hele-shaw.h:40
double * sum
scalar S
Definition gotm.h:16
macro
We also redefine the "per field" (inner) traversal.
Definition layers.h:18
size_t max
Definition mtrace.h:8
def _i
Definition stencils.h:405
scalar omega[]
We allocate the vorticity field , the streamfunction field and a structure to store the statistics o...
Definition stream.h:39
long n
Definition common.h:27
long tn
Definition common.h:28
Definition common.h:78
double x
Definition common.h:79
Definition utils.h:138
double avg
Definition utils.h:139
The statsf() function returns the minimum, maximum, volume sum, standard deviation and volume for fie...
Definition utils.h:166
double max
Definition utils.h:167
Definition utils.h:48
double speed
Definition utils.h:51
double min
Definition utils.h:52
double real
Definition utils.h:50
double avg
Definition utils.h:53
double cpu
Definition utils.h:49
double max
Definition utils.h:54
long mem
Definition utils.h:56
size_t tnc
Definition utils.h:55
scalar x
Definition common.h:47
scalar y
Definition common.h:49
void timer_print(timer t, int i, size_t tnc)
This function writes timing statistics on standard output.
Definition utils.h:110
double sweby(double s0, double s1, double s2)
Definition utils.h:212
vector lookup_vector(const char *name)
Definition utils.h:330
long nc
Definition utils.h:17
double tp
Definition utils.h:21
stats statsf(scalar f)
Definition utils.h:170
scalar lookup_field(const char *name)
These functions return the scalar/vector fields called name, or -1 if they don't exist.
Definition utils.h:321
timer gt
Definition utils.h:27
double change(scalar s, scalar sn)
Given two scalar fields s and sn this function returns the maximum of their absolute difference.
Definition utils.h:303
double ispeed
Definition utils.h:25
void gradients(scalar *f, vector *g)
Given a list of scalar fields f, this function fills the gradient fields g with the corresponding gra...
Definition utils.h:247
double speed
Definition utils.h:23
double t
Definition utils.h:21
double CFL
Definition utils.h:10
double DT
Definition utils.h:10
static double generic_limiter(double r, double beta)
Definition utils.h:197
void fields_stats(scalar *list=all)
This function returns a summary of the currently-defined fields.
Definition utils.h:382
double superbee(double s0, double s1, double s2)
Definition utils.h:208
double minmod(double s0, double s1, double s2)
Definition utils.h:204
void vorticity(const vector u, scalar omega)
Definition utils.h:290
double theta
This is the generalised minmod limiter.
Definition utils.h:223
void update_perf()
Performance statistics are gathered by this function, which is typically called by the run() loop.
Definition utils.h:34
norm normf(scalar f)
Definition utils.h:142
struct @16 perf
Performance statistics are stored in this structure.
timing timer_timing(timer t, int i, size_t tnc, double *mpi)
Given a timer, iteration count i, total number of cells tnc and array of MPI timings mpi (with a size...
Definition utils.h:64
long tnc
Definition utils.h:19
macro foreach_segment(coord S[2], coord p[2], Reduce reductions=None)
The macro below traverses the set of sub-segments intersecting the mesh and spanning the [A:B] segmen...
Definition utils.h:349
double minmod2(double s0, double s1, double s2)
Definition utils.h:225
src vof fflush(ferr)