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
coord pc[ns];
double R[ns];
srand (0);
double a = 0.5, b = 0.04;
for (int i = 0; i < ns; i++) {
foreach_dimension()
pc[i].x = a*noise();
R[i] = 2.*(0.02 + b*fabs(noise()));
}
vertex scalar phi[];
foreach_vertex() {
phi[] = HUGE;
for (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++)
phi[] = intersection (phi[], (sq(x + xp - pc[i].x)
+ 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)
{
s[] = (cs[] != 0.)*(G.x[]*x + G.y[]*y + G.z[]*z); // exact pressure
}
void refine_exact (Point point, scalar s)
{
foreach_child()
s[] = (cs[] != 0.)*(G.x[]*x + G.y[]*y + G.z[]*z); // exact pressure
}
int main()
{
init_grid (1 << 5);
origin (-0.5, -0.5, -0.5);
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
adapt_wavelet ({cs}, (double[]){0.01}, 7);
porous (cs, fs);
adapt_wavelet ({cs}, (double[]){0.01}, 7);
porous (cs, fs);
#endif
a = G;
TOLERANCE = 1e-9;
NITERMAX = 10;
alpha = fm;
dt = 1.;
foreach()
p[] = (cs[] != 0.)*(G.x[]*x + G.y[]*y + G.z[]*z); // exact pressure
#if 0
p.restriction = restriction_exact;
p.refine = p.prolongation = refine_exact;
p.dirty = true;
#endif
event ("acceleration");
#if 1
event ("projection");
#else
foreach_face()
uf.x[] -= alpha.x[] ? dt*alpha.x[]*face_gradient_x (p, 0) : 0.;
face vector gf[];
foreach_face()
gf.x[] = fm.x[] ? fm.x[]*a.x[] - alpha.x[]*(p[] - p[-1])/Delta : 0.;
trash ({g});
foreach()
foreach_dimension()
g.x[] = (gf.x[] + gf.x[1])/(fm.x[] + fm.x[1] + SEPS);
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",
mgp.resb, mgp.resa, mgp.i, mgp.minlevel, mgp.nrelax);
fprintf (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");
p.nodump = false;
scalar ep[];
foreach()
ep[] = p[] - (cs[] != 0.)*(G.x[]*x + G.y[]*y);
dump ();
#if 0
p[bottom] = dirichlet (y);
foreach() {
if (cs[] > 0.)
printf ("%g %g %g %g %g %g %g %g %g %g %g\n",
x, y, z, p[], u.x[], u.y[], u.z[], g.x[], g.y[], g.z[], cs[]);
p[] = G.x[]*x + G.y[]*y;
}
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. &&
embed_face_gradient_z (point, p, i) != 0.) {
printf ("fz %g %g %g %g %g\n", x, y, z, (p[0,0,i] - p[0,0,i-1])/Delta,
embed_face_gradient_z (point, p, i));
scalar a = p;
{
coord p = embed_face_barycentre_z (point, i);
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);
p.x = fabs(p.x), p.y = fabs(p.y);
printf ("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
}