sandbox/M1EMN/Exemples/svdbmult.c
Rupture de barrage Multi Couches
exemple en C simple Sans Viscosité
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>
// Emmanuel Audusse, Marie-Odile Bristeau, Benoıt Perthame, and Jacques Sainte-Marie
// A MULTILAYER SAINT-VENANT SYSTEM WITH MASS EXCHANGES FOR SHALLOW WATER FLOWS. DERIVATION AND NUMERICAL VALIDATION
//
// From NR
double **alloc_2d_double(int n1, int n2)
{
double **dd, *d;
int j;
dd = (double **) malloc(sizeof(double *) * n1);
d = (double *) malloc(sizeof(double) * n1 * n2);
dd[0] = d;
for (j = 1; j < n1; j++) {
dd[j] = dd[j - 1] + n2;
}
return dd;
}
void free_2d_double(double **dd)
{
free(dd[0]);
free(dd);
}
double*x=NULL,*h=NULL,*u=NULL,*Q=NULL,*Z=NULL,*Fp=NULL,*hn=NULL,*un=NULL,*c0=NULL;
double**h_alpha=NULL,**u_alpha=NULL,**Q_alpha=NULL,*l_alpha=NULL;
double**z_alphap12=NULL,**u_alphap12=NULL,**G_alphap12=NULL,**w_alphap12=NULL;
double t,dt,tmax,dx;
int nx,N;
Definition of the velocity, and of the discrete flux
double C(double ug,double ud,double hg,double hd,double g)
{ double c;
//Rusanov
c=fmax(fabs(ug)+sqrt(g*hg),fabs(ud)+sqrt(g*hd));
//c=fmax( c,1*dx/2/dt);
return c;
}
double FR1(double ug,double ud,double hg,double hd,double g,double c)
{ //double cR;
//Rusanov
//cR=fmax(fabs(ug)+sqrt(g*hg),fabs(ud)+sqrt(g*hd));
//c=1*dx/2/dt;
return (hg*ug+hd*ud)*0.5-c*(hd-hg)*0.5;
}
double FR2(double ug,double ud,double hg,double hd,double g,double c)
{ //double cR;
//Rusanov
// cR=fmax(fabs(ug)+sqrt(g*hg),fabs(ud)+sqrt(g*hd));
// c=1*dx/2/dt;
return (ug*ug*hg + g*hg*hg/2. + ud*ud*hd + g*hd*hd/2.)*0.5 - c*(hd*ud-hg*ug)*0.5;
}
/* ------------------------------------------------- */
int main (int argc, const char *argv[]) {
int it=0;
double**fp=NULL,*Fp=NULL,**fd=NULL,**un_alpha=NULL,**hn_alpha=NULL;
Initialisations
// parameters --------------------------------------------------------------
dt=0.05/8;
tmax=1;
dx=0.1/8;
nx=2*50*8;
N=16;
t=0;
fprintf(stderr," --------------------- \n");
fprintf(stderr," <-- | \n");
fprintf(stderr," --------------------------- \n");
fprintf(stderr," |---> \n");
fprintf(stderr," ----------------------------------------------\n");
/* ------------------------------------------------------------------------*/
x= (double*)calloc(nx+1,sizeof(double));
h= (double*)calloc(nx+1,sizeof(double));
hn=(double*)calloc(nx+1,sizeof(double));
Q= (double*)calloc(nx+1,sizeof(double));
Z= (double*)calloc(nx+1,sizeof(double));
u= (double*)calloc(nx+1,sizeof(double));
un=(double*)calloc(nx+1,sizeof(double));
Fp=(double*)calloc(nx+1,sizeof(double));
c0=(double*)calloc(nx+1,sizeof(double));
l_alpha= (double*)calloc(N+1,sizeof(double));
We consider that the flow domain is divided in the vertical direction into N layers of thickness h_\alpha with N + 1 interfaces z_{\alpha+1/2}
h_alpha=alloc_2d_double(nx+1,N+1);
u_alpha=alloc_2d_double(nx+1,N+1);
Q_alpha=alloc_2d_double(nx+1,N+1);
hn_alpha=alloc_2d_double(nx+1,N+1);
un_alpha=alloc_2d_double(nx+1,N+1);
fp=alloc_2d_double(nx+1,N+1);
fd=alloc_2d_double(nx+1,N+1);
u_alphap12=alloc_2d_double(nx+1,N+1);
w_alphap12=alloc_2d_double(nx+1,N+1);
z_alphap12=alloc_2d_double(nx+1,N+1);
G_alphap12=alloc_2d_double(nx+1,N+1);
// initialisation cond init ----------------------------
for(int i=0;i<=nx;i++)
{ x[i]=(i-nx/2)*dx;
//dambreak
Z[i]=0;
h[i]=1*( x[i]<0)+.00;
u[i]=0.00;
Q[i]=u[i]*h[i];
}
H =\Sigma_{\alpha=1}^N h_\alpha (2.6) and each layer depth h_\alpha is then deduced from the total water height by the relation h_\alpha=l_\alpha H (2.19)
for(int alpha=1;alpha<=N;alpha++)
{
l_alpha[alpha]= (1.00)/N;
for(int i=0;i<=nx;i++)
h_alpha[i][alpha]=h[i]*l_alpha[alpha];
}
We consider the average velocities u_\alpha, $= 1,…,N $
for(int alpha=0;alpha<=N;alpha++)
{
for(int i=0;i<=nx;i++)
{
u_alpha[i][alpha]=0;
w_alphap12[i][alpha]=0;
}
}
the value of the velocity at the interface z_{\alpha+1/2} is u_{\alpha+1/2} = u(x,z_{\alpha+1/2},t) eq. (2.10)
for(int alpha=0;alpha<=N;alpha++)
{
for(int i=0;i<=nx;i++)
u_alphap12[i][alpha]=0;
}
The definition of : G_{\alpha+1/2}=\partial_t z_{\alpha+1/2} + u_{\alpha+1/2} \partial_t z_{\alpha+1/2}-w(z,z_{\alpha+1/2},t) (2.13) The relation (2.13) gives the mass flux leaving/entering the layer \alpha through the interface z_{\alpha+1/2}
for(int alpha=0;alpha<=N;alpha++)
{
for(int i=0;i<=nx;i++)
G_alphap12[i][alpha]=0;
}
Time advance
while(t<tmax){ // boucle en temps
t+=dt;
it++;
Estimating a global wave velocity
for(int i=1;i<=nx;i++)
c0[i]=C(u[i-1],u[i],h[i-1],h[i],1.);
flux corresponding to mass conservation accross the full layer F_{p }= \Sigma_{\alpha=1}^N h_\alpha u_\alpha = Q
for(int i=1;i<=nx;i++)
Fp[i]=FR1(u[i-1],u[i],h[i-1],h[i],1.,c0[i]);
for(int i=1;i<nx;i++)
hn[i]=h[i]-dt*(Fp[i+1]-Fp[i])/dx; //conservation de la masse
Flux of mass f_{p\alpha} in each layer (2.11): $f_{p}= h_u_$
for(int alpha=1;alpha<=N;alpha++)
for(int i=1;i<=nx;i++)
fp[i][alpha]=FR1(u_alpha[i-1][alpha],u_alpha[i][alpha],h_alpha[i-1][alpha],h_alpha[i][alpha],1/l_alpha[alpha],c0[i]);
Flux of of momentum $f_{d}= h_u_^2 + $ eq.(2.21) has a l_\alpha in flux \partial_x(h_\alpha u_\alpha^2 + \frac{1}{l_\alpha} \frac{g h_\alpha^2}{2})
for(int alpha=1;alpha<=N;alpha++)
for(int i=1;i<=nx;i++)
fd[i][alpha]=FR2(u_alpha[i-1][alpha],u_alpha[i][alpha],h_alpha[i-1][alpha],h_alpha[i][alpha],1/l_alpha[alpha],c0[i]);
have to compute G, Using (2.18), (2.19), the expression of G_{\alpha+1/2} given by (2.16) can also be written as (2.22) \displaystyle G_{\alpha+1/2}= \Sigma_{j=1}^\alpha(\partial_x(F_{pj}) -l_j \partial_x(f_{pj}))
for(int i=0;i<nx;i++)
{
for(int alpha=1; alpha<N; alpha++)
{
double dxhjuj=0;
double slj=0;
for(int j=1;j<=alpha;j++)
{
slj=slj+l_alpha[j];
dxhjuj = dxhjuj + (fp[i+1][j]-fp[i][j])/dx;
}
G_alphap12[i][alpha]= -slj*(Fp[i+1]-Fp[i])/dx + dxhjuj ;
}
// fprintf(stderr,"%d dh/dt=%lf G %lf %lf %lf\n",i,-(Fp[i+1]-Fp[i])/dx,G_alphap12[i][0],G_alphap12[i][1],G_alphap12[i][2]);
}
G_{1/2}=0 G_{N+1/2}=0 (2.15) the equations just express that there is no loss/supply of mass through the bottom and the free surface.
for(int i=1;i<nx;i++)
G_alphap12[i][0]=0;
for(int i=1;i<nx;i++)
G_alphap12[i][N]=0;
The velocities u_{\alpha+1/2} are obtained using an upwinnding (2.23), if G_{\alpha+1/2}>=0 then u_{\alpha+1/2}= u_{\alpha}, if G_{\alpha+1/2}<0 then u_{\alpha+1/2}= u_{\alpha+1}
for(int alpha=1;alpha<N;alpha++)
{
for(int i=1;i<nx;i++)
{
if( G_alphap12[i][alpha]>=0) {
u_alphap12[i][alpha] = u_alpha[i][alpha];
}else{
u_alphap12[i][alpha] = u_alpha[i][alpha+1];
}
// u_alphap12[i][alpha]=(u_alpha[i][alpha]+u_alpha[i][alpha])/2;
}
}
Final update $q_^{n+1} $ $=q_^{n} - $ \Delta t(\partial_x (f_{d \alpha}) + u_{\alpha+1/2} G_{\alpha+1/2} - u_{\alpha-1/2} G_{\alpha-1/2})
for(int alpha=1;alpha<=N;alpha++)
{
double q;
for(int i=1;i<nx;i++)
{
hn_alpha[i][alpha]=l_alpha[alpha]*hn[i];
if(hn_alpha[i][alpha]>0.){ //conservation qunatité de mouvement
q=h_alpha[i][alpha]*u_alpha[i][alpha]
-dt*(fd[i+1][alpha]-fd[i][alpha])/dx
+dt*(u_alphap12[i][alpha]*G_alphap12[i][alpha]-u_alphap12[i][alpha-1]*G_alphap12[i][alpha-1]);
un_alpha[i][alpha]=q/hn_alpha[i][alpha];}
else{
un_alpha[i][alpha]=0.;}
}
}
Simple Neumann BC
for(int alpha=0;alpha<=N;alpha++)
{
// flux nul en entree sortie
hn_alpha[0][alpha]=hn_alpha[1][alpha];
un_alpha[0][alpha]=un_alpha[1][alpha];
hn_alpha[nx][alpha]=hn_alpha[nx-1][alpha];
un_alpha[nx][alpha]=un_alpha[nx-1][alpha];
}
hn[0]=hn[1];
hn[nx]=hn[nx-1];
//final swap
for(int i=0;i<=nx;i++)
{
h[i]=hn[i];
Q[i]=0;
for(int alpha=1;alpha<=N;alpha++)
{
h_alpha[i][alpha]=hn_alpha[i][alpha];
u_alpha[i][alpha]=un_alpha[i][alpha];
Q[i]=Q[i]+hn_alpha[i][alpha]*un_alpha[i][alpha];
}
if(hn[i]>0.){ un[i]=Q[i]/hn[i];} else {un[i]=0;}
u[i]=un[i];
z_{\alpha+1/2} = z_b + \Sigma_{j=1}^\alpha h_j (2.7)
z_alphap12[i][0] = Z[i];
for(int alpha=1;alpha<=N;alpha++){
for(int j=1;j<=alpha;j++)
{
z_alphap12[i][j]=z_alphap12[i][j-1]+h_alpha[i][j];
}
}
}
Results
if(it%10==0){
/* Saving the fields */
FILE *g= fopen("solxhQt.OUT", "w");
for (int i=0; i<=nx;i++)
{ fprintf(g,"%lf %lf %lf %lf %lf %lf \n",x[i],h[i],Q[i],t,h_alpha[i][1],h_alpha[i][2]);}
fprintf(g,"\n");
fclose(g);
}
printf("t=%lf\n",t);
printf("set xlabel \"x\" ; set title \"t=%lf \"\n",t);
double y1=-.1,y2=1.25;
printf("set label \"*\" at 0,.296296296296296 \n");
printf("h(x)=(((x-0)<-t)+((x-0)>-t)*(2./3*(1-(x-0)/(2*t)))**2)*(((x-0)<2*t)) \n");
printf("p[%lf:%lf][%lf:%lf] h(x) t'h exact','-' u 1:2 t'Q' w l,'-' t'h' w lp,'-' t'h_1' w lp,'-' t'Z' w l linec -1\n ",
-nx*dx/2,nx*dx/2,y1,y2);
for (int i=0; i<=nx;i++)
{
printf("%lf %lf \n",x[i],Q[i]);}
printf("e \n");
for (int i=0; i<=nx;i++)
{
printf("%lf %lf \n",x[i],h[i]+Z[i]);}
printf("e \n");
for (int i=0; i<=nx;i++)
{
printf("%lf %lf \n",x[i],h_alpha[i][1]+Z[i]);}
printf("e \n");
for (int i=0; i<=nx;i++)
{
printf("%lf %lf \n",x[i],Z[i]);}
printf("e \n");
//getchar();
}
free(x);
free(fp);
free(fd);
free(un);
free(hn);
free_2d_double(h_alpha);
return 0;
}
Run
Programme en C simple fichier (en cours on a regardé un fichier plus compliqué). Cas de rupture de barrage flux Rusanov (essayer HLC) compilation on le compile et on crée l’exécutable db
cc -O3 -ffast-math -std=c99 -lm svdbmult.c -o svdbmult
pour lancer le programme:
./svdbmult | gnuplot
Results
un fichier appelé solxhQt.OUT avec x h Q et est créé, pour le tracer, on lance gnuplot:
In this case there is no viscosity, so no coupling, each layer behaves as it is alone, we recover the exact Ritter solution of dam break.
set ylabel "h"; set xlabel "x";
set label "+" at 0,.296296296296296
h(x,t)=(((x-0)<-t)+((x-0)>-t)*(2./3*(1-(x-0)/(2*t)))**2)*(((x-0)<2*t))
p 'solxhQt.OUT' u 1:2 w p, h(x,1)
Links
- damb.c the same with only one layer
Bibliography
- Emmanuel Audusse, Marie-Odile Bristeau, Benoıt Perthame, and Jacques Sainte-Marie A multilayer saint-venant system with mass exchanges for shallow water flows. derivation and numerical validation ESAIM: M2AN 45 (2011) 169–200 DOI: 10.1051/m2an/2010036
PYL version 1, Manchester, fev 2016