Basilisk CFD
Adaptive Cartesian mesh PDE framework
Loading...
Searching...
No Matches
geometry.h
Go to the documentation of this file.
1/** @file geometry.h
2 */
3/**
4# Basic geometric functions
5
6These basic geometric functions are mostly related to Volume-Of-Fluid
7computations.
8
9We consider a square cell of size unity centered on the origin, cut by
10a straight line.
11
12![Cell and interface](/src/figures/square.svg)
13
14The line can be described by the equation
15\f[
16n_xx+n_yy=\alpha
17\f]
18where \f$\mathbf{n}\f$ is a vector normal to the interface and \f$\alpha\f$ is
19the intercept. We note \f$c\f$ the volume of the part of the square cell
20which lies "inside" the interface, where "inside" is defined by
21convention as the opposite direction to the normal vector \f$\mathbf{n}\f$
22(i.e. the normal vector is pointing "outside").
23
24With these definitions, the interface is uniquely defined by providing
25\f$\mathbf{n}\f$ and either \f$\alpha\f$ or \f$c\f$ i.e. there is a unique
26function which computes \f$\alpha\f$ given \f$c\f$ and \f$\mathbf{n}\f$. We call
27this function `line_alpha()` and define it as: */
28
29#if dimension == 1
30double line_alpha (double c, coord n)
31{
32 return clamp (c, 0., 1.) - 0.5;
33}
34#endif // dimension == 1
35
36#if dimension >= 2
37double line_alpha (double c, coord n)
38{
39 double alpha, n1, n2;
40
41 n1 = fabs (n.x); n2 = fabs (n.y);
42 if (n1 > n2)
43 swap (double, n1, n2);
44
45 c = clamp (c, 0., 1.);
46 double v1 = n1/2.;
47 if (c <= v1/n2)
48 alpha = sqrt (2.*c*n1*n2);
49 else if (c <= 1. - v1/n2)
50 alpha = c*n2 + v1;
51 else
52 alpha = n1 + n2 - sqrt (2.*n1*n2*(1. - c));
53
54 if (n.x < 0.)
55 alpha += n.x;
56 if (n.y < 0.)
57 alpha += n.y;
58
59 return alpha - (n.x + n.y)/2.;
60}
61#endif // dimension >= 2
62
63#if dimension >= 3
64double plane_alpha (double c, coord n)
65{
66 double alpha;
67 coord n1;
68
69 n1.x = fabs (n.x); n1.y = fabs (n.y); n1.z = fabs (n.z);
70
71 double m1, m2, m3;
72 m1 = min(n1.x, n1.y);
73 m3 = max(n1.x, n1.y);
74 m2 = n1.z;
75 if (m2 < m1) {
76 double tmp = m1;
77 m1 = m2;
78 m2 = tmp;
79 }
80 else if (m2 > m3) {
81 double tmp = m3;
82 m3 = m2;
83 m2 = tmp;
84 }
85 double m12 = m1 + m2;
86 double pr = max(6.*m1*m2*m3, 1e-50);
87 double V1 = m1*m1*m1/pr;
88 double V2 = V1 + (m2 - m1)/(2.*m3), V3;
89 double mm;
90 if (m3 < m12) {
91 mm = m3;
92 V3 = (m3*m3*(3.*m12 - m3) + m1*m1*(m1 - 3.*m3) + m2*m2*(m2 - 3.*m3))/pr;
93 }
94 else {
95 mm = m12;
96 V3 = mm/(2.*m3);
97 }
98
99 c = clamp (c, 0., 1.);
100 double ch = min(c, 1. - c);
101 if (ch < V1)
102 alpha = pow (pr*ch, 1./3.);
103 else if (ch < V2)
104 alpha = (m1 + sqrt(m1*m1 + 8.*m2*m3*(ch - V1)))/2.;
105 else if (ch < V3) {
106 double p12 = sqrt (2.*m1*m2);
107 double q = 3.*(m12 - 2.*m3*ch)/(4.*p12);
108 double teta = acos(clamp(q,-1.,1.))/3.;
109 double cs = cos(teta);
110 alpha = p12*(sqrt(3.*(1. - cs*cs)) - cs) + m12;
111 }
112 else if (m12 <= m3)
113 alpha = m3*ch + mm/2.;
114 else {
115 double p = m1*(m2 + m3) + m2*m3 - 1./4., p12 = sqrt(p);
116 double q = 3.*m1*m2*m3*(1./2. - ch)/(2.*p*p12);
117 double teta = acos(clamp(q,-1.,1.))/3.;
118 double cs = cos(teta);
119 alpha = p12*(sqrt(3.*(1. - cs*cs)) - cs) + 1./2.;
120 }
121 if (c > 1./2.) alpha = 1. - alpha;
122
123 if (n.x < 0.)
124 alpha += n.x;
125 if (n.y < 0.)
126 alpha += n.y;
127 if (n.z < 0.)
128 alpha += n.z;
129
130 return alpha - (n.x + n.y + n.z)/2.;;
131}
132#else // dimension < 3
133# define plane_alpha line_alpha
134#endif
135
136/**
137Conversely there is a unique function computing \f$c\f$ as a function of
138\f$\mathbf{n}\f$ and \f$\alpha\f$. We call this function `line_area()` and
139define it as: */
140
141#if dimension == 1
142double line_area (double nx, double alpha)
143{
144 double area;
145
146 alpha += nx/2.;
147 if (nx < 0.) {
148 alpha -= nx;
149 nx = -nx;
150 }
151
152 if (alpha <= 0.)
153 return 0.;
154
155 if (alpha >= nx)
156 return 1.;
157
158 area = alpha/nx;
159 return clamp (area, 0., 1.);
160}
161#define plane_volume(n, alpha) line_area(n.x, alpha)
162#endif // dimension == 1
163
164#if dimension >= 2
165double line_area (double nx, double ny, double alpha)
166{
167 double a, v, area;
168
169 alpha += (nx + ny)/2.;
170 if (nx < 0.) {
171 alpha -= nx;
172 nx = - nx;
173 }
174 if (ny < 0.) {
175 alpha -= ny;
176 ny = - ny;
177 }
178
179 if (alpha <= 0.)
180 return 0.;
181
182 if (alpha >= nx + ny)
183 return 1.;
184
185 if (nx < 1e-10)
186 area = alpha/ny;
187 else if (ny < 1e-10)
188 area = alpha/nx;
189 else {
190 v = sq(alpha);
191
192 a = alpha - nx;
193 if (a > 0.)
194 v -= a*a;
195
196 a = alpha - ny;
197 if (a > 0.)
198 v -= a*a;
199
200 area = v/(2.*nx*ny);
201 }
202
203 return clamp (area, 0., 1.);
204}
205#endif // dimension >= 2
206
207#if dimension >= 3
208double plane_volume (coord n, double alpha)
209{
210 double al = alpha + (n.x + n.y + n.z)/2. +
211 max(0., -n.x) + max(0., -n.y) + max(0., -n.z);
212 if (al <= 0.)
213 return 0.;
214 double tmp = fabs(n.x) + fabs(n.y) + fabs(n.z);
215 if (al >= tmp)
216 return 1.;
217 if (tmp < 1e-10)
218 return 0.;
219 double n1 = fabs(n.x)/tmp;
220 double n2 = fabs(n.y)/tmp;
221 double n3 = fabs(n.z)/tmp;
222 al = max(0., min(1., al/tmp));
223 double al0 = min(al, 1. - al);
224 double b1 = min(n1, n2);
225 double b3 = max(n1, n2);
226 double b2 = n3;
227 if (b2 < b1) {
228 tmp = b1;
229 b1 = b2;
230 b2 = tmp;
231 }
232 else if (b2 > b3) {
233 tmp = b3;
234 b3 = b2;
235 b2 = tmp;
236 }
237 double b12 = b1 + b2;
238 double bm = min(b12, b3);
239 double pr = max(6.*b1*b2*b3, 1e-50);
240 if (al0 < b1)
241 tmp = al0*al0*al0/pr;
242 else if (al0 < b2)
243 tmp = 0.5*al0*(al0 - b1)/(b2*b3) + b1*b1*b1/pr;
244 else if (al0 < bm)
245 tmp = (al0*al0*(3.*b12 - al0) + b1*b1*(b1 - 3.*al0) +
246 b2*b2*(b2 - 3.*al0))/pr;
247 else if (b12 < b3)
248 tmp = (al0 - 0.5*bm)/b3;
249 else
250 tmp = (al0*al0*(3. - 2.*al0) + b1*b1*(b1 - 3.*al0) +
251 b2*b2*(b2 - 3.*al0) + b3*b3*(b3 - 3.*al0))/pr;
252
253 double volume = al <= 0.5 ? tmp : 1. - tmp;
254 return clamp (volume, 0., 1.);
255}
256#elif dimension == 2
257# define plane_volume(n, alpha) line_area(n.x, n.y, alpha)
258#endif
259
260/**
261VOF algorithms require the computation of volume fractions on
262(rectangular) parts of the initial square cell.
263
264We first define a function which takes an interface definition
265(\f$\mathbf{n}\f$, \f$\alpha\f$), the coordinates of the lower-left `a`
266and upper-right `b` corners of a rectangle and returns the
267fraction of this rectangle which lies inside the interface. */
268
270{
271 coord n1;
272 for (int _d = 0; _d < dimension; _d++) {
273 alpha -= n.x*(b.x + a.x)/2.;
274 n1.x = n.x*(b.x - a.x);
275 }
276 return plane_volume (n1, alpha);
277}
278
279/**
280From the interface definition, it is also possible to compute the
281coordinates of the segment in 2D, or facet in 3D, representing the
282interface in the unit cell.
283
284In two dimensions, the function below returns the 0,1 or 2 coordinates
285(stored in the `p` array provided by the user) of the corresponding
286interface segments. The case where only 1 coordinate is returned
287corresponds to the degenerate case where the interface intersects the
288cell exactly on a vertex.
289
290In three dimensions, the function returns up to 12 coordinates of the
291planar fragment. */
292
293#if dimension <= 2
294int facets (coord n, double alpha, coord p[2])
295{
296 int i = 0;
297 for (double s = -0.5; s <= 0.5; s += 1.)
298 for (int _d = 0; _d < dimension; _d++)
299 if (fabs (n.y) > 1e-4 && i < 2) {
300 double a = (alpha - s*n.x)/n.y;
301 if (a >= -0.5 && a <= 0.5) {
302 p[i].x = s;
303 p[i++].y = a;
304 }
305 }
306 return i;
307}
308#else
309static coord cube_edge[12][2] = {
310 {{0.,0.,0.},{1.,0.,0.}},{{0.,0.,1.},{1.,0.,1.}},
311 {{0.,1.,1.},{1.,1.,1.}},{{0.,1.,0.},{1.,1.,0.}},
312 {{0.,0.,0.},{0.,1.,0.}},{{0.,0.,1.},{0.,1.,1.}},
313 {{1.,0.,1.},{1.,1.,1.}},{{1.,0.,0.},{1.,1.,0.}},
314 {{0.,0.,0.},{0.,0.,1.}},{{1.,0.,0.},{1.,0.,1.}},
315 {{1.,1.,0.},{1.,1.,1.}},{{0.,1.,0.},{0.,1.,1.}}
316};
317
318/* first index is the edge number, second index is the edge
319 orientation (0 or 1), third index are the edges which this edge may
320 connect to in order */
321static int cube_connect[12][2][4] = {
322 {{9, 1, 8}, {4, 3, 7}}, /* 0 */
323 {{6, 2, 5}, {8, 0, 9}}, /* 1 */
324 {{10, 3, 11}, {5, 1, 6}}, /* 2 */
325 {{7, 0, 4}, {11, 2, 10}}, /* 3 */
326 {{3, 7, 0}, {8, 5, 11}}, /* 4 */
327 {{11, 4, 8}, {1, 6, 2}}, /* 5 */
328 {{2, 5, 1}, {9, 7, 10}}, /* 6 */
329 {{10, 6, 9}, {0, 4, 3}}, /* 7 */
330 {{5, 11, 4}, {0, 9, 1}}, /* 8 */
331 {{1, 8, 0}, {7, 10, 6}}, /* 9 */
332 {{6, 9, 7}, {3, 11, 2}}, /* 10 */
333 {{2, 10, 3}, {4, 8, 5}} /* 11 */
334};
335
336int facets (coord n, double alpha, coord v[12], double h)
337{
338 coord a[12];
339 int orient[12];
340
341 for (int i = 0; i < 12; i++) {
342 coord e, d;
343 double den = 0., t = alpha;
344 for (int _d = 0; _d < dimension; _d++) {
345 d.x = h*(cube_edge[i][0].x - 0.5);
346 e.x = h*(cube_edge[i][1].x - 0.5);
347 den += n.x*(e.x - d.x);
348 t -= n.x*d.x;
349 }
350 orient[i] = -1;
351 if (fabs (den) > 1e-10) {
352 t /= den;
353 if (t >= 0. && t < 1.) {
354 double s = - alpha;
355 for (int _d = 0; _d < dimension; _d++) {
356 a[i].x = d.x + t*(e.x - d.x);
357 s += n.x*e.x;
358 }
359 orient[i] = (s > 0.);
360 }
361 }
362 }
363
364 for (int i = 0; i < 12; i++) {
365 int nv = 0, e = i;
366 while (orient[e] >= 0) {
367 int m = 0, * ne = cube_connect[e][orient[e]];
368 v[nv++] = a[e];
369 orient[e] = -1;
370 while (m < 3 && orient[e] < 0)
371 e = ne[m++];
372 }
373 if (nv > 2)
374 return nv;
375 }
376 return 0;
377}
378#endif // dimension == 3
379
380/**
381This function fills the coordinates *p* of the centroid of the
382interface fragment and returns the length/area of the fragment. */
383
385{
386 alpha += (m.x + m.y)/2.;
387
388 coord n = m;
390 if (n.x < 0.) {
391 alpha -= n.x;
392 n.x = - n.x;
393 }
394
395 p->x = p->y = p->z = 0.;
396
397 if (alpha <= 0. || alpha >= n.x + n.y)
398 return 0.;
399
401 if (n.x < 1e-4) {
402 p->x = 0.;
403 p->y = (m.y < 0. ? 1. - alpha : alpha) - 0.5;
404 return 1.;
405 }
406
407 if (alpha >= n.x) {
408 p->x += 1.;
409 p->y += (alpha - n.x)/n.y;
410 }
411 else
412 p->x += alpha/n.x;
413
414 double ax = p->x, ay = p->y;
415 if (alpha >= n.y) {
416 p->y += 1.;
417 ay -= 1.;
418 p->x += (alpha - n.y)/n.x;
419 ax -= (alpha - n.y)/n.x;
420 }
421 else {
422 p->y += alpha/n.y;
423 ay -= alpha/n.y;
424 }
425
427 p->x /= 2.;
428 p->x = clamp (p->x, 0., 1.);
429 if (m.x < 0.)
430 p->x = 1. - p->x;
431 p->x -= 0.5;
432 }
433
434 return sqrt (ax*ax + ay*ay);
435}
436
437#if dimension == 2
438#define plane_area_center(m,a,p) line_length_center(m,a,p)
439#else // dimension == 3
440double plane_area_center (coord m, double alpha, coord * p)
441{
442 for (int _d = 0; _d < dimension; _d++)
443 if (fabs (m.x) < 1e-4) {
444 coord n, q;
445 ((double *)&n)[0] = m.y;
446 ((double *)&n)[1] = m.z;
447 double length = line_length_center (n, alpha, &q);
448 p->x = 0.;
449 p->y = ((double *)&q)[0];
450 p->z = ((double *)&q)[1];
451 return length;
452 }
453
454 alpha += (m.x + m.y + m.z)/2.;
455 coord n = m;
456 for (int _d = 0; _d < dimension; _d++)
457 if (n.x < 0.) {
458 alpha -= n.x;
459 n.x = - n.x;
460 }
461
462 double amax = n.x + n.y + n.z;
464 p->x = p->y = p->z = 0.;
465 return 0.;
466 }
467
468 double area = sq(alpha);
469 p->x = p->y = p->z = area*alpha;
470
471 for (int _d = 0; _d < dimension; _d++) {
472 double b = alpha - n.x;
473 if (b > 0.) {
474 area -= b*b;
475 p->x -= b*b*(2.*n.x + alpha);
476 p->y -= b*b*b;
477 p->z -= b*b*b;
478 }
479 }
480
481 amax = alpha - amax;
482 for (int _d = 0; _d < dimension; _d++) {
483 double b = amax + n.x;
484 if (b > 0.) {
485 area += b*b;
486 p->y += b*b*(2.*n.y + alpha - n.z);
487 p->z += b*b*(2.*n.z + alpha - n.y);
488 p->x += b*b*b;
489 }
490 }
491
492 area *= 3.;
493 for (int _d = 0; _d < dimension; _d++) {
494 if (area) {
495 p->x /= area*n.x;
496 p->x = clamp (p->x, 0., 1.);
497 }
498 else
499 p->x = 0.;
500 if (m.x < 0.) p->x = 1. - p->x;
501 p->x -= 0.5;
502 }
503
504 return area*sqrt (1./(sq(n.x)*sq(n.y)) +
505 1./(sq(n.x)*sq(n.z)) +
506 1./(sq(n.z)*sq(n.y)))/6.;
507}
508#endif // dimension == 3
509
510/**
511This function fills the coordinates *p* of the centroid of the
512fraction *a* of a square cell lying under the line $(m,alpha)$. */
513
514void line_center (coord m, double alpha, double a, coord * p)
515{
516 alpha += (m.x + m.y)/2.;
517
518 coord n = m;
520 if (n.x < 0.) {
521 alpha -= n.x;
522 n.x = - n.x;
523 }
524
525 p->z = 0.;
526 if (alpha <= 0.) {
527 p->x = p->y = -0.5;
528 return;
529 }
530
531 if (alpha >= n.x + n.y) {
532 p->x = p->y = 0.;
533 return;
534 }
535
537 if (n.x < 1e-4) {
538 p->x = 0.;
539 p->y = sign(m.y)*(a/2. - 0.5);
540 return;
541 }
542
543 p->x = p->y = cube(alpha);
544
546 double b = alpha - n.x;
547 if (b > 0.) {
548 p->x -= sq(b)*(alpha + 2.*n.x);
549 p->y -= cube(b);
550 }
551 }
552
554 p->x /= 6.*sq(n.x)*n.y*a;
555 p->x = sign(m.x)*(p->x - 0.5);
556 }
557}
558
559/**
560This function fills the coordinates *p* of the centroid of the
561fraction *a* of a cubic cell lying under the plane $(m,alpha)$. */
562
563#if dimension == 2
564#define plane_center(m,alpha,a,p) line_center(m,alpha,a,p)
565#else // dimension == 3
566void plane_center (coord m, double alpha, double a, coord * p)
567{
568 for (int _d = 0; _d < dimension; _d++)
569 if (fabs (m.x) < 1e-4) {
570 coord n, q;
571 ((double *)&n)[0] = m.y;
572 ((double *)&n)[1] = m.z;
573 line_center (n, alpha, a, &q);
574 p->x = 0.;
575 p->y = ((double *)&q)[0];
576 p->z = ((double *)&q)[1];
577 return;
578 }
579
580 alpha += (m.x + m.y + m.z)/2.;
581 coord n = m;
582 for (int _d = 0; _d < dimension; _d++)
583 if (n.x < 0.) {
584 alpha -= n.x;
585 n.x = - n.x;
586 }
587
588 if (alpha <= 0. || a == 0.) {
589 p->x = p->y = p->z = -0.5;
590 return;
591 }
592
593 if (alpha >= n.x + n.y + n.z || a == 1.) {
594 p->x = p->y = p->z = 0.;
595 return;
596 }
597
598 p->x = p->y = p->z = sq(sq(alpha));
599 for (int _d = 0; _d < dimension; _d++) {
600 double b = alpha - n.x;
601 if (b > 0.) {
602 p->x -= cube(b)*(3.*n.x + alpha);
603 p->y -= sq(sq(b));
604 p->z -= sq(sq(b));
605 }
606 }
607
608 double amax = alpha - (n.x + n.y + n.z);
609 for (int _d = 0; _d < dimension; _d++) {
610 double b = amax + n.z;
611 if (b > 0.) {
612 p->x += cube(b)*(3.*n.x + alpha - n.y);
613 p->y += cube(b)*(3.*n.y + alpha - n.x);
614 p->z += sq(sq(b));
615 }
616 }
617
618 double b = 24.*n.x*n.y*n.z*a;
619 for (int _d = 0; _d < dimension; _d++) {
620 p->x /= b*n.x;
621 p->x = sign(m.x)*(p->x - 0.5);
622 }
623}
624#endif // dimension == 3
double b2
Definition NASG.h:19
double b1
Definition NASG.h:19
vector q[]
The primitive variables are the momentum , pressure , density , (face) specific volume ,...
Definition all-mach.h:44
const vector alpha
Definition all-mach.h:47
const vector a
Definition all-mach.h:59
scalar h[]
Definition atmosphere.h:6
int min
Definition balance.h:192
#define dimension
Definition bitree.h:3
define m((k)==0 &&(l)==0 &&(m)==0) macro2 foreach_point(double _x=0.
int x
Definition common.h:76
static number sq(number x)
Definition common.h:11
#define swap(type, a, b)
Definition common.h:19
static number clamp(number x, number a, number b)
Definition common.h:15
static int sign(number x)
Definition common.h:13
static number cube(number x)
Definition common.h:12
#define p
Definition tree.h:320
return hxx pow(1.+sq(hx), 3/2.)
else return n
Definition curvature.h:101
scalar s
Definition embed-tree.h:56
scalar cs[]
The volume and area fractions are stored in these fields.
Definition embed.h:21
double v[2]
Definition embed.h:383
double d[2]
Definition embed.h:383
scalar int i
Definition embed.h:74
double t
Definition events.h:24
double line_length_center(coord m, double alpha, coord *p)
This function fills the coordinates p of the centroid of the interface fragment and returns the lengt...
Definition geometry.h:384
#define plane_center(m, alpha, a, p)
This function fills the coordinates p of the centroid of the fraction a of a cubic cell lying under t...
Definition geometry.h:564
double line_alpha(double c, coord n)
Definition geometry.h:37
double rectangle_fraction(coord n, double alpha, coord a, coord b)
VOF algorithms require the computation of volume fractions on (rectangular) parts of the initial squa...
Definition geometry.h:269
void line_center(coord m, double alpha, double a, coord *p)
This function fills the coordinates p of the centroid of the fraction a of a square cell lying under ...
Definition geometry.h:514
#define plane_alpha
Definition geometry.h:133
#define plane_area_center(m, a, p)
Definition geometry.h:438
int facets(coord n, double alpha, coord p[2])
From the interface definition, it is also possible to compute the coordinates of the segment in 2D,...
Definition geometry.h:294
#define plane_volume(n, alpha)
Definition geometry.h:257
double line_area(double nx, double ny, double alpha)
Conversely there is a unique function computing as a function of and .
Definition geometry.h:165
static float area(const KdtRect rect)
Definition kdt.c:439
static float length(const KdtRect rect)
Definition kdt.c:444
size_t max
Definition mtrace.h:8
size *double * b
Definition common.h:78
double z
Definition common.h:79
double x
Definition common.h:79
double y
Definition common.h:79
scalar x
Definition common.h:47
scalar y
Definition common.h:49
scalar c
Definition vof.h:57