sandbox/Antoonvh/cooling2D2.c
Thermal inertia
Outputs include:
Visualization showing the evolution of 1) the temperature field (top left), 2) the radially averaged temperature profile (top right), 3) The vorticity field (bottom left) and 4) the grid cell distribution (bottom right)
set size square
set ylabel 'Temp [^oC]'
set xlabel 'time [s]'
set grid
plot 'out' w l lw 2 t 'Cylinder centre',\
'' u 1:3 w l lw 2 t 'Air'
Setup
The Navier-Stokes equations are solved with a tracer field that is subject to diffusion. For the flow field around the cylinder, we use embedded boundaries. Meaning that the cylinder’ surface cuts the cells.
#include "embed.h"
#include "navier-stokes/centered.h"
#include "diffusion.h"
#include "tracer.h"
#include "view.h"
The system is defined by a Gaussian-in-time inflow (i.e. the jet).
#define U_in (U_jet*exp(-sq((t - t_jet)/tau_jet)) + U_base)
#define T_in (T_jet*exp(-sq((t - t_jet)/tau_jet)))
A bunch of physical parameters are set.
double T_jet = 5., U_jet = 1, t_jet = 20, tau_jet = 10;
double tend = 100, U_base = 0.1;
double R = 0.005;
double muv = 1.7e-5;
double lambda_a = 0.026, lambda_b = 0.6;
double rho_Cp_a = 1.*1006., rho_Cp_b = 1000.*4200.;
Including numerical parameters for the maximum grid refinement level, and the refinement criteria.
int maxlevel = 7;
double Te = 0.05, ue = 0.05;
Now we let the solver(s) know about our setup and parameters. The
temperature field T
is declared and we tell the solver we
wish to advect it with the flow. Further, the variable viscosity field
(which is defined on faces) is declared.
scalar T[], * tracers = {T};
face vector muf[];
.n[embed] = dirichlet (0.);
u.t[embed] = dirichlet (0.);
u
.n[left] = dirichlet (U_in);
u.t[left] = dirichlet (0.);
u[left] = neumann (0.);
p[left] = dirichlet (T_in);
T
[right] = dirichlet (0.);
p.n[right] = neumann (0.);
u
int main() {
= 25*R;
L0 = -L0/3.5;
X0 = -L0/2.;
Y0 = muf;
mu = 128;
N run();
}
During initialization we overload the tracer attributes because it is now also defined inside the embedded boundary.
event init (t = 0) {
for (scalar s in tracers) {
.refine = s.prolongation = refine_bilinear;
s.coarsen = s.restriction = restriction_average;
s}
// Embed a cylinder using a distance field
refine (sqrt(sq(x) + sq(y)) < 2*R && level < maxlevel);
vertex scalar phi[];
foreach_vertex()
[] = sqrt(sq(x) + sq(y));
phifractions (phi, cs, fs, R);
//Initialize `u.x` and `T`
foreach() {
.x[] = U_in * (cs[] > 0);
u[] = T_in;
T}
boundary ({T, u.x});
}
The momentum does not diffuse into the solid.
event properties (i++) {
foreach_face()
.x[] = muv*fm.x[];
mufboundary ((scalar*){muf});
}
Temperature diffusion
The temperature diffuses over the entire field. We set a field for \rho C_p and \lambda, which are weighted averages of the properties of the corresponding material fractions.
event tracer_diffusion(i++) {
face vector kappaf[];
scalar Cp[];
foreach_face()
.x[] = fs.x[]*lambda_a + lambda_b*(1. - fs.x[]);
kappafforeach()
[] = cs[]*rho_Cp_a + rho_Cp_b*(1. - cs[]);
Cpboundary ({Cp, kappaf});
(T, dt, kappaf, theta = Cp);
diffusion }
We automatically focus the cells near the (evolving) boundary layer, and wake.
event adapt (i++) {
= U_in/5.;
ue ({cs, T, u}, (double[]){1e-3, Te, ue, ue, ue},
adapt_wavelet , maxlevel - 3);
maxlevelunrefine (x > X0 + 4*L0/5); //Graceful outflow
}
event stop (t = tend);
Outputs and movie
Movies displaying the temperature field (T.mp4
, using
output_ppm), the vorticity field and cells (vor.mp4
, using
bview), and temperature profile (mov.mp4
, via gnuplot and
ffmpeg
) are generated. They are merged at the end of the
simulation with ffmpeg
.
But first, we generate a simple data file tracking the core temperature.
event track (t += 0.1)
printf ("%g %g %g\n", t, interpolate (T, 0, 0), T_in);
FILE * gp, * fpm, * fpv;
event init (t = 0) {
= popen ("gnuplot", "w");
gp = popen("ppm2mp4 T.mp4", "w");
fpm = popen("ppm2mp4 vor.mp4", "w");
fpv fprintf(gp,
"set term pngcairo size 400, 400\n"
"set xr [%g: %g]\n"
"set yr [%g : %g]\n"
"set grid\n"
"set size square\n"
"set xlabel 'Distance'\n"
"set key off\n"
"set ylabel 'T [K]'\n",
-R, 2.5*R,
-1. , T_jet + 1);
}
#undef EMBED //Do not use interpolate_embed
#include "profile6.h"
#define EMBED 1
int frame = 0;
event mov (t += 0.1) {
output_ppm (T, fpm, n = 400, max = T_jet, min = 0.,
= true);
linear
view (width = 800, height = 400, fov = 19, tx = -1.5/7.);
translate (x = -L0/2) {
draw_vof ("cs", "fs", filled = -1, fc = {0.5, 0.5, 0.5});
scalar omg[];
vorticity (u, omg);
squares ("omg", map = cool_warm);
}
translate (x = L0/2) {
cells();
}
save (fp = fpv);
fprintf (gp,
"set output 'plot%d.png'\n"
"set title 't = %d sec\n"
"plot '-' w l lw 3\n"
"%g %g\n", frame, (int)t,
-R, interpolate (T, 0, 0));
double Tr, rp = -R*0.8;
vertex scalar phi[];
foreach_vertex()
[] = sqrt(sq(x) + sq(y)) - R; //Distance function
phiscalar css[];
face vector fss[];
while (rp < 3*R) {
fractions (phi, css, fss, rp);
double dy = interface_average ({T}, &Tr, css, fss);
fprintf (gp,"%g %g\n", rp, Tr);
+= dy;
rp }
fprintf (gp,"e\n");
++;
frame}
event movie_maker (t = end) {
pclose (gp);
pclose (fpm);
pclose (fpv);
system ("rm mov.mp4");
system ("ffmpeg -f image2 -i plot%d.png -c:v libx264 -vf format=yuv420p -y mov.mp4");
system ("rm plot*");
system ("ffmpeg -y -i T.mp4 -i mov.mp4 -filter_complex hstack output.mp4");
system ("ffmpeg -y -i output.mp4 -i vor.mp4 -filter_complex vstack output2.mp4");
return 1;
}