sandbox/Antoonvh/tree/colonizedtree.c

    Potential flow past a digitally-generated tree,

    on a digitally-generated surface:

    Do not mind the blue sky

    Very realistic…. Image via Pixabay

    Very realistic…. Image via Pixabay

    #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;
    
    pot[front] = dirichlet (1);
    pot[back] = dirichlet (0);
    pot[embed] = neumann (0.);
    vector u[];
    u.n[front] = neumann(0);
    u.n[back] = neumann(0);
    int ja = 1000; double R1 = 3, H = 1.5, Hg = 1;
    
    double sy = 1.4;
    int main () {
      L0 = 10;
      X0 = Z0 = -L0/2;
      N = 64;
      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
      srand (0);
      coord atr[ja];
      int j = 0;
      while (j < ja) {
        double R = R1*pow(fabs(noise()), 1./3.1);
        coord vec = {noise(), noise(), noise()};
        normalize (&vec);
        if (vec.y > 0) {
          foreach_dimension()
    	atr[j].x = R*vec.x;
          atr[j].y *= sy;
          atr[j].y += H + Hg;
          j++;
        }
      }
    
      //Get tree nodes
      int tn = 1;
      Tnode * nodes = calloc (tn, sizeof(Tnode));
      nodes[0].x = 0;
      nodes[0].y = Hg;
      nodes[0].z = 0;
      tn = colonize (atr, ja, &nodes, 1, 2, 0.2, 0.3);
    
     // Convert nodes to branches
      Branch * trees = calloc (499, sizeof(Branch)); //?
      printf ("# nodes: %d\n", tn);
      nb = nodestotree (nodes, tn, &trees);
      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
      cp.prolongation = cs.prolongation;
      vertex scalar phi[];
      int nx = 5;
      int ny = 3;
      init_perlin (nx, ny);
      it = 0;
      do {
        foreach_vertex()
          phi[] =  y - Hg - (perlin (x, z, nx, ny));
        boundary ({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()
        phi[] =  y - Hg - (perlin (x, z, nx, ny));
      boundary ({phi});
      fractions (phi, cp, fp);
     
      //Combine tree and surface
      foreach()
        cs[] = min (cs[], cp[]);
      foreach_face()
        fs.x[] = min(fs.x[], fp.x[]);
      boundary ({cs, fs});
      fractions_cleanup (cs, fs);
      
      //Obain potential
      printf ("# Start solving for the Potential\n");
      NITERMIN = 10;
      mgstats mg = poisson (pot, laplace, alpha = fs,
    			embed_flux = embed_flux, tolerance = HUGE);
      printf ("# Solved with a max. residual %g\n", mg.resa);
    
      //Get potential flow field
      foreach() {
        foreach_dimension()
          u.x[] = center_gradient(pot) * cs[];
      }
      boundary ((scalar*){u});
    
      //Place tracer particles
      P = init_tp_square (n = 30, ym = H + Hg, l = 2*R1, zp = -L0/4);
      DT = 0.1;
    
      //free stuff!
      free (trees);
      free (nodes);
      free (gradp);
    }
    
    event set_dtmax (i++) {
      dt = dtnext(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");
      th += 0.006;
    }
    
    event stop (t = 500);