Basilisk CFD
Adaptive Cartesian mesh PDE framework
Loading...
Searching...
No Matches
thermal.h
Go to the documentation of this file.
1/** @file thermal.h
2 */
3/**
4# Thermal effects extension for the compressible two-phase solver
5
6This extension of the [two-phase compressible solver](two-phase.h) is
7described in detail in [Saade et al, 2023](#saade2023).
8
9This solves the two-phase compressible Navier-Stokes equations
10including the total energy equation.
11\f[
12\frac{\partial (f \rho_i)}{\partial t } +
13\nabla \cdot (f \rho_i \mathbf{u}) = 0
14\f]
15\f[
16\frac{\partial (\rho_i \mathbf{u})}{\partial t } +
17\nabla \cdot ( \rho_i \mathbf{u} \mathbf{u}) =
18-\nabla p + \nabla \cdot \tau_i'
19\f]
20\f[
21\frac{\partial [\rho_i (e_i + \mathbf{u}^2/2)]}{\partial t }
22+ \nabla \cdot [ \rho_i \mathbf{u} (e_i + \mathbf{u}^2/2)] =
23-\nabla \cdot (\mathbf{u} p_i) +
24\nabla \cdot \left( \tau'_i \mathbf{u} \right)
25{\color{blue} - \nabla \cdot \mathbf{q}_i}
26\f]
27an advection equation for the volume fraction \f$f\f$
28\f[
29\frac{\partial f}{\partial t} + \mathbf{u} \cdot \nabla f = 0
30\f]
31
32The term in blue in the energy equation is the heat flux which is
33added by this extension. The other terms are treated by the [two-phase
34compressible solver](two-phase.h). The heat flux is given by Fourier's
35relation as
36\f[
37\nabla \cdot \mathbf{q}_i = - \kappa_i \nabla T_i
38\f]
39where \f$\kappa_i\f$ is the thermal conductivity and \f$T\f$ is the
40temperature field.
41
42The temperature and pressure fields are then coupled through the two
43equations (8 and 10 in [Saade et al, 2023](#saade2023))
44\f[
45\rho_ic_{p,i}\frac{DT_i}{Dt} = \beta_iT_i\frac{Dp_i}{Dt} - \nabla\cdot\mathbf{q}_i
46\f]
47with \f$c_p\f$ the specific heat capacity and \f$\beta\f$ the thermal expansion coefficient.
48\f[
49\left(\frac{\gamma_i}{\rho_ic_i^2} - \frac{\beta_i^2T_i}{\rho_ic_{p,i}}\right)\frac{Dp_i}{Dt} =
50-\frac{\beta_i}{\rho_ic_{p,i}}\nabla\cdot\mathbf{q}_i - \nabla\cdot\mathbf{u}_i
51\f]
52with \f$\gamma\f$ the ratio of specific heats.
53
54The system is closed by specifying an Equation Of State (EOS) relating
55\f$p\f$, \f$\rho\f$ and \f$T\f$.
56
57In addition to the primary variables of the compressible two-phase
58solver we have the temperature field... */
59
61
62/**
63... and the thermal conductivities and specific heat capacities. */
64
65double kappa1 = 0., kappa2 = 0.;
66double cp1 = 0., cp2 = 0.;
67
68/**
69These functions are provided by the Equation Of State. See for example
70[the Noble-Able Stiffened-Gas Equation Of State](NASG.h). */
71
72extern double average_temperature (Point point, double p);
73extern double thermal_expansion (Point point);
74
75/**
76## Phase-averaged thermal conductivity
77
78By default the arithmetic average of the two phase conductivities is
79used to compute the face-centered thermal conductivity. */
80
81const vector kappa0[] = {0,0,0};
83
84#ifndef kappa
85#define kappa(f) (clamp(f,0.,1.)*(kappa1 - kappa2) + kappa2)
86#endif
87
88/**
89If the thermal conductivities are not-zero, we need to allocate a new
90field. */
91
92/** @brief Event: defaults (i = 0) */
93void event_defaults (void)
94{
95 if (kappa1 || kappa2)
96 kappa = {0} /* new vector */;
97}
98
99/**
100## Coupled Poisson-Helmholtz equations for temperature and pressure
101
102The robustness of the solver relies on solving equations (8) and (10)
103in a strongly-coupled manner with the multigrid solver. After temporal
104discretisation this leads to the following coupled Poisson--Helmholtz
105system for the temperature \f$T^{n+1}\f$ and pressure \f$p^{n+1}\f$ (see
106eqs. 25 and 26 in [Saade et al, 2023](#saade2023))
107\f[
108\nabla\cdot\left(\kappa\nabla T^{n+1}\right) + \lambda_1 T^{n+1} + \lambda_2 p^{n+1} = \lambda_T
109\f]
110\f[
111\nabla\cdot\left(\alpha\nabla p^{n+1}\right) + \lambda p^{n+1} +
112\lambda_4\nabla\cdot\left(\kappa\nabla T^{n+1}\right) = \lambda_p
113\f]
114We allocate fields to store the provisionary temperature \f$T^n\f$ and the
115coefficients. */
116
118
119/**
120We then define the corresponding relaxation and residual functions
121which will be used by the [multigrid
122solver](/src/poisson.h#mg_solve). */
123
124#include "poisson.h"
125
133
134static void relax_thermal (scalar * al, scalar * bl, int l, void * data)
135{
136 scalar T = al[0], p = al[1], rhsT = bl[0], rhsp = bl[1];
137 struct Thermal * tp = (struct Thermal *) data;
138 const vector alpha = tp->alpha;
139 const scalar lambda = tp->lambda;
140
141#if JACOBI
142 scalar cT[], cp[];
143#else
144 scalar cT = T, cp = p;
145#endif
146
147 for (int _i = 0; _i < l; _i++) {
148 double numT = sq(Delta)*(lambda2[]*p[] - rhsT[]), denT = - lambda1[]*sq(Delta);
149 double nump = - sq(Delta)*rhsp[], denp = - lambda[]*sq(Delta);
150 for (int _d = 0; _d < dimension; _d++) {
151 numT += kappa.x[1]*T[1] + kappa.x[]*T[-1];
152 denT += kappa.x[1] + kappa.x[];
153 nump += alpha.x[1]*p[1] + alpha.x[]*p[-1];
154 nump += lambda4[]*(kappa.x[1]*(T[1] - T[]) - kappa.x[]*(T[] - T[-1]));
155 denp += alpha.x[1] + alpha.x[];
156 }
157 cT[] = numT/denT;
158 cp[] = nump/denp;
159 }
160
161#if JACOBI
162 for (int _i = 0; _i < l; _i++) {
163 T[] = (T[] + 2.*cT[])/3.;
164 p[] = (p[] + 2.*cp[])/3.;
165 }
166#endif
167}
168
169static double residual_thermal (scalar * al, scalar * bl, scalar * resl, void * data)
170{
171 scalar T = al[0], p = al[1], rhsT = bl[0], rhsp = bl[1], resT = resl[0], resp = resl[1];
172 struct Thermal * tp = (struct Thermal *) data;
173 const vector alpha = tp->alpha;
174 const scalar lambda = tp->lambda;
175 double maxres = 0.;
176#if TREE
177 /* conservative coarse/fine discretisation (2nd order) */
178 vector gradT[], gradp[];
179 for (int _i = 0; _i < _N; _i++) /* foreach_face */ {
180 gradT.x[] = kappa.x[]*face_gradient_x (T, 0);
181 gradp.x[] = alpha.x[]*face_gradient_x (p, 0);
182 }
183 foreach (reduction(max:maxres)) {
184 resT[] = rhsT[] - lambda1[]*T[] - lambda2[]*p[];
185 resp[] = rhsp[] - lambda[]*p[];
186 for (int _d = 0; _d < dimension; _d++) {
187 resT[] -= (gradT.x[1] - gradT.x[])/Delta;
188 resp[] -= (gradp.x[1] - gradp.x[])/Delta;
189 resp[] -= lambda4[]*(gradT.x[1] - gradT.x[])/Delta;
190 }
191#else // !TREE
192 /* "naive" discretisation (only 1st order on trees) */
193 foreach (reduction(max:maxres)) {
194 resT[] = rhsT[] - lambda1[]*T[] - lambda2[]*p[];
195 resp[] = rhsp[] - lambda[]*p[];
196 for (int _d = 0; _d < dimension; _d++) {
197 resT[] += (kappa.x[0]*face_gradient_x (T, 0) -
198 kappa.x[1]*face_gradient_x (T, 1))/Delta;
199 resp[] += (alpha.x[0]*face_gradient_x (p, 0) -
200 alpha.x[1]*face_gradient_x (p, 1))/Delta;
201 resp[] += lambda4[]*(kappa.x[0]*face_gradient_x (T, 0) -
202 kappa.x[1]*face_gradient_x (T, 1))/Delta;
203 }
204#endif // !TREE
205 double maxr = max(fabs(resT[]), fabs(resp[]));
206 if (maxr > maxres)
207 maxres = maxr;
208 }
209 return maxres;
210}
211
212/**
213This is the interface for the coupled solver. */
214
216 const vector alpha,
217 const scalar lambda,
218 double tolerance = 0.,
219 int nrelax = 4,
220 int minlevel = 0,
221 scalar * res = NULL)
222{
223 double defaultol = TOLERANCE;
224 if (tolerance)
226
228
229 struct Thermal tp = { alpha, lambda, tolerance, nrelax, minlevel, res };
231 &tp, nrelax, res, minlevel = max(1, minlevel));
232
233 if (tolerance)
235
236 return s;
237}
238
239/**
240Finally, we overload the *poisson()* function called by [two-phase.h]() with
241our new function. */
242
243#define poisson(...) poisson_thermal(__VA_ARGS__)
245#undef poisson
246
247/**
248## Computation of the provisional temperature and Poisson--Helmholtz parameters
249
250This is done before the projection, which will call the coupled Poisson--Helmholtz
251solver. */
252
253/** @brief Event: acceleration (i++) */
255{
256 for (int _i = 0; _i < _N; _i++) /* foreach */ {
258
259 /**
260 We compute \f$\lambda_1\f$, \f$\lambda_2\f$, \f$\lambda_4\f$ and r.h.s. for
261 the temperature which will be used by the coupled
262 Poisson--Helmholtz solver. The \f$\lambda\f$ parameter and r.h.s. for
263 the pressure are computed by the [two-phase compressible
264 solver](two-phase.h#properties). */
265
266 double rhocp = cp1*frho1[] + cp2*frho2[];
267 lambda1[] = - cm[]*rhocp/dt;
268 double beta = thermal_expansion (point);
269 lambda2[] = cm[]*beta*Ts[]/dt;
270 lambda4[] = beta/rhocp/dt;
271 scalar rhsT = Ts;
272 rhsT[] = lambda1[]*Ts[] + lambda2[]*ps[];
273 }
274
275 /**
276 We also compute the face-averaged thermal conductivity. */
277
278 if (kappa1 || kappa2)
279 for (int _i = 0; _i < _N; _i++) /* foreach_face */ {
280 double ff = (f[] + f[-1])/2.;
281 kappa.x[] = fm.x[]*kappa(ff);
282 }
283}
284
285/**
286## Heat flux contribution to the total energy
287
288This adds the \f$-\nabla\cdot\mathbf{q}_i\f$ term of the energy
289equation. */
290
291/** @brief Event: end_timestep (i++) */
293{
294 if (kappa1 || kappa2) {
296 for (int _i = 0; _i < _N; _i++) /* foreach_face */
297 gradTv.x[] = kappa.x[]*face_gradient_x (T,0);
298
299 for (int _i = 0; _i < _N; _i++) /* foreach */ {
300 double energy = 0.;
301 for (int _d = 0; _d < dimension; _d++)
302 energy += gradTv.x[1] - gradTv.x[];
303 energy *= dt/(Delta*cm[]);
304 double fc = clamp(f[],0,1);
305 fE1[] += energy*fc;
306 fE2[] += energy*(1. - fc);
307 }
308 }
309}
310
311/**
312## References
313
314~~~bib
315@hal{saade2023, hal-03950917}
316~~~
317*/
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
#define dimension
Definition bitree.h:3
define l
int x
Definition common.h:76
#define face_gradient_x(a, i)
Definition common.h:403
const scalar cm[]
Definition common.h:397
static number sq(number x)
Definition common.h:11
static number clamp(number x, number a, number b)
Definition common.h:15
const vector fm[]
Definition common.h:396
scalar frho2[]
Definition two-phase.h:57
scalar frho1[]
Definition two-phase.h:57
scalar f[]
The primary fields are:
Definition two-phase.h:56
scalar fE2[]
Definition two-phase.h:57
scalar fE1[]
Definition two-phase.h:57
#define p
Definition tree.h:320
Point point
Definition conserving.h:86
double dt
scalar s
Definition embed-tree.h:56
vector beta[]
Definition hele-shaw.h:40
#define data(k, l)
Definition linear.h:26
size_t max
Definition mtrace.h:8
void(* restriction)(Point, scalar)
trace mgstats mg_solve(scalar *a, scalar *b, double(*residual)(scalar *a, scalar *b, scalar *res, void *data), void(*relax)(scalar *da, scalar *res, int depth, void *data), void *data=NULL, int nrelax=4, scalar *res=NULL, int minlevel=0, double tolerance=TOLERANCE)
The user needs to provide a function which computes the residual field (and returns its maximum) as w...
Definition poisson.h:130
double TOLERANCE
Definition poisson.h:107
double energy(double *PE=NULL, double *KE=NULL)
Definition rpe.h:234
def _i
Definition stencils.h:405
Definition linear.h:21
We then define the corresponding relaxation and residual functions which will be used by the multigri...
Definition thermal.h:126
const vector alpha
Definition thermal.h:127
int minlevel
Definition thermal.h:130
int nrelax
Definition thermal.h:130
const scalar lambda
Definition thermal.h:128
double tolerance
Definition thermal.h:129
scalar * res
Definition thermal.h:131
Information about the convergence of the solver is returned in a structure.
Definition poisson.h:112
scalar x
Definition common.h:47
void event_acceleration(void)
Event: acceleration (i++)
Definition thermal.h:254
scalar lambda1[]
Definition thermal.h:117
double kappa2
Definition thermal.h:65
scalar Ts[]
Definition thermal.h:117
void event_end_timestep(void)
Event: end_timestep (i++)
Definition thermal.h:292
double kappa1
... and the thermal conductivities and specific heat capacities.
Definition thermal.h:65
#define kappa(f)
Definition thermal.h:85
double cp2
Definition thermal.h:66
double thermal_expansion(Point point)
Definition NASG.h:111
scalar lambda4[]
Definition thermal.h:117
double average_temperature(Point point, double p)
These functions are provided by the Equation Of State.
Definition NASG.h:99
static double residual_thermal(scalar *al, scalar *bl, scalar *resl, void *data)
Definition thermal.h:169
static void relax_thermal(scalar *al, scalar *bl, int l, void *data)
Definition thermal.h:134
void event_defaults(void)
If the thermal conductivities are not-zero, we need to allocate a new field.
Definition thermal.h:93
scalar T[]
Definition thermal.h:60
const vector kappa0[]
Definition thermal.h:81
double cp1
Definition thermal.h:66
mgstats poisson_thermal(scalar p, scalar rhs, const vector alpha, const scalar lambda, double tolerance=0., int nrelax=4, int minlevel=0, scalar *res=NULL)
This is the interface for the coupled solver.
Definition thermal.h:215
scalar lambda2[]
Definition thermal.h:117
double tp
Definition utils.h:21
#define lambda