sandbox/M1EMN/Exemples/forchheimer.c
Flow in a Sandglass / Hourglass with a bottom orifice
We propose an implementation of the Jop Pouliquen Forterre \mu(I) rheology for the flow in a hourglass.
Coupled trough Jackson method with a gaz with Darcy Forchheimer
Code
Includes and definitions
#include "navier-stokes/centered.h"
#include "vof.h"
// Domain extent
#define LDOMAIN 4.
// heap definition
double H0,R0,D,W,tmax,Q,Qair,Wmin,muwall,WDOMAIN,Hmask,maskr,P1,position,epai;
//film size
double Lz;
passive fluid small density to preserve 0 pressure and small viscocity
#define RHOF 1e-4
#define mug 1e-5
// Maximum refinement
#define LEVEL 7
// ratio of mask section
#define maskr 0.75
//#define MINLEVEL 7
char s[80];
FILE * fpf,*fwq;
scalar f[];
face vector ug[];
scalar In[];
scalar phi[];
scalar * interfaces = {f};
face vector alphav[];
face vector muv[];
face vector av[];
//velocity of granular materials
double ugranular;
Darcy fluid
double betam = 100;
scalar pDarcy[],sourceDarcy[];
face vector beta[];
face vector gradpDarcy[];
mgstats mgpDarcy;
Boundary conditions for air flow, impose pressure at the top P_1
[left] = neumann(0);
pDarcy[right] = neumann(0);
pDarcy[top] = dirichlet(P1);
pDarcy[bottom] = dirichlet(0);
pDarcy[right]= neumann(0);
pDarcy[left]=neumann(0);
pDarcy
.n[top] = neumann(0);
ug.n[bottom] = neumann(0);
ug.n[right] = dirichlet(0);
ug.n[left] = dirichlet(0); ug
Boundary conditions for granular flow, pressure must be zero at the surface. The pressure is zero in the hole |x|<=W/2, but the lithostatic gradient is given elsewhere on the bottom wall. No slip boundary conditions on the other walls.
#define test 1
#if test
[top] = dirichlet(0);
p.n[top] = neumann(0);
u.t[top] = dirichlet(0);
u.t[bottom] = dirichlet(0);
u.n[bottom] = dirichlet(0);
u.n[right] = dirichlet(0);
u.n[left] = dirichlet(0);
u
/*
p[bottom] = neumann(0);
p[right]= neumann(0);
p[left]=neumann(0);
*/
[left] = neumann(0.);
In[top] = neumann(0.);
In[bottom] = neumann(0.);
In[right] = neumann(0.);
In
[left] = neumann(0.);
phi[top] = neumann(0.);
phi[bottom] = neumann(0.);
phi[right] = neumann(0.);
phi
#else
[top] = dirichlet(0);
p.n[top] = neumann(0);
u.t[bottom] = neumann(0);
u.n[bottom] = neumann(0);
u[bottom] = dirichlet(0);
p[right]=(fabs(y)>= 0. && fabs(y)<= (LDOMAIN*position-epai)) ? dirichlet(0): neumann(0);
p[left]=(fabs(y)>= 0. && fabs(y)<= (LDOMAIN*position-epai)) ? dirichlet(0): neumann(0);
p
.n[right] = (fabs(y)>= 0. && fabs(y)<= (LDOMAIN*position-epai)) ? neumann(0): dirichlet(0);
u.t[right] = (fabs(y)>= 0. && fabs(y)<= (LDOMAIN*position-epai)) ? neumann(0): dirichlet(0);
u.n[left] = (fabs(y)>= 0. && fabs(y)<= (LDOMAIN*position-epai)) ? neumann(0): dirichlet(0);
u.t[left] = (fabs(y)>= 0. && fabs(y)<= (LDOMAIN*position-epai)) ? neumann(0): dirichlet(0);
ubid plaque;
.t[plaque] = dirichlet(0.);
u.n[plaque] = dirichlet(0.);
u
[plaque] = neumann(0.);
p
[left] = neumann(0.);
In[top] = neumann(0.);
In[bottom] = neumann(0.);
In[right] = neumann(0.);
In
[left] = neumann(0.);
phi[top] = neumann(0.);
phi[bottom] = neumann(0.);
phi[right] = neumann(0.);
phi
#endif
int main(int argc, char ** argv) {
= LDOMAIN;
L0 // number of grid points
= 1 << LEVEL;
N // maximum timestep
= 0.01;
DT // coefficient of friction of wall
= 0.1;
muwall = 1e-3;
TOLERANCE = 2.5;
H0 = 20.000;
R0 // Grain size
= 1. / 90.;
D = fopen("outWQ", "w"); // ????
fwq fclose(fwq); // ????
system("rm uprof.txt");
= LDOMAIN;
Lz // size of the hole
= 0.25;
W //Qair = 1.0;
=5.;
P1= 2.;
WDOMAIN = av;
a = alphav;
alpha = muv;
mu =0.1;
epai=1./3.;
position= 0;
Q = 2.;
tmax = fopen("interface.txt", "w");
fpf run();
fclose(fpf);
fprintf(stdout, "\n");
= fopen("outWQ", "a");
fwq fprintf(fwq, " %lf %lf \n", W, Q);
fclose(fwq);
}
#if 0
int adapt() {
#if TREE
astats s = adapt_wavelet ({f}, (double[]){5e-3}, LEVEL, MINLEVEL);
return s.nf;
#else // Cartesian
return 0;
#endif
}
#endif
initial heap, a rectangle
// note the v
event init (t = 0) {
scalar phiinit[];
foreach_vertex()
{
[] = min(H0 - y, R0 - x);
phiinit}
fractions (phiinit, f);
lithostatic pressure, with a zero pressure near the hole to help
foreach()
[] = max(H0- y,0) ;
p// the boundary conditions for the pressure need to be handled by
// the Navier--Stokes solver
foreach()
[]=0;
In
foreach()
[]=0; phi
initial for pressure darcy
foreach(){
[] = P1;
pDarcy[] = 0.;
sourceDarcy.x[]=0.;
ug.y[]=0.;
ug}
boundary ({pDarcy, sourceDarcy});
}
total density
//#define rho(f) ((f) + RHOF*(1. - (f)))
Viscosity computing D_2=D_{ij}D_{ji};
In the pure shear flow D_{11}=D_{22}=0 et D_{12}=D_{21}=(1/2)(\partial u/\partial y), so that D_2=\sqrt{D_{ij}D_{ij}} =\sqrt{ 2 D_{12}^2} = \frac{\partial u}{ \sqrt{2}\partial y}. In a pure shear flow, \partial u/\partial y= \sqrt{2} D_2. The inertial number I is D \sqrt{2} D_2/\sqrt(p) and \mu = \mu_s+ \frac{\Delta \mu}{1+I/I_0} the viscosity is \eta = \mu(I)p/(\sqrt{2}D_2}:
note that if \eta is too small an artificial small viscosity \rho D \sqrt{gD} is taken see Lagrée et al. 11 § 2.3.1.
event properties (i++) {
({alphav});
trash scalar eta[];
foreach() {
[] = mug;
etaif (p[] > 0.) {
double D2 = 0.;
foreach_dimension() {
double dxx = u.x[1,0] - u.x[-1,0];
double dxy = (u.x[0,1] - u.x[0,-1] + u.y[1,0] - u.y[-1,0])/2.;
+= sq(dxx) + sq(dxy);
D2 }
if (D2 > 0.) {
= sqrt(2.*D2)/(2.*Delta);
D2 [] = D2*D/sqrt(p[]); // this D2 is sqrt(2) D2
Indouble muI = .4 + .28*In[]/(.4 + In[]);
double etamin = sqrt(D*D*D);
[] = max((muI*p[])/D2, etamin);
eta[] = min(eta[],100);
eta}
}
}
boundary ({eta});
scalar fa[];
foreach()
[] = (4.*f[] +
fa2.*(f[-1,0] + f[1,0] + f[0,-1] + f[0,1]) +
[1,1] + f[-1,1] + f[1,-1] + f[-1,-1])/16.;
fboundary ({fa});
foreach_face() {
double fm = (fa[] + fa[-1])/2.;
.x[] = (fm*(eta[] + eta[-1])/2. + (1. - fm)*mug);
muv.x[] = 1./( fm * (1. - 0. * In[]) + RHOF*(1. - fm));
alphav}
boundary ((scalar *){muv,alphav});
}
convergence outputs
void mg_print (mgstats mg)
{
if (mg.i > 0 && mg.resa > 0.)
fprintf (stderr, "# %d %g %g %g\n", mg.i, mg.resb, mg.resa,
(log (mg.resb/mg.resa)/mg.i));
exp }
convergence stats
event logfile (i += 1) {
stats s = statsf (f);
fprintf (stderr, "%g %d %g %g %g %g\n", t, i, dt, s.sum, s.min, s.max - 1.);
mg_print (mgp);
mg_print (mgpf);
mg_print (mgu);
fflush (stderr);
}
Computation of Darcy Forchheimer pressure at each time step
event pressureDEF (i++)
{
double B_l=1.0;
double B_i=1.0;
double R_f=1.0;//4.0*1.2/2500;
scalar un[];
vector uold[];
double err=1;
Darcy Forchheimer with penalization to have a constant pressure in the gas (1-f). grains correspond to f=1.
With $R_f= {_f} (1 + C )* (f + (1-f)) $, B_l=[ \eta \beta_l (1-\phi)] f + [\frac{1}{\beta_m}](1-f) and B_i= [\eta \beta_l (1-\phi)] f,
and \beta_m \gg 1 the penalization parameter. We have to solve by projection R_f\frac{\partial \overrightarrow{u}}{\partial t}= - \overrightarrow{\nabla} p - B_l \overrightarrow{u} -B_i |\overrightarrow{u}|\overrightarrow{u} \mbox{ avec } \overrightarrow{\nabla} \cdot \overrightarrow{u} = 0
semi implicit formulation
R_f \frac{\overrightarrow{u}^{n+1} - \overrightarrow{u}^{n}} {\Delta t}= - \overrightarrow{\nabla} p^{n+1} - B_l \overrightarrow{u}^{n+1} - B_i |\overrightarrow{u}^{n}|\overrightarrow{u}^{n+1} the new velocity is \overrightarrow{u}^{n+1} = \frac{ R_f \overrightarrow{u}^{n}- \Delta t \overrightarrow{\nabla} p^{n+1}}{ R_f + \Delta t ( B_l + B_i |\overrightarrow{u}^{n}| )} with \overrightarrow{\nabla} \cdot \overrightarrow{u}^{n+1} = 0 the problem reduces to the computation of
\overrightarrow{\nabla} \cdot (\beta p^{n+1} ) = S_{darcy} with \beta = \frac{ 1}{ R_f+ \Delta t ( B_l + B_i |\overrightarrow{u}^{n}| ) }f + (\frac{\beta_m}{(R_f+ \Delta t)})(1 - f);
foreach_face(){
.x[] = ug.x[];
uold[] = norm(ug);
un.x[] =1.0/(R_f+dt*(B_l+B_i*un[]))*f[] + (betam/(R_f+dt))*(1. - f[]);
beta}
boundary ((scalar *){beta});
computation of source term \overrightarrow{u}_s = ( \frac{R_f \overrightarrow{u}^{n} }{ R_f + \Delta t ( B_l + B_i |\overrightarrow{u}^{n}| )})f+ (\frac{R_f \overrightarrow{u}^{n} }{ R_f + \Delta t })(1-f)
vector us[];
foreach_face(){
.x[]=R_f*ug.x[]/(R_f+dt*(B_l+B_i*un[]))*f[] + R_f*ug.x[]/(R_f+dt)*(1-f[]);
us}
boundary ((scalar *){us});
S_{darcy}= \overrightarrow{\nabla} \cdot \overrightarrow{u}_s/\Delta t
scalar div[];
foreach(){
[]=0.0;
divforeach_dimension()
[] +=us.x[1]-us.x[];
div[] /=dt*Delta;
div}
=div; sourceDarcy
solve \nabla \cdot (\beta \nabla p_{darcy} )= S_{darcy} with Poisson solver
= poisson (pDarcy, sourceDarcy, beta); mgpDarcy
update \overrightarrow{u}^{n+1} = \frac{ R_f \overrightarrow{u}^{n}- \Delta t \overrightarrow{\nabla} p^{n+1}}{ R_f + \Delta t ( B_l + B_i |\overrightarrow{u}^{n}| )}
foreach() {
[] = norm(ug);
unforeach_dimension(){
.x[] =(pDarcy[0,0] - pDarcy[-1,0])/Delta;
gradpDarcy.x[]= (R_f*uold.x[] - gradpDarcy.x[]*dt)/(R_f +dt*( B_i * un[]+B_l))*f[]+
ug(R_f/betam*uold.x[] -gradpDarcy.x[]*dt) / ((R_f +dt)/betam)*(1-f[]) ;
}
}
boundary ((scalar *){ug,gradpDarcy});
monitoring unsteadiness
double max=0;
foreach() {
double du = fabs(un[] -norm(ug));
if(du > max) max = du;
}
=max;
errfprintf (stderr, "%g du= %g\n", t, err);
}
event acceleration (i++)
{
double eps = 1.0;
Coupling gravity : Grad(p) added to gravity
foreach_face(y)
.y[] += - 1. - eps*(pDarcy[0,0] - pDarcy[0,-1])/Delta;
avforeach_face(x)
.x[] += - eps*(pDarcy[0,0] - pDarcy[-1,0])/Delta ;
avboundary ((scalar *){av});
}
save velocity for analytical solution
event sauf (t += 0.1) {
FILE * fp = fopen("uprof.txt","a");
fprintf (fp,"%g %g \n", t,interpolate(ug.y, 3.5, 2));
}
event interface (t = 0 ; t += 1. ; t <= tmax) {
#if dimension == 2
output_facets (f, fpf);
#endif
char s[80];
sprintf (s, "field-%g.txt", t);
FILE * fp = fopen (s, "w");
output_field ({f,p,u,uf,pf,pDarcy,gradpDarcy,In,ug}, fp, linear = true);
fclose (fp);
}
Rate of flowing materials across the hole
event debit (t = 0 ; t += 0.1 ; t <= tmax) {
static double V = 1;
= 0;
V foreach()
= V + f[]* Delta * Delta;
V if (t >= 0.) fprintf (stdout,"%lf %lf %lf\n",t,V,ugranular);
fflush (stdout);
}
Calculate velocity of flowing materials in the bulk and add it to Qair at the top to simulate the counter flow
event velocitybulk (i++) {
static double VVold, VV = 3.9,Qinst = 0;
= VV;
VVold = 0;
VV foreach()
= VV + f[]* Delta * Delta;
VV = -(VV-VVold)/dt;
Qinst = Qinst/(LDOMAIN*(1-maskr));
ugranular }
film output
#if 1
event movie (t += 0.05) {
static FILE * fp1 = popen ("ppm2mpeg > level.mpg", "w");
scalar l[];
foreach()
[] = level;
lboundary ({l});
output_ppm (l, fp1, min = 0, max = LEVEL,
= 512, box = {{0,0},{Lz,Lz}});
n
foreach()
[] = f[]*(1 + sqrt(sq(u.x[]) + sq(u.y[])));
lboundary ({l});
static FILE * fp2 = popen ("ppm2mpeg > velo.mpg", "w");
output_ppm (l, fp2, min = 0, max = 2., linear = true,
= 512, box = {{0,0},{Lz,Lz}});
n
foreach()
[] = sqrt(sq(ug.x[]) + sq(ug.y[]));
lboundary ({l});
static FILE * fp4 = popen ("ppm2mpeg > velo_f.mpg", "w");
output_ppm (l, fp4, min = 0, max = 2., linear = true,
= 512, box = {{0,0},{Lz,Lz}});
n
static FILE * fp3 = popen ("ppm2mpeg > pDarcy.mpg", "w");
foreach()
[] = pDarcy[];
lboundary ({l});
output_ppm (l, fp3, min = 0, linear = true,
= 512, box = {{0,0},{Lz,Lz}});
n }
event pictures (t==3) {
output_ppm (f, file = "f.png",
= 0, max = 2, spread = 2, n = 512, linear = true,
min box = {{0,0},{2,2}});
}
#endif
#if 0
event gfsview (i++)
{
static FILE * fp = popen ("gfsview2D -s", "w");
output_gfs (fp, t = t);
}
#endif
Run
to run
qcc -g -O2 -Wall -o forchheimer forchheimer.c -lm
./forchheimer> out
Results
set pm3d map
set palette rgbformulae 22,13,-31;
unset colorbox
set xlabel "x iso p"
splot [][:] 'field-1.txt' u 1:2:10 not
reset
set ylabel "p_darcy"
set xlabel "y"
p 'field-1.txt' u 2:10
Analytical solution of the problem, $ = 2 $
\frac{\partial u}{\partial t}= -2 - u + u^2 u(t)= \frac{2 (exp(3 t )-1)}{(1+2 exp(3 t))}
set xlabel "t"
set ylabel "u(t)"
p'uprof.txt' t'num.' ,-2*(exp(3*x)-1)/(1+2*exp(3*x)) t'analytic'