Basilisk CFD
Adaptive Cartesian mesh PDE framework
Loading...
Searching...
No Matches
multilayer.h
Go to the documentation of this file.
1/** @file multilayer.h
2 */
3/**
4# Multilayer Saint-Venant system with mass exchanges
5
6<div class="message">
7Note that the [multilayer solver](layered/hydro.h) provides the same
8functionality and should be prefered for most applications.</div>
9
10The [Saint-Venant system](saint-venant.h) is extended to multiple
11layers following [Audusse et al, 2011](references.bib#audusse2011) as
12\f[
13\partial_th + \partial_x\sum_{l=0}^{nl-1}h_lu_l = 0
14\f]
15with
16\f[
17h_l = \mathrm{layer}_lh
18\f]
19with \f$\mathrm{layer}_l\f$ the relative thickness of the layers satisfying
20\f[
21\mathrm{layer}_l >= 0,\;\sum_{l=0}^{nl - 1}\mathrm{layer}_l = 1.
22\f]
23The momentum equation in each layer is thus
24\f[
25\partial_t(h\mathbf{u}_l) + \nabla\cdot\left(h\mathbf{u}_l\otimes\mathbf{u}_l +
26\frac{gh^2}{2}\mathbf{I}\right) =
27- gh\nabla z_b + \frac{1}{\mathrm{layer}_l}\left[\mathbf{u}_{l+1/2}G_{l+1/2} -
28\mathbf{u}_{l-1/2}G_{l-1/2}
29+ \nu\left(\frac{u_{l+1} - u_l}{h_{l+1/2}} -
30\frac{u_{l} - u_{l-1}}{h_{l-1/2}}\right)\right]
31\f]
32where \f$G_{l+1/2}\f$ is the relative vertical transport velocity between
33layers and the second term corresponds to viscous friction between
34layers.
35
36These last two terms are the only difference with the [one layer
37system](saint-venant.h).
38
39The horizontal velocity in each layer is stored in *ul* and the
40vertical velocity between layers in *wl*. */
41
44double * layer;
45
46/**
47The index of the layer is set as a field attribute. */
48
50 int l;
51}
52
53/**
54## Viscous friction between layers
55
56Boundary conditions on the top and bottom layers need to be added to close the
57system for the viscous stresses. We chose to impose a Neumann condition on the
58top boundary i.e.
59\f[
60\partial_z u |_t = \dot{u}_t
61\f]
62and a Navier slip condition on the bottom i.e.
63\f[
64u|_b = u_b + \lambda_b \partial_z u|_b
65\f]
66By default the viscosity is zero and we impose free-slip on the top
67boundary and no-slip on the bottom boundary i.e. \f$\dot{u}_t = 0\f$,
68\f$\lambda_b = 0\f$, \f$u_b = 0\f$. */
69
70double nu = 0.;
71const scalar lambda0[] = 0, dut0[] = 0, u_b0[] = 0;
73// fixme: should be able to replace the two lines above with:
74// const scalar lambda_b[] = 0, dut[] = 0, u_b[] = 0;
75
76/**
77For stability, we discretise the viscous friction term implicitly as
78\f[
79\frac{(hu_l)_{n + 1} - (hu_l)_{\star}}{\Delta t} =
80\frac{\nu}{\mathrm{layer}_l} \left( \frac{u_{l + 1} - u_l}{h_{l + 1 / 2}} -
81\frac{u_l - u_{l - 1}}{h_{l - 1 / 2}} \right)_{n + 1}
82\f]
83which can be expressed as the linear system
84\f[
85\mathbf{Mu}_{n + 1} = \mathrm{rhs}
86\f]
87where \f$\mathbf{M}\f$ is a
88[tridiagonal matrix](https://en.wikipedia.org/wiki/Tridiagonal_matrix).
89The lower, principal and upper diagonals are *a*, *b* and *c* respectively. */
90
91void vertical_viscosity (Point point, double h, vector * ul, double dt)
92{
93 if (nu) {
94 double a[nl], b[nl], c[nl], rhs[nl];
95 for (int _d = 0; _d < dimension; _d++) {
96
97 /**
98 The *rhs* of the tridiagonal system is \f$h_lu_l = h\mathrm{layer}_lu_l\f$. */
99
100 int l = 0;
101 for (int _u = 0; _u < 1; _u++) /* vector in ul */
102 rhs[l] = h*layer[l]*u.x[], l++;
103
104 /**
105 The lower, principal and upper diagonals \f$a\f$, \f$b\f$ and \f$c\f$ are given by
106 \f[
107 a_{l > 0} = - \left( \frac{\nu \Delta t}{h_{l - 1 / 2}} \right)_{n + 1}
108 \f]
109 \f[
110 c_{l < \mathrm{nl} - 1} = - \left( \frac{\nu \Delta t}{h_{l + 1 / 2}}
111 \right)_{n + 1}
112 \f]
113 \f[
114 b_{0 < l < \mathrm{nl} - 1} = \mathrm{layer}_l h_{n + 1} - a_l - c_l
115 \f]
116 */
117
118 for (l = 1; l < nl - 1; l++) {
119 a[l] = - 2.*nu*dt/(h*(layer[l-1] + layer[l]));
120 c[l] = - 2.*nu*dt/(h*(layer[l] + layer[l+1]));
121 b[l] = layer[l]*h - a[l] - c[l];
122 }
123
124 /**
125 For the top layer the boundary conditions give the (ghost)
126 boundary value
127 \f[
128 u_{\mathrm{nl}} = u_{\mathrm{nl} - 1} + \dot{u}_t h_{\mathrm{nl} - 1},
129 \f]
130 which gives the diagonal coefficient and right-hand-side
131 \f[
132 b_{\mathrm{nl} - 1} = \mathrm{layer}_{\mathrm{nl} - 1} h_{n + 1}
133 - a_{\mathrm{nl} - 1}
134 \f]
135 \f[
136 \mathrm{rhs}_{\mathrm{nl} - 1} = \mathrm{layer}_{\mathrm{nl} - 1}
137 (hu_{\mathrm{nl} - 1})_{\star} + \nu \Delta t \dot{u}_t
138 \f]
139 */
140
141 a[nl-1] = - 2.*nu*dt/(h*(layer[max(0,nl-2)] + layer[nl-1]));
142 b[nl-1] = layer[nl-1]*h - a[nl-1];
143 rhs[nl-1] += nu*dt*dut[];
144
145 /**
146 For the bottom layer, the boundary conditions give the (ghost)
147 boundary value \f$u_{- 1}\f$
148 \f[
149 u_{- 1} = \frac{2 h_0}{2 \lambda_b + h_0} u_b + \frac{2 \lambda_b - h_0}{2
150 \lambda_b + h_0} u_0,
151 \f]
152 which gives the diagonal coefficient and right-hand-side
153 \f[
154 b_0 = \mathrm{layer}_0 h_{n + 1} - c_0 +
155 \frac{2 \nu \Delta t}{2 \lambda_b + h_0}
156 \f]
157 \f[
158 \mathrm{rhs}_0 = \mathrm{layer}_0 (hu_0)_{\star} + \frac{2 \nu \Delta t}{2
159 \lambda_b + h_0} u_b
160 \f]
161 */
162
163 c[0] = - 2.*dt*nu/(h*(layer[0] + layer[min(1,nl-1)]));
164 b[0] = layer[0]*h - c[0] + 2.*nu*dt/(2.*lambda_b[] + h*layer[0]);
165 rhs[0] += 2.*nu*dt/(2.*lambda_b[] + h*layer[0])*u_b[];
166
167 /**
168 We can now solve the tridiagonal system using the [Thomas
169 algorithm](https://en.wikipedia.org/wiki/Tridiagonal_matrix_algorithm). */
170
171 for (l = 1; l < nl; l++) {
172 b[l] -= a[l]*c[l-1]/b[l-1];
173 rhs[l] -= a[l]*rhs[l-1]/b[l-1];
174 }
175 vector u = ul[nl-1];
176 u.x[] = a[nl-1] = rhs[nl-1]/b[nl-1];
177 for (l = nl - 2; l >= 0; l--) {
178 u = ul[l];
179 u.x[] = a[l] = (rhs[l] - c[l]*a[l+1])/b[l];
180 }
181 }
182 }
183}
184
185/**
186## Fluxes between layers
187
188The relative vertical velocity between layers \f$l\f$ and \f$l+1\f$ is defined
189as (eq. (2.22) of [Audusse et al, 2011](references.bib#audusse2011))
190\f[
191G_{l+1/2} = \sum_{j=0}^{l}(\mathrm{div}_j + \mathrm{layer}_j\mathrm{dh})
192\f]
193with
194\f[
195\mathrm{div}_l = \nabla\cdot(h_l\mathbf{u}_l)
196\f]
197\f[
198\mathrm{dh} = - \sum_{l=0}^{nl-1} \mathrm{div}_l
199\f]
200*/
201
203 scalar * divl, scalar dh)
204{
205 for (int _i = 0; _i < _N; _i++) /* foreach */ {
206 double Gi = 0., sumjl = 0.;
207 for (int l = 0; l < nl - 1; l++) {
208 scalar div = divl[l];
209 Gi += div[] + layer[l]*dh[];
210 sumjl += layer[l];
211 scalar w = div;
212 w[] = dh[]*sumjl - Gi;
213 for (int _d = 0; _d < dimension; _d++) {
214
215 /**
216 To compute the vertical advection term, we need an estimate of
217 the velocity at \f$l+1/2\f$. This is obtained using simple
218 upwinding according to the sign of the interface velocity
219 \f$\mathrm{Gi} = G_{l+1/2}\f$ and the values of the velocity in
220 the \f$l\f$ and \f$l+1\f$ layers. Note that the inequality of
221 upwinding is consistent with equs. (5.110) of [Audusse et al,
222 2011](references.bib#audusse2011) and (77) of [Audusse et al,
223 2011b](references.bib#audusse2011b) but not with eq. (2.23) of
224 [Audusse et al, 2011](references.bib#audusse2011). */
225
226 scalar ub = evolving[l].x, ut = evolving[l + 1].x;
227 double ui = Gi < 0. ? ub[] : ut[];
228
229 /**
230 The flux at \f$l+1/2\f$ is then added to the updates of the bottom
231 layer and substracted from the updates of the top layer. */
232
233 double flux = Gi*ui;
234 scalar du_b = updates[l].x, du_t = updates[l + 1].x;
235 du_b[] += flux/layer[l];
236 du_t[] -= flux/layer[l + 1];
237
238 /**
239 To compute the vertical velocity we use the definition of the
240 mass flux term (eq. 2.13 of [Audusse et
241 al, 2011](references.bib#audusse2011)):
242 \f[
243 \mathrm{w}(\mathbf{x},z_{l+1/2}) =
244 \partial_t z_{l+1/2} - G_{l+1/2} + \mathbf{u}_{l+1/2}
245 \cdot \nabla z_{l+1/2}
246 \f]
247 We can write the vertical position of the interface as:
248 \f[
249 z_{l+1/2} = z_{b} + \sum_{j=0}^{l} h_{j}
250 \f]
251 so that the vertical velocity is:
252 \f[
253 \mathrm{w}(\mathbf{x},z_{l+1/2}) =
254 \mathrm{dh}\sum_{j=0}^{l}\mathrm{layer}_{j} - G_{l+1/2} +
255 \mathbf{u}_{l+1/2} \cdot \left[\nabla z_{b} + \nabla h
256 \sum_{j=0}^{l}\mathrm{layer}_{j}\right]
257 \f]
258 */
259
260 w[] += ui*((zb[1] - zb[-1]) + (h[1] - h[-1])*sumjl)/(2.*Delta);
261 }
262 }
263 }
264}
#define u
Definition advection.h:30
const vector a
Definition all-mach.h:59
scalar zb[]
Definition atmosphere.h:6
scalar h[]
Definition atmosphere.h:6
int min
Definition balance.h:192
#define dimension
Definition bitree.h:3
define l
int x
Definition common.h:76
vector w[]
scalar * evolving
The generic time-integration scheme in predictor-corrector.h needs to know which fields are updated i...
Point point
Definition conserving.h:86
double dt
double dh
Definition heights.h:331
int nl
Definition layers.h:9
size_t max
Definition mtrace.h:8
size *double * b
double * layer
Definition multilayer.h:44
const scalar lambda_b
Definition multilayer.h:72
void vertical_fluxes(vector *evolving, vector *updates, scalar *divl, scalar dh)
Definition multilayer.h:202
const scalar dut0[]
Definition multilayer.h:71
const scalar u_b0[]
Definition multilayer.h:71
scalar * wl
Definition multilayer.h:43
const scalar lambda0[]
Definition multilayer.h:71
attribute
The index of the layer is set as a field attribute.
Definition multilayer.h:49
void vertical_viscosity(Point point, double h, vector *ul, double dt)
For stability, we discretise the viscous friction term implicitly as.
Definition multilayer.h:91
double nu
Definition multilayer.h:70
const scalar u_b
Definition multilayer.h:72
vector * ul
Definition multilayer.h:42
const scalar dut
Definition multilayer.h:72
def _i
Definition stencils.h:405
Definition linear.h:21
scalar x
Definition common.h:47
scalar flux[]
Definition vof.h:166
scalar c
Definition vof.h:57