sandbox/alimare/alex_functions.h

    Miscalleneous functions

    Norm calculation

    #ifdef VOF
    coord normal (Point point, scalar c) {

    A function to rescale normals so that they are unit vectors w.r.t. the 2-norm (by default, the 1-norm is adopted for efficiency purposes).

      coord n = mycs (point, c);
      double nn = 0.;
      foreach_dimension()
        nn += sq(n.x);
      nn = sqrt(nn);
      foreach_dimension()
        n.x /= nn;
      return n;
    }

    A function to compute 2-norm normal in every cell.

    void compute_normal (scalar f, vector normal_vector) {
      foreach() {
        coord n = normal (point, f);
        foreach_dimension() 
          normal_vector.x[] = n.x;
      }
      boundary((scalar*){normal_vector});
    }
    #endif

    Norm-2

    |\cdot|_2 norm

    double norm2 (coord u) {
      double sum = 0;
      foreach_dimension()
        sum += sq(u.x);
      return sqrt(sum);
    
    }

    Sign function

    If x == 0 then returns 0.

    double sign2 (double x)
    {
      return(x > 0. ? 1. : x<0 ? -1. : 0.);
    }

    Probe

    Returns the value contained in a cell

    double capteur(Point point, scalar s){
      return s[];
    }

    Interpolations functions

    • 1D linear
    • 2D bilinear with ENO correction
    • 2D bicubic

    Interpolation stencil

    Used to choose which stencil will be used for interpolation.

    void InterpStencil (coord p, int Stencil[]){
      if(p.x<0){Stencil[0] = -1;} 
      else{Stencil[0] = 0;} 
    
      if(p.y<0) {Stencil[1] = -1;}
      else {Stencil[1] = 0;}
    }

    1D - linear interpolation

    double linearInterpolation(double x1, double f_x1, double x2, double f_x2, 
      double x)
    {
      double result = (x - x1)/(x2-x1)*f_x2  + (x2-x)/(x2-x1)*f_x1;
      return result;
    }

    Bilinear with quadratic correction

    #if dimension == 2
    double mybilin (Point point, scalar s, int Arr[], coord p_interp,
      double coeff[]){
    
      double dx = p_interp.x - Arr[0];
      double dy = p_interp.y - Arr[1];
      double dxdy = dx*dy;
      // f11
      coeff[0] = 1. - dx - dy + dxdy;
      // f21
      coeff[1] = dx - dxdy;
      // f12 
      coeff[2] = dy - dxdy;
      // f22
      coeff[3] = dxdy;
    
    //quadratic correction. from Min and Gibou 2006.
      
      double phixx0 = s[-2,0] - 2*s[-1,0] + s[];
      dx = phixx0*(dx)*(1.-dx)/2.;
    
      phixx0 = s[0,-1] - 2*s[] + s[0,1];
      dy= phixx0*(dy)*(1.-dy)/2.;
      // double phixx0 = s[Arr[0]-1,Arr[1]] - 2*s[Arr[0],Arr[1]] 
        // + s[Arr[0]+1,Arr[1]];
      // double phixx1 = s[Arr[0],Arr[1]] - 2*s[Arr[0]+1,Arr[1]] 
        // + s[Arr[0]+2,Arr[1]];
      // double phixx2 = s[Arr[0]-1,Arr[1]+1] - 2*s[Arr[0],Arr[1]+1] 
        // + s[Arr[0]+1,Arr[1]+1];
      // double phixx3 = s[Arr[0],Arr[1]+1] - 2*s[Arr[0]+1,Arr[1]+1] 
        // + s[Arr[0]+2,Arr[1]+1];
      // double phixval[4] = {phixx0,phixx1,phixx2,phixx3};  
      // fprintf(stderr, "%g %g %g %g\n", phixx0, phixx1, phixx2, phixx3);
      // dx = phixval[minlist(phixval)]*(dx)*(1.-dx)/2.;
      // fprintf(stderr, "%g\n", phixval[minlist(phixval)]);
    
    
      // phixx0 = s[Arr[0],Arr[1]-1] - 2*s[Arr[0],Arr[1]] 
      //   + s[Arr[0],Arr[1]+1];
      // phixx1 = s[Arr[0],Arr[1]] - 2*s[Arr[0],Arr[1]+1] 
      //   + s[Arr[0],Arr[1]+2];
      // phixx2 = s[Arr[0]+1,Arr[1]-1] - 2*s[Arr[0]+1,Arr[1]] 
      //   + s[Arr[0]+1,Arr[1]+1];
      // phixx3 = s[Arr[0]+1,Arr[1]] - 2*s[Arr[0]+1,Arr[1]+1] 
      //   + s[Arr[0]+1,Arr[1]+2];
    
      // fprintf(stderr, "%g %g %g %g\n", phixx0, phixx1, phixx2, phixx3);
      // dy = phixval[minlist(phixval)]*(dy)*(1.-dy)/2.;
      // fprintf(stderr, "%g\n", phixval[minlist(phixval)]);
      // fprintf(stderr, "####\n" );
      // exit(1);
    
      return  s[Arr[0],Arr[1]]*coeff[0] + 
              s[Arr[0]+1,Arr[1]]*coeff[1] + 
              s[Arr[0],Arr[1]+1]*coeff[2] + 
              s[Arr[0]+1,Arr[1]+1]*coeff[3];
              // -dx-dy;
    }
    #endif

    Biquadratic interpolation on a Cartesian grid.

    We want to calculate a matrix A such that: \displaystyle \begin{aligned} f(x,y) &= \sum_{i=0}^2\sum_{j=0}^2a_{ij}x^iy^j \\ &= \left[\begin{array}{cccc} x^2 & x & 1 \end{array}\right] \left[\begin{array}{cccc} a_{2,2} & a_{2,1} & a_{2,0}\\ a_{1,2} & a_{1,1} & a_{1,0}\\ a_{0,2} & a_{0,1} & a_{0,0}\\ \end{array}\right] \left[\begin{array}{c} y^2\\ y\\ 1 \end{array}\right]\\ &= X A Y^T \end{aligned} Given a set of 3\times 3 known data points, we have: \displaystyle \begin{aligned} F &= BAB^T\\ \left[\begin{array}{ccc} f(-1,-1) & f(-1,0) & f(-1,1)\\ f(0,-1) & f(0,0) & f(0,1) \\ f(1,-1) & f(1,0) & f(1,1) \\ \end{array}\right]_{F} &= \left[\begin{array}{ccc} (-1)^2 & -1 & 1\\ 0^2 & 0 & 1\\ 1^2 & 1 & 1\\ \end{array}\right]_{B} \left[\begin{array}{ccc} a_{2,2} & a_{2,1} & a_{2,0}\\ a_{1,2} & a_{1,1} & a_{1,0}\\ a_{0,2} & a_{0,1} & a_{0,0}\\ \end{array}\right]_A \left[\begin{array}{ccc} (-1)^2 & 0 & (1)^2\\ -1 & 0 & 1 \\ 1 & 1 & 1 \\ \end{array}\right]_{B^T} \end{aligned} Therefore we have: \displaystyle \begin{aligned} F = BAB^T \Rightarrow A &= B^{-1} F \left(B^{T}\right)^{-1}\\ &= B^{-1} F \left(B^{-1}\right)^{T}\end{aligned} after some calculations, one gets: \displaystyle B = \left[\begin{array}{ccc} 1 & -1 & 1\\ 0 & 0 & 1 \\ 1 & 1 & 1 \\ \end{array}\right] \Rightarrow B^{-1} = \left[\begin{array}{ccc} 0.5 & -1 & 0.5\\ -0.5 & 0 & 0.5\\ 0 & 1 & 0\\ \end{array}\right]

    static inline double mybiquadratic(Point point, scalar s, coord p, int offset){
      double dx = p.x;
      double dy = p.y;
      double X[3] = {dx*dx,dx,1.};
      double Y[3] = {dy*dy,dy,1.};
    
    double Bm1[9] = {0.5, -1, 0.5,
                    -0.5,  0, 0.5,
                      0,  1,   0};
    double Bm1T[9]= {0.5,-0.5, 0,
                      -1,  0,  1,
                     0.5,  0.5, 0};
    double XX[3],YY[3];
      for (int kk=0;kk<=2;kk++){
        XX[kk] = Bm1[kk]*X[0] + Bm1[3+kk]*X[1] + 
          Bm1[6+kk]*X[2];
        YY[kk] = Bm1T[kk*3]*Y[0] + Bm1T[kk*3+1]*Y[1] +
          Bm1T[kk*3+2]*Y[2];
      }
    
    
      for (int kk = 0;kk<=2;kk++){
        X[kk] = s[-1,-1+kk,offset]*XX[0] + 
                s[ 0,-1+kk,offset]*XX[1] +
                s[+1,-1+kk,offset]*XX[2];
      }
      return X[0]*YY[0]+X[1]*YY[1]+X[2]*YY[2];
    }
    
    // taken from Ghigo
    
    double mytriquadratic(Point point, scalar s, coord p){

    We do a triple biquadratic interpolation and then quadratically interpolate the result.

      double dz = p.z;
      double arr[3];
      arr[0] = mybiquadratic(point, s, p, -1);
      arr[1] = mybiquadratic(point, s, p, 0);
      arr[2] = mybiquadratic(point, s, p, 1);
      return quadratic(dz,arr[0],arr[1],arr[2]);
    }

    Bicubic interpolation on a Cartesian grid

    Taken from this link (slide 16-17).

    We want to calculate a matrix A such that: \displaystyle \begin{aligned} f(x,y) &= \sum_{i=0}^3\sum_{j=0}^3a_{ij}x^iy^j \\ &= \left[\begin{array}{cccc} x^3 & x^2 & x & 1 \end{array}\right] \left[\begin{array}{cccc} a_{3,3} & a_{3,2} & a_{3,1} & a_{3,0}\\ a_{2,3} & a_{2,2} & a_{2,1} & a_{2,0}\\ a_{1,3} & a_{1,2} & a_{1,1} & a_{1,0}\\ a_{0,3} & a_{0,2} & a_{0,1} & a_{0,0}\\ \end{array}\right] \left[\begin{array}{c} y^3\\ y^2\\ y\\ 1 \end{array}\right]\\ &= X A Y^T \end{aligned} Given a set of 4\times 4 known data points, we have: \displaystyle \begin{aligned} F &= BAB^T\\ \left[\begin{array}{cccc} f(-1,-1) & f(-1,0) & f(-1,1) & f(-1,2)\\ f(0,-1) & f(0,0) & f(0,1) & f(0,2)\\ f(1,-1) & f(1,0) & f(1,1) & f(1,2)\\ f(2,-1) & f(2,0) & f(2,1) & f(2,2)\\ \end{array}\right]_{F} &= \left[\begin{array}{cccc} (-1)^3 & (-1)^2 & -1 & 1\\ 0^3 & 0^2 & 0 & 1\\ 1^3 & 1^2 & 1 & 1\\ 2^3 & 2^2 & 2 & 1\\ \end{array}\right]_{B} \left[\begin{array}{cccc} a_{3,3} & a_{3,2} & a_{3,1} & a_{3,0}\\ a_{2,3} & a_{2,2} & a_{2,1} & a_{2,0}\\ a_{1,3} & a_{1,2} & a_{1,1} & a_{1,0}\\ a_{0,3} & a_{0,2} & a_{0,1} & a_{0,0}\\ \end{array}\right]_A \left[\begin{array}{cccc} (-1)^3 & 0 & (1)^3 & (2)^3\\ (-1)^2 & 0 & (1)^2 & (2)^2\\ -1 & 0 & 1 & 2\\ 1 & 1 & 1 & 1\\ \end{array}\right]_{B^T} \end{aligned} Therefore we have: \displaystyle \begin{aligned} F = BAB^T \Rightarrow A &= B^{-1} F \left(B^{T}\right)^{-1}\\ &= B^{-1} F \left(B^{-1}\right)^{T}\end{aligned} after some calculations, one gets: \displaystyle B = \left[\begin{array}{cccc} -1 & 1 & -1 & 1\\ 0 & 0 & 0 & 1 \\ 1 & 1 & 1 & 1 \\ 8 & 4 & 2 & 1 \\ \end{array}\right] \Rightarrow B^{-1} = \left[\begin{array}{cccc} -1/6 & 1/2 & -1/2 & 1/6\\ 1/2 & -1 & 1/2 & 0 \\ -1/3 & -1/2 & 1 & -1/6 \\ 0 & 1 & 0 & 0 \\ \end{array}\right] Now we can do the bicubic interpolation: \displaystyle f(x,y) = X B^{-1} F \left(B^{-1}\right)^T Y^T = \mathcal{X} F \mathcal{Y}

    A simple test case can be seen here.

    double bicubic(Point point , scalar s, int Arr[], coord p){
      double dx = p.x - Arr[0];
      double dy = p.y - Arr[1];
      double X[4] = {dx*dx*dx,dx*dx,dx,1.};
      double Y[4] = {dy*dy*dy,dy*dy,dy,1.};

    B^{-1} and (B^{-1})^T are hardcoded.

      double Bm1[16] = {-1./6, 1/2., -1/2., 1/6.,
                        1/2., -1   ,  1/2., 0   ,
                        -1./3, -1/2. ,   1  , -1./6,
                        0   ,  1   ,   0  ,  0  };
    
      double Bm1T[16] = {-1/6., 1/2., -1./3,  0.,
                          1/2.,   -1, -1/2.,  1.,
                         -1/2., 1/2.,    1.,  0.,
                          1/6.,    0, -1./6,  0};

    We calculate \mathcal{X} and \mathcal{Y}.

      double XX[4],YY[4];
      for (int kk=0;kk<=3;kk++){
        XX[kk] = Bm1[kk]*X[0] + Bm1[4+kk]*X[1] + 
          Bm1[8+kk]*X[2] + Bm1[12+kk]*X[3];
        YY[kk] = Bm1T[kk*4]*Y[0] + Bm1T[kk*4+1]*Y[1] +
          Bm1T[kk*4+2]*Y[2] + Bm1T[kk*4+3]*Y[3];
      }
    
    
      for (int kk = 0;kk<=3;kk++){
        X[kk] = s[Arr[0]-1,Arr[1]-1+kk]*XX[0] + 
                s[Arr[0]  ,Arr[1]-1+kk]*XX[1] +
                s[Arr[0]+1,Arr[1]-1+kk]*XX[2] +
                s[Arr[0]+2,Arr[1]-1+kk]*XX[3];
      }
    
      return X[0]*YY[0]+X[1]*YY[1]+X[2]*YY[2]+X[3]*YY[3];
    }

    Cell to node interpolation

    Bilinear with quadratic correction (ENO) or bicubic interpolation.

    void cell2node(scalar cell_scalar, vertex scalar node_scalar){
      foreach_vertex(){
        coord p_interp = {-0.5, -0.5, -0.5};
    
        if((point.i-1) > (1 << grid-> depth)){
          p_interp.x = 0.5;
        }
    
        if((point.j-1) > (1 << grid-> depth)){
          p_interp.y = 0.5;
        }
        
    #ifdef BICUBIC    
        assert(dimension == 2); // tricubic not coded so far.
        int Stencil[2] = {-1,-1};
        node_scalar[] = bicubic(point , cell_scalar, Stencil, p_interp);
    #elif QUADRATIC
    #if dimension == 2
        node_scalar[] = mybiquadratic(point , cell_scalar, p_interp,0);
    #else
        if((point.k-1) > (1 << grid-> depth)){
          p_interp.z = 0.5;
        }
        node_scalar[] = mytriquadratic(point , cell_scalar, p_interp);
    #endif
    #else
        assert(dimension ==2);
        double coeff[4];
        int Stencil[2] = {-1,-1};
        node_scalar[] = mybilin(point , cell_scalar, Stencil, p_interp, coeff);
    #endif
      }
      boundary ({node_scalar});
      restriction({node_scalar});
    
    }