/** [Return to my homepage](http://basilisk.fr/sandbox/nlemoine/README) # MacDonald test problem #3 -- stationary, periodic subcritical flow (MacDonald *et al.*, 1997) ## Flow equation For a 1D stationary flow, the continuity equation in the Saint-Venant system boils down to $q = q_x = \textrm{cst} = q_0$ and the momentum equation becomes: $$0\quad =\quad -\partial_x\left[\frac{q^2}{h} + \frac{1}{2}g h^2\right]- gh\ \partial_x z_b-\frac{\tau}{\rho}$$ In the Manning-Strickler model, bed shear stress is given by: $$\boldsymbol{\tau}\quad=\quad\rho\,g\,n^2 h^{-\frac{1}{3}}\left|\mathbf{u} \right|\mathbf{u}\quad=\quad\rho\,g\,n^2 h^{-\frac{7}{3}}\left|\mathbf{q} \right|\mathbf{q}$$ so that $$0\quad =\quad +\frac{q_0^2}{h^2}\partial_x h- gh\ \partial_x h - gh\ \partial_x z_b - n^2 g\, h^{-\frac{7}{3}}q_0^2$$ Hence $$\partial_x z_b\quad=\quad \underbrace{\left[\frac{q_0^2}{g h^3}-1\right]}_{\textrm{Fr}^2-1}\partial_x h\quad-\quad n^2 q_0^2\,h^{-\frac{10}{3}}$$ The rationale behind [MacDonald's test case](https://doi.org/10.1061/(ASCE)0733-9429(1997)123:11(1041)) is that of an inverse problem: we determine the bed elevation profile corresponding to a desired water depth profile $h(x)$ and uniform flow rate $q_0$, i.e., the right-hand side of the latter equation is fully known. The method can be straightforwardly extended to the case of a variable Manning coefficient $n(x)$. For a periodic geometry, the integration of $\partial_x z_b$ can be easily performed using Fourier transform. Indeed, the Fourier spectrum of the detrended topography $z_b^\ast$ is a function of wavenumber $k$ (in $\textrm{rad}\cdot\textrm{m}^{-1}$) which satisfies: $$\mathcal{F}[z_b^\ast](k) = \begin{cases} \displaystyle\frac{1}{ik}\mathcal{F}[\partial_x z_b](k) & \textrm{for }k\neq 0 \\ 0 & \textrm{for }k=0\textrm{ (zero-mean elevation)} \end{cases}$$ The inverse transform yields $z_b^\ast(x)$. The average slope $I=I_x$, hence the linear trend which must be added to $z_b^\ast$, is simply the spatial mean of $\partial_x z_b$ over the length $\lambda$ of a pattern: $$I\quad=\quad -\frac{1}{\lambda}\int_\lambda (\partial_x z_b) dx\quad \propto \quad\mathcal{F}[\partial_x z_b](k=0)$$ We use the [detrended bathymetry](manning-tilt.h) $z_b^\ast(x)$ as an input to Basilisk and we set $\ \texttt{tilt.x} = I$, together with a periodic boundary condition on all fields. ## Implementation This test case makes use of Fourier transforms with the [FFTW](https://www.fftw.org/) library. */ #include #include #pragma autolink -lfftw3 #include "grid/multigrid1D.h" #include "saint-venant.h" #include "nlemoine/SWE/manning-tilt.h" #define LEVEL 7 #define tfin 900. #define sec_per_day 86400. #define M_PI acos(-1.0) #define Lpattern 1000. #define npatterns 3 #define q0 2.0 #define hmean (9./8.) #define hrange (1./4.) #define nharmo 10 // nharmo < N/(2*npatterns) /** ### Functions returning analytical depth and Manning coefficient for any given position */ double get_analytical_depth(double x, int derivative) { double wavenum = 2.0*M_PI/Lpattern; double res; if(!derivative) res = hmean + hrange*sin(wavenum*x); else res = wavenum*hrange*cos(wavenum*x); return res; } double get_manning(double x) { // return 0.03-0.01*sin(2.0*M_PI*x/Lpattern); return 0.03; } double AMPLITUDE[nharmo], PHASESHIFT[nharmo]; int init_harmo_zb () { fftw_complex *in, *out; fftw_plan p; in = (fftw_complex*) fftw_malloc(sizeof(fftw_complex) * N); out = (fftw_complex*) fftw_malloc(sizeof(fftw_complex) * N); double xm,hm,nm,dh_dx,Sf,Fr2,dzb_dx; /* initialize input array */ for(int m=0;m1) printf("error : analytical solution is locally supercritical (Fr>1)\n"); dzb_dx = (Fr2-1.)*dh_dx - Sf ; in[m][0] = dzb_dx; in[m][1] = 0.; } /* compute forward Fourier transform of dzb_dx */ p = fftw_plan_dft_1d(N, in, out, FFTW_FORWARD, FFTW_ESTIMATE); fftw_execute(p); fftw_destroy_plan(p); /* retrieve average slope (real part of 1st element out[0] */ tilt.x = (-1./N)*out[0][0]; printf("tilt.x = %g\n",tilt.x); in[0][0] = 0.; in[0][1] = 0.; /* integrate in Fourier space */ double k0 = (2.*M_PI/L0); for(int m=1;m0. ? cimag(clog(zz)) : 0.; } /* clean-up */ fftw_free(in); fftw_free(out); return(0); } /** Now we can define the function returning bed elevation for any position */ double get_zb(double x) { double res = 0., kpattern = 2.*M_PI/Lpattern; for(int m=1;m