sandbox/Antoonvh/tree/colonizedtree.c
Potential flow past a digitally-generated tree,
on a digitally-generated surface:
Do not mind the blue sky

#include "grid/octree.h"
#include "embed.h"
#include "poisson.h"
#include "run.h"
#include "colonization.h"
#include "../ABL/perlin.h"
#include "../tracer-particles.h"
#include "view.h"
#include "../scatter2.h"
scalar pot[], laplace[];
Particles P;
[front] = dirichlet (1);
pot[back] = dirichlet (0);
pot[embed] = neumann (0.);
potvector u[];
.n[front] = neumann(0);
u.n[back] = neumann(0);
uint ja = 1000; double R1 = 3, H = 1.5, Hg = 1;
double sy = 1.4;
int main () {
= 10;
L0 = Z0 = -L0/2;
X0 = 64;
N run();
}
Initialization
In the initialization stage we first find the tree nodes via the
space colonization algorithm and convert those to Branches. Next, the
tree interface can be reconstructed in terms of tree-cell-volume
fractions. A periodic Perlin topography is added before an equation for
the flow potential (pot
) is solved. This is then converted
into the velocity field. Finally this field is visualized with tracer
particles.
face vector fp[];
scalar cp[];
event init (t = 0) {
//Seed atraction points in a prolate semi spheriod
(0);
srand [ja];
coord atrint j = 0;
while (j < ja) {
double R = R1*pow(fabs(noise()), 1./3.1);
= {noise(), noise(), noise()};
coord vec (&vec);
normalize if (vec.y > 0) {
foreach_dimension()
[j].x = R*vec.x;
atr[j].y *= sy;
atr[j].y += H + Hg;
atr++;
j}
}
//Get tree nodes
int tn = 1;
Tnode * nodes = calloc (tn, sizeof(Tnode));
[0].x = 0;
nodes[0].y = Hg;
nodes[0].z = 0;
nodes= colonize (atr, ja, &nodes, 1, 2, 0.2, 0.3);
tn
// Convert nodes to branches
Branch * trees = calloc (499, sizeof(Branch)); //?
printf ("# nodes: %d\n", tn);
= nodestotree (nodes, tn, &trees);
nb printf ("# branches: %d\n", nb);
fflush (stdout);
//Convert branches to volume fractions
int it = 0;
do {
tree_interface (trees, cs, fs);
boundary({cs});
printf ("# Tree Reconstruction Iteration %d\n", ++it);
} while (adapt_wavelet ({cs}, (double[]){0.1}, 9, 4).nf > (grid->tn/100));
tree_interface (trees, cs, fs);
boundary({cs, fs});
fractions_cleanup (cs, fs);
//Obtain surface volume and face fractions
.prolongation = cs.prolongation;
cpvertex scalar phi[];
int nx = 5;
int ny = 3;
init_perlin (nx, ny);
= 0;
it do {
foreach_vertex()
[] = y - Hg - (perlin (x, z, nx, ny));
phiboundary ({phi});
fractions (phi, cp, fp);
boundary ({cp});
printf ("# Surface Reconstruction Iteration %d\n", ++it);
} while (adapt_wavelet ({cs, cp}, (double[]){0.1, 0.01}, 8, 4).nf > (grid->tn/1000));
foreach_vertex()
[] = y - Hg - (perlin (x, z, nx, ny));
phiboundary ({phi});
fractions (phi, cp, fp);
//Combine tree and surface
foreach()
[] = min (cs[], cp[]);
csforeach_face()
.x[] = min(fs.x[], fp.x[]);
fsboundary ({cs, fs});
fractions_cleanup (cs, fs);
//Obain potential
printf ("# Start solving for the Potential\n");
= 10;
NITERMIN mgstats mg = poisson (pot, laplace, alpha = fs,

unknown function parameter ‘embed_flux’
embed_flux = embed_flux, tolerance = HUGE);
printf ("# Solved with a max. residual %g\n", mg.resa);
//Get potential flow field
foreach() {
foreach_dimension()
.x[] = center_gradient(pot) * cs[];
u}
boundary ((scalar*){u});
//Place tracer particles
= init_tp_square (n = 30, ym = H + Hg, l = 2*R1, zp = -L0/4);
P = 0.1;
DT
//free stuff!
free (trees);
free (nodes);
free (gradp);
}
event set_dtmax (i++) {
= dtnext(DT);
dt }
double th = 0;
event movie (t += 1.) {
view (bg = {0.3, 0.3, 0.9}, theta = th, phi = 0.2);
view (ty = -.3);
draw_vof ("cs", "fs", fc = {0.73,0.4,0.2});
translate (y = 0.01)
draw_vof ("cp", "fp", fc = {0.2,0.9,0.2});
scatter (P);
box();
save ("tree.mp4");
+= 0.006;
th }
event stop (t = 500);