sandbox/Tianyang/embedded_contact_2D/src/vof_ebm.h

    #include "fractions_ebm.h"
    
    attribute {
      scalar angle;
      scalar cfg;
      scalar cet;
      vector mcl;
      vector hp;
    }
    
    event stability (i++) {
    #if !EMBED
      if (CFL > 0.5)
        CFL = 0.5;
    #else
      if (CFL > 0.5)
        CFL = 0.1;
    #endif
    }
    
    static scalar * _interface = NULL;
    
    // To avoid the advection of "f"
    event vof (i++) {
      interfaces = _interface;
    }
    
    // need to disable the vof event
    #include "vof.h"
    
    // To avoid the advection of "f"
    event vof (i++) {
      _interface = interfaces;
      interfaces = NULL;
    }
    
    event defaults (i = 0)
    {
      for (scalar c in interfaces) {
        scalar cfg = c.cfg;
        if (!cfg.i)
          cfg = new scalar;
        c.cfg = cfg;
    
        scalar cet = c.cet;
        if (!cet.i)
          cet = new scalar;
        c.cet = cet;
    
        vector mcl = c.mcl;
        if (!mcl.x.i)
          mcl = new vector;
        c.mcl = mcl;
    
        vector hp = c.hp;
        if (!hp.x.i)
          hp = new vector;
        c.hp = hp;
      }
    }
    
    foreach_dimension()
    static void sweep_ebm_x (scalar c, scalar cc, scalar * tcl)
    {
      vector n[], ncs[];
      scalar alpha[], alphacs[], flux[];
      double cfl = 0.;
    
      scalar * tracers = c.tracers, * gfl = NULL, * tfluxl = NULL;
      if (tracers) {
        for (scalar t in tracers) {
          scalar gf = new scalar, flux = new scalar;
          gfl = list_append (gfl, gf);
          tfluxl = list_append (tfluxl, flux);
        }
    
        foreach() {
          scalar t, gf;
          for (t,gf in tracers,gfl)
    	      gf[] = vof_concentration_gradient_x (point, c, t);
        }
      }
    
      reconstruction_cs (cs, fs, ncs, alphacs);
      reconstruction_emd (c, n, alpha, cs, ncs, alphacs);
      
      foreach_face(x, reduction (max:cfl)) {
    
        double un = uf.x[]*dt/(Delta*fm.x[] + SEPS), s = sign(un);
        int i = -(s + 1.)/2.;
    
        if (un*fm.x[]*s/(cm[] + SEPS) > cfl)
          cfl = un*fm.x[]*s/(cm[] + SEPS);
    
        double cf;
        if (cs[i] >= 1.)
          cf = (c[i] <= 0. || c[i] >= 1.) ? c[i] :
          rectangle_fraction ((coord){-s*n.x[i], n.y[i], n.z[i]}, alpha[i],
    			  (coord){-0.5, -0.5, -0.5},
    			  (coord){s*un - 0.5, 0.5, 0.5});
        else {
          if (c[i] <= 0.)
            cf = 0.;
          else if (c[i] >= cs[i])
            cf = 1.;
          else {
            assert (cs[i] > 0. && cs[i] < 1.);
            assert (c[i] > 0. && c[i] < cs[i]);
    #if dimension == 2
            if (fs.x[] > 0. && fabs(un) > 0.) {
              coord m   = {1., 0., 0.};
              coord mcs = {-s*ncs.x[i], ncs.y[i], ncs.z[i]};
              double fv = uf.x[]*dt*s/Delta;
              assert (fv > 0. && fv < cs[i]);
              double unc = line_alpha_ebm (fv, cs[i], mcs, alphacs[i], m) + 0.5;
              assert (unc > fv - 1e-10);
    
              double vlq = rectangle_fraction_cs (cs[i], fs.x[], (coord){-s*ncs.x[i], ncs.y[i], ncs.z[i]}, alphacs[i],
                    (coord){-s*n.x[i], n.y[i], n.z[i]}, alpha[i],
    			          (coord){-0.5, -0.5, -0.5},
    			          (coord){unc - 0.5, 0.5, 0.5});
              double vfluid = rectangle_fraction ((coord){-s*ncs.x[i], ncs.y[i], ncs.z[i]}, alphacs[i],
    			          (coord){-0.5, -0.5, -0.5},
    			          (coord){unc - 0.5, 0.5, 0.5});
    
              if (vfluid < vlq - 1e-10)
                fprintf (stdout, "Warning: t: %g vfluid - vlq = %g\n", t, (vfluid - vlq));
              cf = min (vlq/vfluid, 1.);
            }
            else
              cf = 0.;
    #endif
          }
        }
    
        flux[] = cf*uf.x[];
        
        scalar t, gf, tflux;
        for (t,gf,tflux in tracers,gfl,tfluxl) {
          double cf1 = cf, ci = c[i];
          if (t.inverse)
    	      cf1 = 1. - cf1, ci = 1. - ci;
          if (ci > 1e-10) {
    	      double ff = t[i]/ci + s*min(1., 1. - s*un)*gf[i]*Delta/2.;
    	      tflux[] = ff*cf1*uf.x[];
          }
          else
    	      tflux[] = 0.;
        }
      }
      delete (gfl); free (gfl);
    
      if (cfl > 0.1 + 1e-6)
        fprintf (stdout, 
    	     "WARNING: CFL must be <= 0.1 for VOF (cfl - 0.1 = %g)\n", 
    	     cfl - 0.1), fflush (stdout);
    
      foreach()
        if (cs[] > 0.) {
          c[] += dt*(flux[] - flux[1] + cc[]*(uf.x[1] - uf.x[]))/Delta;
          c[] = c[] < 1e-10 ? 0. : c[] > cs[] - 1e-10 ? cs[] : c[]; // filter
    #if NO_1D_COMPRESSION
          for (t, tflux in tracers, tfluxl)
    	t[] += dt*(tflux[] - tflux[1])/Delta;
    #else // !NO_1D_COMPRESSION
          scalar t, tc, tflux;
          for (t, tc, tflux in tracers, tcl, tfluxl)
    	t[] += dt*(tflux[] - tflux[1] + tc[]*(uf.x[1] - uf.x[]))/Delta;
    #endif // !NO_1D_COMPRESSION
        }
    
      scalar cfg = c.cfg;
      scalar cfgn[];
      foreach()
        cfgn[] = cfg[];
    
      foreach()
        if (cfg[] == 1.) {
          if (is_three_phase (c[], cs[])) {
            coord m, mcs;
            foreach_dimension() {
              m.x = n.x[];
              mcs.x = ncs.x[];
            }
            double alphan = line_alpha_ebm (c[], cs[], mcs, alphacs[], m);
            coord clp = find_cl_pos (m, alphan, mcs, alphacs[]);
            if (fabs(clp.x) > 0.5 || fabs(clp.y) > 0.5)
              for (int k = 0; k < 2; k++) {
                int i = 2*k - 1;
                foreach_dimension()
                  if (fs.x[k] > 0. && fs.x[k] < 1. && i*clp.x > 0.5 && is_three_phase (c[i], cs[i]))
                    cfgn[] = (fabs(cfg[i]) == 2. ? - cfg[i] : nodata);
              }
          }
          else
            cfgn[] = (c[] >= cs[] ? 2. : -2.);
        }
    
      foreach()
        if (cs[] > 0. && cs[] < 1. && cfgn[] == nodata)
          for (int k = 0; k < 2; k++) {
            int i = 2*k - 1;
            foreach_dimension()
              if (fs.x[k] > 0. && fs.x[k] < 1. && fabs(cfg[i]) == 2.)
                cfgn[] = cfg[i];
          }
    
      foreach()
        if (cs[] > 0. && cs[] < 1. && fabs(cfgn[]) == 2.)
          for (int k = 0; k < 2; k++) {
            int i = 2*k - 1;
            foreach_dimension()
              if (fs.x[k] > 0. && fs.x[k] < 1. && (cfgn[] + cfgn[i]) == 0. && cfg[i] == 1.)
                cfgn[] = 1.;
          }
    
      foreach()
        cfg[] = cfgn[];
    
      delete (tfluxl); free (tfluxl);
    }

    Multi-dimensional advection

    The multi-dimensional advection is performed by the event below.

    void vof_advection_ebm (scalar * interfaces, int i)
    {
      for (scalar c in interfaces) {

    We first define the volume fraction field used to compute the divergent term in the one-dimensional advection equation above. We follow Weymouth & Yue, 2010 and use a step function which guarantees exact mass conservation for the multi-dimensional advection scheme (provided the advection velocity field is exactly non-divergent).

        scalar cc[], * tcl = NULL, * tracers = c.tracers;    
        for (scalar t in tracers) {
    #if !NO_1D_COMPRESSION
          scalar tc = new scalar;
          tcl = list_append (tcl, tc);
    #endif // !NO_1D_COMPRESSION
    #if TREE
          if (t.refine != vof_concentration_refine) {
    	t.refine = t.prolongation = vof_concentration_refine;
    	t.restriction = restriction_volume_average;
    	t.dirty = true;
    	t.c = c;
          }
    #endif // TREE
        }
        foreach() {
    #if !EMBED
          cc[] = (c[] > 0.5);
    #else
          cc[] = (c[] > 0.5*cs[]);
    #endif
    #if !NO_1D_COMPRESSION
          scalar t, tc;
          for (t, tc in tracers, tcl) {
    	if (t.inverse)
    	  tc[] = c[] < 0.5 ? t[]/(1. - c[]) : 0.;
    	else
    	  tc[] = c[] > 0.5 ? t[]/c[] : 0.;
          }
    #endif // !NO_1D_COMPRESSION
        }

    We then apply the one-dimensional advection scheme along each dimension. To try to minimise phase errors, we alternate dimensions according to the parity of the iteration index i.

        void (* sweep[dimension]) (scalar, scalar, scalar *);
        int d = 0;
    #if !EMBED
        foreach_dimension()
          sweep[d++] = sweep_x;
    #else
        foreach_dimension()
          sweep[d++] = sweep_ebm_x;
    #endif
        for (d = 0; d < dimension; d++) {
          sweep[(i + d) % dimension] (c, cc, tcl);
    #if EMBED
          update_cfg (c, cs, fs, c.cfg);
          update_cet (c, cs, fs, c.cfg, c.cet, c.angle);
    #endif
    
          assert (c.height.x.i);
    #if !EMBED
          heights (c, c.height);
    #else
          heights_ebm (c, cs, c.height, c.cet);
    #endif
        }
        delete (tcl), free (tcl);
      }
    }
    
    event vof (i++)
      vof_advection_ebm (interfaces, i);