src/test/hydrostatic3.c
Hydrostatic balance with refined embedded boundaries in 3D
This is very close to hydrostatic2.c but in 3D.
#include "grid/octree.h"
#include "embed.h"
#include "navier-stokes/centered.h"
#include "view.h"
We use a similar porous medium as in /src/examples/porous3D.c.
void porous (scalar cs, face vector fs)
{
int ns = 60; // 160, 80
[ns];
coord pcdouble R[ns];
(0);
srand double a = 0.5, b = 0.04;
for (int i = 0; i < ns; i++) {
foreach_dimension()
[i].x = a*noise();
pc[i] = 2.*(0.02 + b*fabs(noise()));
R}
vertex scalar phi[];
foreach_vertex() {
[] = HUGE;
phifor (double xp = -L0; xp <= L0; xp += L0)
for (double yp = -L0; yp <= L0; yp += L0)
for (double zp = -L0; zp <= L0; zp += L0)
for (int i = 0; i < ns; i++)
[] = intersection (phi[], (sq(x + xp - pc[i].x)
phi+ sq(y + yp - pc[i].y)
+ sq(z + zp - pc[i].z)
- sq(R[i])));
[] = - phi[];
phi}
fractions (phi, cs, fs);
fractions_cleanup (cs, fs);
}
const face vector G[] = {1.,2.,3.};
void restriction_exact (Point point, scalar s)
{
[] = (cs[] != 0.)*(G.x[]*x + G.y[]*y + G.z[]*z); // exact pressure
s}
void refine_exact (Point point, scalar s)
{
foreach_child()
[] = (cs[] != 0.)*(G.x[]*x + G.y[]*y + G.z[]*z); // exact pressure
s}
int main()
{
(1 << 5);
init_grid (-0.5, -0.5, -0.5); origin
The events of the Navier-Stokes solver are called “by hand”.
event ("metric");
event ("defaults");
porous (cs, fs);
#if 0
refine (level < 7 && cs[] > 0 && cs[] < 1);
porous (cs, fs);
#else
({cs}, (double[]){0.01}, 7);
adapt_wavelet porous (cs, fs);
({cs}, (double[]){0.01}, 7);
adapt_wavelet porous (cs, fs);
#endif
= G;
a
= 1e-9;
TOLERANCE = 10;
NITERMAX = fm;
alpha = 1.;
dt
foreach()
[] = (cs[] != 0.)*(G.x[]*x + G.y[]*y + G.z[]*z); // exact pressure
p#if 0
.restriction = restriction_exact;
p.refine = p.prolongation = refine_exact;
p.dirty = true;
p#endif
event ("acceleration");
#if 1
event ("projection");
#else
foreach_face()
.x[] -= alpha.x[] ? dt*alpha.x[]*face_gradient_x (p, 0) : 0.;
uf
face vector gf[];
foreach_face()
.x[] = fm.x[] ? fm.x[]*a.x[] - alpha.x[]*(p[] - p[-1])/Delta : 0.;
gf
({g});
trash foreach()
foreach_dimension()
.x[] = (gf.x[] + gf.x[1])/(fm.x[] + fm.x[1] + SEPS);
g
correction (dt);
#endif
We check the convergence rate and the norms of the velocity field (which should be negligible).
fprintf (stderr, "mgp %.10f %.10f %d %d %d\n",
.resb, mgp.resa, mgp.i, mgp.minlevel, mgp.nrelax);
mgpfprintf (stderr, "umax %.12f %.12f %.12f %.12f %.12f\n",
normf(u.x).max, normf(u.y).max,
normf(uf.x).max, normf(uf.y).max, normf(uf.z).max);
The pressure is hydrostatic, in each of the pores.

view (fov = 19, width = 400, height = 400);
squares ("p", spread = -1);
save ("p.png");
.nodump = false;
pscalar ep[];
foreach()
[] = p[] - (cs[] != 0.)*(G.x[]*x + G.y[]*y);
epdump ();
#if 0
[bottom] = dirichlet (y);
pforeach() {
if (cs[] > 0.)
printf ("%g %g %g %g %g %g %g %g %g %g %g\n",
, y, z, p[], u.x[], u.y[], u.z[], g.x[], g.y[], g.z[], cs[]);
x[] = G.x[]*x + G.y[]*y;
p}
foreach_face (x)
printf ("fx %g %g %g %g\n", x, y, z, face_gradient_x (p, 0));
foreach_face (y)
printf ("fy %g %g %g %g\n", x, y, z, face_gradient_y (p, 0));
foreach_face (z) {
int i = 0;
if (fs.z[0,0,i] > 0. && fs.z[0,0,i] < 1. &&
(point, p, i) != 0.) {
embed_face_gradient_z printf ("fz %g %g %g %g %g\n", x, y, z, (p[0,0,i] - p[0,0,i-1])/Delta,
(point, p, i));
embed_face_gradient_z scalar a = p;
{
= embed_face_barycentre_z (point, i);
coord p int j = sign(p.x), k = sign(p.y);
printf ("bary %g %g %g %d %d\n", p.x, p.y, p.z, j, k);
.x = fabs(p.x), p.y = fabs(p.y);
pprintf ("valz %g\n",
(((a[0,0,i] - a[0,0,i-1])*(1. - p.x) +
(a[j,0,i] - a[j,0,i-1])*p.x)*(1. - p.y) +
((a[0,k,i] - a[0,k,i-1])*(1. - p.x) +
(a[j,k,i] - a[j,k,i-1])*p.x)*p.y)/Delta);
for (int l = -1; l <= 1; l++)
for (int m = -1; m <= 1; m++)
printf ("point %d %d %g %g %g %g\n", l, m, fs.z[l,m,i],
(a[l,m,i] - a[l,m,i-1])/Delta, a[l,m,i], a[l,m,i-1]);
exit (1);
}
}
}
#endif
}