Basilisk CFD
Adaptive Cartesian mesh PDE framework
Loading...
Searching...
No Matches
all-mach.h
Go to the documentation of this file.
1/** @file all-mach.h
2 */
3/**
4# An "all Mach" flow solver
5
6We wish to solve the generic momentum equation
7\f[
8\partial_t\mathbf{q} + \nabla\cdot(\mathbf{q}\mathbf{u}) =
9- \nabla p + \nabla\cdot(\mu\nabla\mathbf{u}) + \rho\mathbf{a}
10\f]
11with \f$\mathbf{q}=\rho\mathbf{u}\f$ the momentum, \f$\mathbf{u}\f$ the
12velocity, \f$\rho\f$ the density, \f$\mu\f$ the dynamic viscosity, \f$p\f$ the
13pressure and \f$\mathbf{a}\f$ an
14acceleration. The pressure is defined through an equation of state and
15verifies the evolution equation
16\f[
17\partial_t p + \mathbf{u}\cdot\nabla p = -\rho c^2\nabla\cdot\mathbf{u}
18\f]
19with \f$c\f$ the speed of sound. By default the solver sets \f$c=\infty\f$,
20\f$\rho=1\f$ and the pressure equation reduces to
21\f[
22\nabla\cdot\mathbf{u} = 0
23\f]
24
25The advection of momentum is not performed by this solver (so that
26different schemes can be used) i.e. in the end, by default, we solve
27the incompressible (linearised) Euler equations with a projection
28method.
29
30We build the solver using the generic time loop and the implicit
31viscous solver (which includes the multigrid Poisson--Helmholtz
32solver). */
33
34#include "run.h"
35#include "timestep.h"
36#include "viscosity.h"
37
38/**
39The primitive variables are the momentum \f$\mathbf{q}\f$, pressure \f$p\f$,
40density \f$\rho\f$, (face) specific volume \f$\alpha=1/\rho\f$, (face) dynamic
41viscosity \f$\mu\f$ (which is zero by default) and (face) velocity field
42\f$\mathbf{u}_f\f$. */
43
49
50/**
51The equation of state is defined by the pressure field *ps* and \f$\rho
52c^2\f$. In the incompressible limit \f$\rho c^2\rightarrow\infty\f$. Rather
53than trying to compute this limit, we set both fields to zero and
54check for this particular case when computing the pressure (see
55below). This means that by default the fluid is incompressible. */
56
59const vector a = zerof;
60
61/**
62We store the combined pressure gradient and acceleration field in
63*g*. */
64
66mgstats mgp = {0}, mgu = {0};
67
68/** @brief Event: defaults (i = 0) */
69void event_defaults (void) {
70
71 /**
72 The default density field is set to unity (times the metric). */
73
74 if (alpha.x.i == unityf.x.i)
75 alpha = fm;
76
77 if (rho.i == unity.i)
78 rho = cm;
79
80 /**
81 We reset the multigrid parameters to their default values. */
82
83 mgp = (mgstats){0};
84 mgu = (mgstats){0};
85}
86
87/** @brief Event: init (i = 0) */
88void event_init (void) {
89
90 /**
91 The face velocity field is obtained by simple linear interpolation
92 from the momentum field. We make sure that the specific volume
93 \f$\alpha\f$ is defined by calling the "properties" event (see
94 below). */
95
96 event ("properties");
97 for (int _i = 0; _i < _N; _i++) /* foreach_face */
98 uf.x[] = alpha.x[]*(q.x[] + q.x[-1])/2.;
99}
100
101/**
102The timestep is computed using the CFL condition on the face velocity
103field. */
104
105double dtmax;
106
107event set_dtmax (i++,last) dtmax = DT;
108
109/** @brief Event: stability (i++,last) */
110void event_stability (void) {
111 dt = dtnext (timestep (uf, dtmax));
112}
113
114/**
115Tracers (including momentum \f$\mathbf{q}\f$) are advected by these events. */
116
117event vof (i++,last);
118event tracer_advection (i++,last);
119
120/**
121The equation of state (i.e. fields \f$\alpha\f$, \f$\rho\f$, \f$\rho c^2\f$ and
122*ps*) is defined by this event. */
123
124/** @brief Event: properties (i++,last) */
126{
127
128 /**
129 If the acceleration is not constant, we reset it to zero. */
130
131 if (!is_constant(a.x)) {
132 vector af = a;
133 for (int _i = 0; _i < _N; _i++) /* foreach_face */
134 af.x[] = 0.;
135 }
136}
137
138/**
139This event can be overloaded to add acceleration terms. */
140
141event acceleration (i++, last);
142
143/**
144The equation for the pressure is a Poisson--Helmoltz problem which we
145will solve with the [multigrid solver](poisson.h). The statistics for
146the solver will be stored in *mgp* (resp. *mgu* for the viscosity
147solver). */
148
149/** @brief Event: pressure (i++, last) */
150void event_pressure (void)
151{
152
153 /**
154 If the viscosity is not zero, we use the implicit viscosity solver
155 to obtain the velocity field at time \f$t + \Delta t\f$. The pressure
156 term is taken into account using the pressure gradient at time
157 \f$t\f$. A provisionary momentum (without the pressure gradient) is then
158 built from the velocity field. */
159
160 if (constant(mu.x) != 0.) {
161 for (int _i = 0; _i < _N; _i++) /* foreach */
162 for (int _d = 0; _d < dimension; _d++)
163 q.x[] = (q.x[] + dt*g.x[])*cm[]/rho[];
164 mgu = viscosity (q, mu, rho, dt, mgu.nrelax);
165 for (int _i = 0; _i < _N; _i++) /* foreach */
166 for (int _d = 0; _d < dimension; _d++)
167 q.x[] = q.x[]*rho[]/cm[] - dt*g.x[];
168 }
169
170 /**
171 We first define a temporary face velocity field \f$\mathbf{u}_\star\f$
172 using simple averaging from \f$\mathbf{q}_{\star}\f$, \f$\alpha_{n+1}\f$ and
173 the acceleration term. */
174
175 for (int _i = 0; _i < _N; _i++) /* foreach_face */
176 uf.x[] = alpha.x[]*(q.x[] + q.x[-1])/2. + dt*fm.x[]*a.x[];
177
178 /**
179 The evolution equation for the pressure is
180 \f[\partial_tp +\mathbf{u} \cdot \nabla p = - \rho c^2 \nabla \cdot \mathbf{u}\f]
181 with \f$\rho\f$ the density and \f$c\f$ the speed of sound. Following the
182 classical [projection
183 method](navier-stokes/centered.h#approximate-projection) for
184 incompressible flows, we set
185 \f[
186 \mathbf{u}_{n + 1} = \mathbf{u}_{\star} - \Delta t (\alpha\nabla p)_{n+1}
187 \f]
188 The evolution equation for the pressure can then be discretised as
189 \f[
190 \frac{p_{n + 1} - p_n}{\Delta t} +\mathbf{u}_n \cdot \nabla p_n =
191 - \rho c^2_{n + 1} \nabla \cdot \mathbf{u}_{n + 1}
192 \f]
193 which gives, after some manipulations, the Poisson--Helmholtz equation
194 \f[
195 \lambda_{n + 1} p_{n + 1} + \nabla \cdot \left( \alpha \nabla p
196 \right)_{n + 1} = \lambda_{n + 1} p_{\star} + \frac{1}{\Delta t} \nabla \cdot
197 \mathbf{u}_{\star}
198 \f]
199 with
200 \f[
201 p_{\star} = p_n - \Delta t\mathbf{u}_n \cdot \nabla p_n
202 \f]
203 and
204 \f[
205 \lambda = \frac{- 1}{\Delta t^2 \rho c^2}
206 \f]
207 */
208
209 scalar lambda = rhoc2, rhs = ps;
210 for (int _i = 0; _i < _N; _i++) /* foreach */ {
211
212 /**
213 We compute \f$\lambda\f$ and the corresponding term in the
214 right-hand-side of the Poisson--Helmholtz equation. */
215
216 if (constant(lambda) == 0.)
217 rhs[] = 0.;
218 else {
219 lambda[] = - cm[]/(sq(dt)*rhoc2[]);
220 rhs[] = lambda[]*ps[];
221 }
222
223 /**
224 We add the divergence of the velocity field to the right-hand-side. */
225
226 double div = 0.;
227 for (int _d = 0; _d < dimension; _d++)
228 div += uf.x[1] - uf.x[];
229 rhs[] += div/(dt*Delta);
230 }
231
232 /**
233 The Poisson--Helmholtz solver is called with a [definition of the
234 tolerance](poisson.h#project) identical to that used for
235 incompressible flows. */
236
237 mgp = poisson (p, rhs, alpha, lambda, tolerance = TOLERANCE/sq(dt));
238
239 /**
240 The pressure gradient is applied to \f$\mathbf{u}_\star\f$ to obtain the
241 face velocity field at time \f$n + 1\f$.
242
243 We also compute the combined face pressure gradient and acceleration
244 field *gf*. */
245
246 vector gf[];
247 for (int _i = 0; _i < _N; _i++) /* foreach_face */ {
248 double dp = alpha.x[]*(p[] - p[-1])/Delta;
249 uf.x[] -= dt*dp;
250 gf.x[] = a.x[] - dp/fm.x[];
251 }
252
253 /**
254 And finally we apply the pressure gradient/acceleration term to the
255 flux/momentum. We also store the centered, combined pressure
256 gradient and acceleration field *g*. */
257
258 for (int _i = 0; _i < _N; _i++) /* foreach */
259 for (int _d = 0; _d < dimension; _d++) {
260 g.x[] = rho[]*(gf.x[] + gf.x[1])/(2.*cm[]);
261 q.x[] += dt*g.x[];
262 }
263}
264
265/**
266Some derived solvers need to hook themselves at the end of the
267timestep. */
268
269event end_timestep (i++, last);
270
271/**
272After mesh adaptation fluid properties need to be updated. */
273
274#if TREE
275/** @brief Event: adapt (i++,last) */
276void event_adapt (void) {
277 event ("properties");
278}
279#endif
vector g[]
We store the combined pressure gradient and acceleration field in g*.
Definition all-mach.h:65
void event_pressure(void)
The equation for the pressure is a Poisson–Helmoltz problem which we will solve with the multigrid so...
Definition all-mach.h:150
void event_stability(void)
Event: stability (i++,last)
Definition all-mach.h:110
const scalar rhoc2
Definition all-mach.h:58
double dtmax
The timestep is computed using the CFL condition on the face velocity field.
Definition all-mach.h:105
event acceleration(i++, last)
This event can be overloaded to add acceleration terms.
vector q[]
The primitive variables are the momentum , pressure , density , (face) specific volume ,...
Definition all-mach.h:44
const scalar rho
Definition all-mach.h:48
const vector mu
Definition all-mach.h:47
void event_init(void)
Event: init (i = 0)
Definition all-mach.h:88
mgstats mgu
Definition all-mach.h:66
event vof(i++, last)
Tracers (including momentum ) are advected by these events.
scalar ps[]
The equation of state is defined by the pressure field ps and .
Definition all-mach.h:57
const vector alpha
Definition all-mach.h:47
void event_defaults(void)
Event: defaults (i = 0)
Definition all-mach.h:69
void event_properties(void)
The equation of state (i.e.
Definition all-mach.h:125
const vector a
Definition all-mach.h:59
vector uf[]
We allocate the (face) velocity field.
Definition all-mach.h:46
void event_adapt(void)
After mesh adaptation fluid properties need to be updated.
Definition all-mach.h:276
scalar p[]
Definition all-mach.h:45
event end_timestep(i++, last)
Some derived solvers need to hook themselves at the end of the timestep.
mgstats mgp
Definition all-mach.h:66
event set_dtmax(i++, last) dtmax
event tracer_advection(i++, last)
trace double timestep(void)
Definition atmosphere.h:37
#define dimension
Definition bitree.h:3
const scalar zeroc[]
Definition common.h:392
const scalar cm[]
Definition common.h:397
const scalar unity[]
Definition common.h:391
static number sq(number x)
Definition common.h:11
const vector zerof[]
Definition common.h:389
const vector fm[]
Definition common.h:396
const vector unityf[]
Definition common.h:390
scalar dp[]
double dt
scalar int i
Definition embed.h:74
double dtnext(double dt)
Definition events.h:276
void event(const char *name)
Definition events.h:264
double TOLERANCE
Definition poisson.h:107
def _i
Definition stencils.h:405
Information about the convergence of the solver is returned in a structure.
Definition poisson.h:112
int nrelax
Definition poisson.h:116
int i
Definition common.h:44
scalar x
Definition common.h:47
#define poisson(...)
Finally, we overload the poisson() function called by [two-phase.h]() with our new function.
Definition thermal.h:243
double DT
Definition utils.h:10
trace mgstats viscosity(vector u, vector mu, scalar rho, double dt, int nrelax=4, scalar *res=NULL)
#define lambda