sandbox/msaini/Marangoni/functionsHF.h

    Check if this is exact copy of curvature.h in Basilisk scr

    #if TREE
    static void curvature_restriction (Point point, scalar kappa)
    {
      double k = 0., s = 0.;
      foreach_child()
        if (kappa[] != nodata)
          k += kappa[], s++;
      kappa[] = s ? k/s : nodata;
    }
    
    static void curvature_prolongation (Point point, scalar kappa)
    {
      foreach_child() {
        double sk = 0., s = 0.;
        for (int i = 0; i <= 1; i++)
        #if dimension > 1
          for (int j = 0; j <= 1; j++)
        #endif
          #if dimension > 2
    	for (int k = 0; k <= 1; k++)
          #endif
    	  if (coarse(kappa,child.x*i,child.y*j,child.z*k) != nodata)
    	    sk += coarse(kappa,child.x*i,child.y*j,child.z*k), s++;
        kappa[] = s ? sk/s : nodata;
      }
    }
    #endif // TREE
    
    #include "heights.h"
    
    foreach_dimension()
    static double kappa_y (Point point, vector h)
    {
      int ori = orientation(h.y[]);
      for (int i = -1; i <= 1; i++)
        if (h.y[i] == nodata || orientation(h.y[i]) != ori)
          return nodata;
      double hx = (h.y[1] - h.y[-1])/2.;
      double hxx = (h.y[1] + h.y[-1] - 2.*h.y[])/Delta;
      return hxx/pow(1. + sq(hx), 3/2.);
    }
    
    foreach_dimension()
    static coord normal_y (Point point, vector h)
    {
      coord n = {nodata, nodata, nodata};
      if (h.y[] == nodata)
        return n;
      int ori = orientation(h.y[]);
      if (h.y[-1] != nodata && orientation(h.y[-1]) == ori) {
        if (h.y[1] != nodata && orientation(h.y[1]) == ori)
          n.x = (h.y[-1] - h.y[1])/2.;
        else
          n.x = h.y[-1] - h.y[];
      }
      else if (h.y[1] != nodata && orientation(h.y[1]) == ori)
        n.x = h.y[] - h.y[1];
      else
        return n;
      double nn = (ori ? -1. : 1.)*sqrt(1. + sq(n.x));
      n.x /= nn;
      n.y = 1./nn;
      return n;
    }
    
    static double height_curvature (Point point, scalar c, vector h)
    {
    
      typedef struct {
        double n;
        double (* kappa) (Point, vector);
      } NormKappa;
      struct { NormKappa x, y, z; } n;  
      foreach_dimension()
        n.x.n = c[1] - c[-1], n.x.kappa = kappa_x;
      double (* kappaf) (Point, vector) = NULL; NOT_UNUSED (kappaf);
        
      if (fabs(n.x.n) < fabs(n.y.n))
        swap (NormKappa, n.x, n.y);
    #if dimension == 3
      if (fabs(n.x.n) < fabs(n.z.n))
        swap (NormKappa, n.x, n.z);
      if (fabs(n.y.n) < fabs(n.z.n))
        swap (NormKappa, n.y, n.z);
    #endif
    
      double kappa = nodata;
      foreach_dimension()
        if (kappa == nodata) {
          kappa = n.x.kappa (point, h);
          if (kappa != nodata) {
    	kappaf = n.x.kappa;
    	if (n.x.n < 0.)
    	  kappa = - kappa;
          }
        }
    
      if (kappa != nodata) {
        
        if (fabs(kappa) > 1./Delta)
          kappa = sign(kappa)/Delta;
        
      }
      
      return kappa;
    }
    
    coord height_normal (Point point, scalar c, vector h)
    {
    
      typedef struct {
        double n;
        coord (* normal) (Point, vector);
      } NormNormal;
      struct { NormNormal x, y, z; } n;  
      foreach_dimension()
        n.x.n = c[1] - c[-1], n.x.normal = normal_x;
        
      if (fabs(n.x.n) < fabs(n.y.n))
        swap (NormNormal, n.x, n.y);
    #if dimension == 3
      if (fabs(n.x.n) < fabs(n.z.n))
        swap (NormNormal, n.x, n.z);
      if (fabs(n.y.n) < fabs(n.z.n))
        swap (NormNormal, n.y, n.z);
    #endif
    
      coord normal = {nodata, nodata, nodata};
      foreach_dimension()
        if (normal.x == nodata)
          normal = n.x.normal (point, h);
      
      return normal;
    }
    
    #include "parabola.h"
    
    static int independents (coord * p, int n)
    {
      if (n < 2)
        return n;
      int ni = 1;
      for (int j = 1; j < n; j++) {
        bool depends = false;
        for (int i = 0; i < j && !depends; i++) {
          double d2 = 0.;
          foreach_dimension()
    	d2 += sq(p[i].x - p[j].x);
          depends = (d2 < sq(0.5));
        }
        ni += !depends;
      }
      return ni;
    }
    
    static double height_curvature_fit (Point point, scalar c, vector h)
    {
      
      coord ip[dimension == 2 ? 6 : 27];
      int n = 0;
      
      foreach_dimension() {
        
        int n1 = 0, n2 = 0;
        for (int i = -1; i <= 1; i++)
          if (h.y[i] != nodata) {
    	if (orientation(h.y[i])) n1++; else n2++;
          }
        int ori = (n1 > n2);
    
        for (int i = -1; i <= 1; i++)
          if (h.y[i] != nodata && orientation(h.y[i]) == ori)
    	ip[n].x = i, ip[n++].y = height(h.y[i]);
      }
      
      if (independents (ip, n) < (dimension == 2 ? 3 : 9))
        return nodata;
      
      coord m = mycs (point, c), fc;
      double alpha = plane_alpha (c[], m);
      double area = plane_area_center (m, alpha, &fc);
      ParabolaFit fit;
      parabola_fit_init (&fit, fc, m);
      NOT_UNUSED(area);
      parabola_fit_add (&fit, fc, PARABOLA_FIT_CENTER_WEIGHT);
    
      for (int i = 0; i < n; i++)
        parabola_fit_add (&fit, ip[i], 1.);
      parabola_fit_solve (&fit);
      double kappa = parabola_fit_curvature (&fit, 2., NULL)/Delta;
      return kappa;
    }
    
    
    static double centroids_curvature_fit (Point point, scalar c)
    {
      
      coord m = mycs (point, c), fc;
      double alpha = plane_alpha (c[], m);
      plane_area_center (m, alpha, &fc);
      ParabolaFit fit;
      parabola_fit_init (&fit, fc, m);
    
      coord r = {x,y,z};
      foreach_neighbor(1)
        if (c[] > 0. && c[] < 1.) {
          coord m = mycs (point, c), fc;
          double alpha = plane_alpha (c[], m);
          double area = plane_area_center (m, alpha, &fc);
          coord rn = {x,y,z};
          foreach_dimension()
    	fc.x += (rn.x - r.x)/Delta;
          parabola_fit_add (&fit, fc, area);
        }
      parabola_fit_solve (&fit);
      double kappa = parabola_fit_curvature (&fit, 2., NULL)/Delta;
      return kappa;
    }
    
    
    static inline bool interfacial (Point point, scalar c)
    {
      if (c[] >= 1.) {
        for (int i = -1; i <= 1; i += 2)
          foreach_dimension()
    	if (c[i] <= 0.)
    	  return true;
      }
      else if (c[] <= 0.) {
        for (int i = -1; i <= 1; i += 2)
          foreach_dimension()
    	if (c[i] >= 1.)
    	  return true;
      }
      else // c[] > 0. && c[] < 1.
        return true;
      return false;
    }
    
    typedef struct {
      int h; // number of standard HF curvatures
      int f; // number of parabolic fit HF curvatures
      int a; // number of averaged curvatures
      int c; // number of centroids fit curvatures
    } cstats;
    
    trace
    cstats curvature (scalar c, scalar kappa,
    		  double sigma = 1.[0], bool add = false)
    {
      int sh = 0, sf = 0, sa = 0, sc = 0;
      vector ch = c.height, h = automatic (ch);
      if (!ch.x.i)
        heights (c, h);

    On trees we set the prolongation and restriction functions for the curvature.

    #if TREE
      kappa.refine = kappa.prolongation = curvature_prolongation;
      kappa.restriction = curvature_restriction;
    #endif

    We first compute a temporary curvature k: a “clone” of \kappa.

      scalar k[];
      scalar_clone (k, kappa);
    
      foreach(reduction(+:sh) reduction(+:sf)) {
        
        if ((k[] = height_curvature (point, c, h)) != nodata)
          sh++;
        else if ((k[] = height_curvature_fit (point, c, h)) != nodata)
          sf++;
      }
      
      foreach (reduction(+:sa) reduction(+:sc)) {

    We then construct the final curvature field using either the computed temporary curvature…

        double kf;
        if (k[] < nodata)
          kf = k[];
        else if (interfacial (point, c)) {

    …or the average of the curvatures in the 3^{d} neighborhood of interfacial cells.

          double sk = 0., a = 0.;
          foreach_neighbor(1)
    	if (k[] < nodata)
    	  sk += k[], a++;
          if (a > 0.)
    	kf = sk/a, sa++;
          else

    Empty neighborhood: we try centroids as a last resort.

    	kf = centroids_curvature_fit (point, c), sc++;
        }
        else
          kf = nodata;

    We add or set kappa.

        if (kf == nodata)
          kappa[] = nodata;
        else if (add)
          kappa[] += sigma*kf;
        else
          kappa[] = sigma*kf;      
      }
    
      return (cstats){sh, sf, sa, sc};
    }

    Position of an interface

    This is similar to curvature but this time for the position of the interface, defined as \displaystyle pos = \mathbf{G}\cdot(\mathbf{x} - \mathbf{Z}) with \mathbf{G} and \mathbf{Z} two vectors and \mathbf{x} the coordinates of the interface.

    This is defined only in interfacial cells. In all the other cells it takes the value nodata.

    We first need a function to compute the position \mathbf{x} of an interface. For accuracy, we first try to use height functions.

    foreach_dimension()
    static double pos_x (Point point, vector h, coord * G, coord * Z)
    {
      if (fabs(height(h.x[])) > 1.)
        return nodata;
      coord o = {x, y, z};
      o.x += height(h.x[])*Delta;
      double pos = 0.;
      foreach_dimension()
        pos += (o.x - Z->x)*G->x;
      return pos;
    }

    We now need to choose one of the x, y or z height functions to compute the position. This is done by the function below which returns the HF position given a volume fraction field f, a height function field h and vectors G and Z.

    static double height_position (Point point, scalar f, vector h,
    			       coord * G, coord * Z)
    {

    We first define pairs of normal coordinates n (computed by simple differencing of f) and corresponding HF position function pos (defined above).

      typedef struct {
        double n;
        double (* pos) (Point, vector, coord *, coord *);
      } NormPos;
      struct { NormPos x, y, z; } n;
      foreach_dimension()
        n.x.n = f[1] - f[-1], n.x.pos = pos_x;

    We sort these pairs in decreasing order of |n|.

      if (fabs(n.x.n) < fabs(n.y.n))
        swap (NormPos, n.x, n.y);
    #if dimension == 3
      if (fabs(n.x.n) < fabs(n.z.n))
        swap (NormPos, n.x, n.z);
      if (fabs(n.y.n) < fabs(n.z.n))
        swap (NormPos, n.y, n.z);
    #endif

    We try each position function in turn.

      double pos = nodata;
      foreach_dimension()
        if (pos == nodata)
          pos = n.x.pos (point, h, G, Z);
    
      return pos;
    }

    The position() function fills field pos with \displaystyle \mathbf{G}\cdot(\mathbf{x} - \mathbf{Z}) with \mathbf{x} the position of the interface defined by f.

    If add is true, the position is added to pos.

    void position (scalar f, scalar pos,
    	       coord G = {0}, coord Z = {0}, bool add = false)
    {

    On trees we set the prolongation and restriction functions for the position.

    #if TREE
      pos.refine = pos.prolongation = curvature_prolongation;
      pos.restriction = curvature_restriction;
    #endif
    
      vector fh = f.height, h = automatic (fh);
      if (!fh.x.i)
        heights (f, h);
      foreach() {
        if (interfacial (point, f)) {
          double hp = height_position (point, f, h, &G, &Z);
          if (hp == nodata) {

    If the height function is not defined, we use the centroid of the reconstructed VOF interface.

    	coord n = mycs (point, f), o = {x,y,z}, c;
    	double alpha = plane_alpha (f[], n);
    	plane_area_center (n, alpha, &c);
    	hp = 0.;
    	foreach_dimension()
    	  hp += (o.x + Delta*c.x - Z.x)*G.x;
          }
          if (add)
    	pos[] += hp;
          else
    	pos[] = hp;
        }
        else
          pos[] = nodata;
      }
    }