sandbox/Antoonvh/tree/fractaltree.c
Flow past a fractal tree
See also this page, for the generation of the last section of the movie.
#include "grid/octree.h"
#include "embed.h"
#include "navier-stokes/centered.h"
#include "navier-stokes/double-projection.h"
#include "navier-stokes/perfs.h"
#include "treegen.h"
#include "view.h"
#include "lambda2.h"
double U = 1, Re = 1000., c = 10., ue, nu;
int maxlevel = 11;
int minlevel = 5;
double FILLVAL = 1e5;
scalar J[], res[];
.n[left] = dirichlet (U);
u.n[left] = U;
uf.t[left] = dirichlet (0.);
u[left] = dirichlet (0.);
p[left] = dirichlet (0.);
pf
.n[right] = neumann (0.);
u[right] = neumann (0.);
p[right] = neumann (0.);
pf
.n[embed] = dirichlet (0.);
u.t[embed] = dirichlet (0.);
u#if (dimension == 3)
.r[embed] = dirichlet (0.);
u.r[left] = dirichlet (0);
u#endif
void prolongate_ratio (Point point, scalar s) {
foreach_child() {
if (s[] != FILLVAL)
[] += s[]*Delta;
s}
}
FILE * fp;
face vector muc[];
int main() {
= U*stem_rad/Re;
nu #if (dimension == 3)
periodic (back);
#endif
= 100;
L0 = -L0/3.;
X0 = -L0/2.;
Z0 = muc;
mu char logname[99];
= U/c;
ue sprintf (logname, "log3rd%g3D%d-%g",Re, maxlevel, c);
= fopen (logname, "w");
fp = 128;
N run();
}
Branch * trees;
event init (t = 0) {
= 1;
levels (0); //Reproducible and identical among threads
srand = tree_skeleton();
trees .prolongation = prolongate_ratio;
resdo {
tree_interface (trees, cs, fs, J);
boundary ({J});
fractions_cleanup (cs, fs);
foreach() {
[] = FILLVAL;
resif (cs[] > 0 && cs[] < 1) {
[] = U/sqrt(trees[(int)(J[] + 0.5)].R*nu);
res}
}
boundary ({res});
} while (adapt_wavelet ({res}, (double[]){2.}, maxlevel, minlevel).nf > grid->tn/1000);
tree_interface (trees, cs, fs, J);
fractions_cleanup (cs, fs);
dump();
view (height = 1080, width = 1080, fov = 9, ty = -0.2);
draw_vof ("cs", "fs", color = "J");
cells();
save ("tree.ppm");
foreach() {
.x[] = cs[] > 0;
u.y[] = noise()*U/200.;
u#if (dimension == 3)
.z[] = noise()*U/200.;
u#endif
}
}
event properties (i++) {
foreach_face()
.x[] = fm.x[]*nu;
mucboundary ((scalar*){muc});
}
event damp (i++) {
= {U, 0, 0};
coord Uinf double Lay = L0/10;
double tau = 0.5;
foreach() {
if (x - X0 < Lay || (X0 + L0) - x < Lay) {
foreach_dimension()
.x[] += dt*(Uinf.x - u.x[])/tau;
u}
}
boundary ((scalar*){u});
}
event adapt (i++) {
foreach() {
[] = FILLVAL;
resif (cs[] > 0 && cs[] < 1) {
[] = U/sqrt(trees[(int)(J[] + 0.5)].R*nu);
res}
}
boundary ({res});
((scalar*){res, u},
adapt_wavelet (double[]){2., ue, ue, ue}, maxlevel, minlevel);
}
double embed_interpolate2 (Point point, scalar s, coord p) {
int i = sign(p.x), j = sign(p.y);
#if dimension == 2
if (cs[i] && cs[0,j] && cs[i,j])
// bilinear interpolation when all neighbors are defined
return ((s[]*(1. - fabs(p.x)) + s[i]*fabs(p.x))*(1. - fabs(p.y)) +
(s[0,j]*(1. - fabs(p.x)) + s[i,j]*fabs(p.x))*fabs(p.y));
#else //dimension == 3, see cartesian-common.h
int k = sign(p.z);
= fabs(p.x); y = fabs(p.y); z = fabs(p.z);
x /* trilinear interpolation */
if (cs[i] && cs[0,j] && cs[i,j] && cs[0,0,k] &&
[i,0,k] && cs[0,j,k] && cs[i,j,k]) {
csreturn (((s[]*(1. - x) + s[i]*x)*(1. - y) +
(s[0,j]*(1. - x) + s[i,j]*x)*y)*(1. - z) +
((s[0,0,k]*(1. - x) + s[i,0,k]*x)*(1. - y) +
(s[0,j,k]*(1. - x) + s[i,j,k]*x)*y)*z);
}
#endif
else {
// linear interpolation with gradients biased toward the
// cells which are defined
double val = s[];
foreach_dimension() {
int i = sign(p.x);
if (cs[i])
+= fabs(p.x)*(s[i] - s[]);
val else if (cs[-i])
+= fabs(p.x)*(s[] - s[-i]);
val }
return val;
}
}
event logger (i += 5) {
#if (dimension == 2)
, Fmu;
coord Fpembed_force (p, u, mu, &Fp, &Fmu);
fprintf (fp, "%d %g %g %g %g %g %ld\n",
, t, Fp.x, Fp.y, Fmu.x, Fmu.y, grid->n);
i#elif (dimension == 3)
double Fpx = 0., Fpy = 0, Fpz = 0;
foreach (reduction(+:Fpx) reduction(+:Fpy) reduction(+:Fpz))
if (cs[] > 0. && cs[] < 1.) {
, b;
coord ndouble area = embed_geometry (point, &b, &n);
*= pow (Delta, dimension - 1);
area double Fn = area*embed_interpolate2 (point, p, b);
+= Fn*n.x;
Fpx += Fn*n.y;
Fpy += Fn*n.z;
Fpz }
if (pid() == 0) {
fprintf (fp, "%d %g %g %g %g %ld\n",
, t, Fpx, Fpy, Fpz, grid->n);
ifflush (fp);
printf ( "%d %g %g %g %ld %d %d %d\n",
, t, Fpx, Fpy, grid->n, mgpf.i, mgp.i, mgu.i);
i}
#endif
}
event movies (t += 0.2) {
scalar l2[];
lambda2 (u, l2);
view (fov = 12, theta = -0.8, phi = 0.4,
= 0, ty = -0.15, bg = {65./256,157./256,217./256},
tx = 1080, height = 1080);
width isosurface ("l2", -0.1);
if (t < 50 || t > 100)
cells();
draw_vof ("cs", "fs", fc = {98./256,78./256,44./256});
char str[99];
sprintf (str, "Re = %g, C = %g, ML= %d", Re, c, maxlevel);
draw_string (str, 1, lw = 3, lc = {1, 0, 1});
double py = 20;
translate (y = -py)
squares ("u.x", n = {0,1,0}, alpha = py,
= -1.1, max = 1.1, map = cool_warm);
min save ("movtree.mp4");
}
event dumper (t += 10) {
.nodump = false;
pchar str[99];
sprintf (str, "dump3D%g", t);
dump(str);
}
event stop (t = 150) {
fclose (fp);
free (trees);
}