/** [Return to my homepage](http://basilisk.fr/sandbox/nlemoine/README) # Diffusive wave approximation to the Shallow Water Equations ## General formulation The diffusive wave approximation stems from the Saint-Venant Shallow Water Equations, which can be written in full form as: $$ \displaystyle\frac{\partial}{\partial t} \left[\begin{array}{c} h \\ h\,u_x \\ h\,u_y \end{array}\right] = -\boldsymbol{\nabla}\cdot \left[\begin{array}{cc} h\,u_x & h\,u_y \\ h\,u_x^2+ \frac{1}{2} g h^2 & h\,u_x\,u_y \\ h\,u_x\,u_y & h\,u_y^2 + \frac{1}{2} g h^2\end{array}\right] \ -\ g\,h\left[\begin{array}{c} 0 \\ \partial_x z_b \\ \partial_y z_b \end{array}\right] \ -\ \frac{1}{\rho}\left[\begin{array}{c} 0 \\ \tau_x \\ \tau_y \end{array}\right]$$ The first line is the continuity equation, while the second and third are the projections of the dynamic (momentum) equation. The diffusive wave approximation is a zero-inertia approximation, obtained by neglecting the inertial acceleration terms in the left-hand side and the convective acceleration terms in the right-hand side: $$\displaystyle\left[\begin{array}{c} \frac{\partial h}{\partial t} \\ \cancel{\frac{\partial(h\,u_x)}{\partial t}} \\ \cancel{\frac{\partial(h\,u_y)}{\partial t}} \end{array}\right] = -\boldsymbol{\nabla}\cdot \left[\begin{array}{cc} h\,u_x & h\,u_y \\ \frac{1}{2} g h^2 & 0 \\ 0 & \frac{1}{2} g h^2\end{array}\right] -\quad\cancel{ \boldsymbol{\nabla}\cdot \left[\begin{array}{cc} 0 & 0 \\ h\,u_x^2 & h\,u_x\,u_y \\ h\,u_x\,u_y & h\,u_y^2 \end{array}\right] } \ -\ g\,h\left[\begin{array}{c} 0 \\ \partial_x z_b \\ \partial_y z_b \end{array}\right] \ -\ \frac{1}{\rho}\left[\begin{array}{c} 0 \\ \tau_x \\ \tau_y \end{array}\right]$$ Denoting $q_x = h\,u_x$ and $q_y = h\,u_y$ the components of the flux density vector, the system boils down to: $$\begin{cases} \frac{\partial h}{\partial t} = -\boldsymbol{\nabla}\cdot\mathbf{q} & \\ 0 = -g h \frac{\partial h}{\partial x} -g h \frac{\partial z_b}{\partial x} - \frac{1}{\rho}\tau_x & \\ 0 = -g h \frac{\partial h}{\partial y} -g h \frac{\partial z_b}{\partial y} - \frac{1}{\rho}\tau_y & \\ \end{cases} $$ The dynamic equation (last two scalar equations) is limited to a quasi-equilibrium between friction and the resultant force of the pressure gradient. Indeed, denoting $\eta = z_b + h$ the water surface elevation, we have: $$\begin{cases} \frac{\partial h}{\partial t} = -\boldsymbol{\nabla}\cdot\mathbf{q} & \\ 0 = -g h \frac{\partial \eta}{\partial x} -\frac{1}{\rho}\tau_x & \\ 0 = -g h \frac{\partial \eta}{\partial y} - \frac{1}{\rho}\tau_y & \\ \end{cases} $$ In the following we chose the Manning friction model, but any other model can be chosen. We then have $\quad\boldsymbol{\tau} = \rho\,g\,n^2\,h^{-\frac{7}{3}}\|\mathbf{q}\|\mathbf{q}\quad$ and then: $$\begin{cases} q_x = -\displaystyle\frac{1}{n^2\|\mathbf{q}\|}h^{\frac{10}{3}}\frac{\partial\eta}{\partial x} & \\ & \\ q_y = -\displaystyle\frac{1}{n^2\|\mathbf{q}\|}h^{\frac{10}{3}}\frac{\partial\eta}{\partial y} & \\ \end{cases} $$ Hence $$\|\mathbf{q}\| = \displaystyle\frac{1}{n^2\|\mathbf{q}\|}h^{\frac{10}{3}}\|\boldsymbol{\nabla}\eta\|$$ We see that we now have an explicit expression for the norm of the flux density vector, and hence for the vector itself: $$\|\mathbf{q}\| = \displaystyle\frac{1}{n}h^{\frac{5}{3}}\|\boldsymbol{\nabla}\eta\|^{\frac{1}{2}}$$ $$\mathbf{q} = \displaystyle-\frac{1}{n}\big(\eta-z_b\big)^{\frac{5}{3}}\|\boldsymbol{\nabla}\eta\|^{-\frac{1}{2}}\boldsymbol{\nabla}\eta$$ Finally we are left with a single equation (the continuity equation) which can be written in the form of a diffusion equation: $$\frac{\partial\eta}{\partial t} = +\boldsymbol{\nabla}\cdot\left( \underbrace{\frac{1}{n}\big(\eta-z_b\big)^{\frac{5}{3}}\|\boldsymbol{\nabla}\eta\|^{-\frac{1}{2}}}_{ \normalsize D\left(\eta,\|\boldsymbol{\nabla}\eta\|\right) }\boldsymbol{\nabla}\eta \right)$$ The problem is nonlinear since the diffusivity $D$ depends both on $\eta$ and on the norm of the gradient of $\eta$. However it can be easily implemented in Basilisk thanks to the [Poisson solver](basilisk.fr/src/diffusion.h), using an implicit scheme with a [staggered grid](http://basilisk.fr/Basilisk%20C#face-and-vertex-fields) diffusivity: ![Centered, face and vertex staggering. The diffusivity field uses the second type.](http://basilisk.fr/src/figures/staggering.svg) It is necessary to desingularize the norm of the gradient of $\eta$, which has exponent $-\frac{1}{2}$ in the diffusivity. We use: $$ D\left(\eta,\|\boldsymbol{\nabla}\eta\|\right) = \frac{1}{n}\big(\eta-z_b\big)^{\frac{5}{3}}\Big(\|\boldsymbol{\nabla}\eta\|+\epsilon\Big)^{-\frac{1}{2}} $$ ## Formulation with detrended topography Just like for the full Saint-Venant system, solving the diffusive wave equation using a [detrended topography](../manning-tilt.h) requires some rewriting of the problem. Denoting $\mathbf{I}_\mathrm{reg} = (I_x,I_y)^T$ the regional ``tilt'' driving the flow, we have: $$\begin{cases} \boldsymbol{\nabla}\eta = \boldsymbol{\nabla}\eta' - \mathbf{I}_\mathrm{reg} & \\ & \\ h = (\eta-z_b) = (\eta'-z_b') & \\ \end{cases} $$ Hence: $$\frac{\partial\eta'}{\partial t} = +\boldsymbol{\nabla}\cdot\left(\underbrace{\frac{1}{n}\big(\eta'-z_b'\big)^{\frac{5}{3}}\|\boldsymbol{\nabla}\eta'-\mathbf{I}_\mathrm{reg}\|^{-\frac{1}{2}}}_{\normalsize D\left(\eta',\|\boldsymbol{\nabla}\eta'\|\right)}\left({\boldsymbol{\nabla}\eta'-\mathbf{I}_\mathrm{reg}}\right)\right)=\boldsymbol{\nabla}\cdot\big(D\boldsymbol{\nabla}\eta'\big) - \mathbf{I}_\mathrm{reg}\cdot\boldsymbol{\nabla}D$$ We see that we can keep using the Poisson solver to compute the evolution of the new variable $\eta'$ (detrended water surface elevation) with the detrended topography $z_b'$ as input, provided that we add a ficticious source term given by $-\mathbf{I}_\mathrm{reg}\cdot\boldsymbol{\nabla}D$. The desingularization of the norm of the gradient is of course still required: $$D\left(\eta',\|\boldsymbol{\nabla}\eta'\|\right) = \frac{1}{n}\big(\eta'-z'_b\big)^{\frac{5}{3}}\Big(\|\boldsymbol{\nabla}\eta'-\mathbf{I}_\mathrm{reg}\|+\epsilon\Big)^{-\frac{1}{2}}$$ and we set $\epsilon = 0.001\ \|\mathbf{I}_\mathrm{reg}\|$. ## Issues with mass conservation One of the specificities of the diffusive wave formulation is that we keep setting the water surface elevation $\eta$ equal to the topographic elevation $z_b$ even where the surface is dry. It is therefore possible that, over a given time step, the value of $\eta$ changes from $\eta=z_b$ to $\eta0)}$ (which has value 1 if $\Delta\eta^{(i)}>0$ on the cell at the previous iteration, and 0 otherwise): $$r=-\left[(1-\alpha)\underbrace{\frac{\Delta\eta^{(i)}}{\Delta t}}_{\textrm{explicit}}\ +\ \alpha\,\underbrace{\mathbb{1}_{(\Delta\eta^{(i)}>0)}\left(\frac{z_b-\eta^{(i+1)}}{\Delta t}\right)}_{\textrm{implicit}}\right]$$ $$r=-\left[(1-\alpha)\frac{\Delta\eta^{(i)}}{\Delta t}+\alpha\,\mathbb{1}_{(\Delta\eta^{(i)}>0)}\frac{z_b}{\Delta t}\right]\quad + \quad \left[\alpha\,\mathbb{1}_{(\Delta\eta^{(i)}>0)}\frac{1}{\Delta t}\right]\eta^{(i+1)}$$ It yields a reaction term with an affine form, directly handled by the Poisson solver in Basilisk: $$r = r_0 + \beta\ \eta^{(i+1)}$$ This correction is stable for $\alpha<1$ (a more thorough study of this property would be necessary). It is worth noting that the situation $\eta0. ? a/Dt : 0.; r[] = -tilt.x * (D.x[1,0]-D.x[])/Delta - tilt.y * (D.y[0,1]-D.y[])/Delta - (1.-a)*excess[]/Dt; r[] += (excess[]>0.) ? -a*zb[]/Dt : 0.; } boundary({r}); return(0); } FILE * fpcontrol; int main (int argc, char * argv[]) { size (2048.); origin (-424.,-2332.); init_grid (1 << LEVEL); // Get .kdt file system("wget https://dropsu.sorbonne-universite.fr/s/sT5GkqPqzsaMYab/download"); system("mv download garonne_local.kdt"); // Get .pts file system("wget https://dropsu.sorbonne-universite.fr/s/5TWiFJaAXGKcb6L/download"); system("mv download garonne_local.pts"); // Get .sum file system("wget https://dropsu.sorbonne-universite.fr/s/sz5qF6fc7MwkPzz/download"); system("mv download garonne_local.sum"); G = 9.81; tilt.x = 0.; tilt.y = 1.103e-3; facExplicit = 10.; run(); if(pid()==0.) fclose(fpcontrol); } event initialize (i=0) { terrain(zb,"garonne_local", NULL); scalar zmin = zb.dmin; output_ppm (zb, min = 3.6, max = 14.6, file = "topo.png", n = 512, linear = true); foreach() { eta[] = fmax(zb[],stage_hydrograph(0.)); h[] = eta[]-zb[]; double zzmin = zmin[]= zb eta[] = fmax(eta[],zb[]); } boundary({zb,eta,excess}); } // Adaptivity int adapt() { #if TREE scalar etamask[], slope[]; foreach() { h[] = eta[]-zb[] > dry ? eta[]-zb[] : 0.; etamask[] = h[] > dry ? eta[] : 0.; slope[] = h[] > dry ? sqrt( sq(eta[1,0]-eta[-1,0]-2.*tilt.x*Delta) + sq(eta[0,1]-eta[0,-1]-2.*tilt.y*Delta) )/2./Delta : 0.; } boundary ({h,etamask,slope}); astats s = adapt_wavelet ({h,etamask,slope}, (double[]){HE,ETAE,SE}, LEVEL, MINLEVEL); boundary({h}); scalar zmin = zb.dmin; foreach(){ double zzmin = zmin[]dry); // If 3x3 neighborhood is water-free according to newly adapted h[], just ignore adapted eta[], set it to newly adapted zb[]. // It will disable sink term. eta[] = wet_stencil ? eta[] : zb[]; } boundary(all); // fprintf (ferr, "# refined %d cells, coarsened %d cells\n", s.nf, s.nc); return s.nf; #else // Cartesian return 0; #endif } event snapshot (t+=300. ; t<=86400.) { scalar m[], etam[]; foreach() { m[] = eta[]*(h[] > dry) - zb[]; etam[] = h[] < dry ? 0. : (zb[] > 0. ? eta[] - zb[] : eta[]); } output_ppm (h, mask = m, min = 0, max = 10, n = 2048, linear = true, file = "h.mp4"); } event info_conservation (t+=30. ; t<=86400.) { coord Section[2]; Section[0] = (coord) { 0. , Y0+L0-L0/N }; Section[1] = (coord) { 600. , Y0+L0-L0/N }; // "Measure" mean elevation at top (outlet) section double etam = segment_eta (Section,h,eta); // "Measure" discharge at top (outlet) section by looping on faces double Q = 0.; foreach_boundary(top) Q += abs(x-300.)<300 ? Delta * D.y[] * ((eta[0,-1]-eta[])/Delta + tilt.y) : 0.; // Total water volume in domain double Vol = 0.; foreach() Vol += h[] * Delta * Delta ; if(pid()==0){ fprintf(fpcontrol,"%g %g %g %g\n",t/3600.,Q,etam,Vol); fflush(fpcontrol); } } /** ## Results ![Simulated water depth (flow direction is from bottom to top). Left: full Saint-Venant solution; Right: diffusive wave approximation.](hstack/h_full_diffwave.mp4)(width=80% ) ~~~gnuplot Comparison with full Saint-Venant: domain volume reset set xlabel "t (h)" set ylabel "Total volume in domain (m3)" ydim = 800 xdim = 480 plot '../fullsaintvenant/outlet_info.txt' u 1:4 w lines lc rgb "black" lw 3 title 'full Saint-Venant', \ 'outlet_info.txt' u 1:4 w lines lc rgb "black" lw 1 title 'diffusive wave' ~~~ ~~~gnuplot Comparison with full Saint-Venant: outflow discharge reset set xlabel "t (h)" set ylabel "Outflow discharge (m3/s)" ydim = 800 xdim = 480 plot '../fullsaintvenant/outlet_info.txt' u 1:2 w lines lc rgb "black" lw 3 title 'full Saint-Venant', \ 'outlet_info.txt' u 1:2 w lines lc rgb "black" lw 1 title 'diffusive wave' ~~~ ![outlet_info.txt](diffwave/outlet_info.txt) */