sandbox/tfullana/test/gnbc.c

    #include "navier-stokes/centered.h"
    #include "contact.h"
    #include "two-phase.h"
    #include "tension.h"
    #include "navier-stokes/perfs.h"
    #include "view.h"
    
    #define GNBC 1
    #define SLIP 1
    
    double rho_1 = 1. [0], rho_2 = 0.2 [0];
    double grav = -1.25 [0];
    double sig = 1. [0];
    double l_c = 1. [0];
    
    double Ca = 0.04 [0];
    double eps = 0.05 [0];
    double angle_eq = pi/2. [0];
    
    #define V_s sqrt(Ca)
    #define mu_1 (V_s)
    #define mu_2 (V_s)
    
    #define L (10*l_c)
    #define h_0 (3.5*l_c)
    
    #define Re (rho_1*V_s*l_c/mu_1)
    
    #define TCHAR (l_c/V_s)
    #define TEND (20.*TCHAR)
    
    int LEVEL = 11;
    double f_err = 1e-3 [0], u_err = 1e-4 [0];
    
    vector h[];
    
    #define robin_local(b, c) ((dirichlet ((c)*Delta/(2*(b) + Delta))) + ((neumann (0))*((2*(b) - Delta)/(2*(b) + Delta) + 1.)))
    
    double bell(double y, double eps){
    	return ((1. - pow(tanh(y/eps), 2))/eps);
    }
    
    double Young_stress(double y, double eps, double theta, double theta_eq){
    	return bell(y, eps)*(cos(theta_eq) - cos(theta));
    }
    
    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];
    }
    
    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;
    }
    
    double quadraticInterpolation(double x0, double f_x0,
                                  double x1, double f_x1,
                                  double x2, double f_x2,
                                  double x)
    {
        double L0 = ((x - x1) * (x - x2)) / ((x0 - x1) * (x0 - x2));
        double L1 = ((x - x0) * (x - x2)) / ((x1 - x0) * (x1 - x2));
        double L2 = ((x - x0) * (x - x1)) / ((x2 - x0) * (x2 - x1));
        double result = f_x0 * L0 + f_x1 * L1 + f_x2 * L2;
        return result;
    }
    
    #if GNBC
    scalar gnbc[];
    double dynamic_angle = pi/2.;
    h.t[left] = contact_angle(dynamic_angle);
    #if SLIP
    u.t[left] = robin_local(eps, gnbc[]);
    #else
    u.t[left] = dirichlet(gnbc[]);
    #endif
    #else
    h.t[left] = contact_angle(angle_eq);
    #if SLIP
    u.t[left] = robin_local(eps, V_s);
    #else
    u.t[left] = dirichlet(V_s);
    #endif
    #endif
    
    u.n[bottom]  = dirichlet(0.);
    u.t[bottom] = dirichlet(0.);
    
    u.n[right]  = neumann(0.);
    u.t[right] = neumann(0.);
    
    u.n[top]  = neumann(0.);
    u.t[top] = neumann(0.);
    
    u.n[left]  = dirichlet(0.);
    
    vertex scalar psi[];
    
    int main (int argc, char *argv[]) {
      if (argc > 1)
          Ca = atof(argv[1]);
      if (argc > 2)
          LEVEL = atoi(argv[2]);
      if (argc > 3)
          eps = atof(argv[3]);
      if (argc > 4)
          angle_eq = (pi/180.)*atof(argv[4]);
    
      origin(0., 0.);
      init_grid (128);
      DT = HUGE [0];
      f.sigma = sig;
      f.height = h;  
      rho1 = rho_1; rho2 = rho_2;
      mu1 = mu_1; mu2 = mu_2;
      size (L); 
      run();
    }
    
    event init (t = 0) {
    if (!restore (file = "restart")) {
    	fraction (f, -(y - h_0));
    	double delta = L/pow(2,LEVEL);
    	fprintf(ferr, "Re = %g Ca = %g GNBC = %d SLIP = %d LEVEL = %d\n", Re, Ca, GNBC, SLIP, LEVEL);
    	fprintf(ferr, "Delta = %g eps = %g ep/Delta = %g, angle_eq = %lf\n", delta, eps, eps/delta, 180.*angle_eq/pi);
    	fprintf(ferr, "--------------------------------------------------\n");
    } else {
    	double delta = L/pow(2,LEVEL);
    	fprintf(ferr, "Re = %g Ca = %g GNBC = %d SLIP = %d LEVEL = %d\n", Re, Ca, GNBC, SLIP, LEVEL);
    	fprintf(ferr, "Delta = %g eps = %g eps/Delta = %g, angle_eq = %lf\n", delta, eps, eps/delta, 180.*angle_eq/pi);
    	fprintf(ferr, "--------------------------------------------------\n");
    }
    }
    
    event acceleration(i++){
    	face vector av = a;
    	foreach_face(y)
        av.y[] += grav;
    }
    
    event adapt(i++){
    	adapt_wavelet ({f,u}, (double[]){f_err,u_err,u_err,u_err},  LEVEL);
    }
    
    event extract (i++){
    	char name[400];
    	sprintf (name, "GNBC%d_SLIP%d_Ca%g_LEVEL%d_eps%g_angle%g", GNBC, SLIP, Ca, LEVEL, eps, angle_eq*180./pi);
    	static FILE * fp = fopen(name, "w");
    	double angle_extracted = 0., angle_above = 0., angle_extrapolated = 0., position = 0., maxYS = 1e-300;
    	double curv = 0., Ca_loc = 0., Ca_biq0 = 0., Ca_biq = 0.;
    	scalar kappa[];
    
    	curvature (f,kappa);
    
    	foreach(reduction(max:angle_extrapolated) reduction(max:angle_above)){
    		if ((x <= (2.*Delta)) & (x > (Delta)) & (h.y[] != nodata) & (f[]< (1. - 1e-6)) & (f[]> 1e-6)){
    				coord n = {0};
    				n = interface_normal (point,f);
    				angle_above = atan2(n.y, n.x);
    				double tmp = pow(((h.y[1,0] - h.y[])/1.0), 2);
    				angle_extrapolated = angle_above + 1.5*Delta*kappa[]*sqrt(1 + tmp)/sin(angle_above);
    		}
    	}
    	scalar uy_tmp[];
    	foreach()
    		uy_tmp[] = u.y[];
    	foreach_boundary(left, reduction(max:position) reduction(max:angle_extracted) reduction(max:curv) reduction(max:Ca_loc) reduction(max:Ca_biq0) reduction(max:Ca_biq)){
    		if ((h.y[] != nodata) & (f[]< (1. - 1e-6)) & (f[]> (1e-6))){
    			double loc_position = Delta*height(h.y[]);
    			position = y + loc_position;
    			coord n = {0};
    			n = interface_normal (point,f);
    			angle_extracted = atan2(n.y, n.x);
    			curv = kappa[];
    			// coord p_interp = {0., position};
    			// Ca_loc = (mu_1/sig)*(((u.y[] - u.y[0,-1])/Delta)*(Delta*height(h.y[]) - Delta/2.) + u.y[]); 
    			Ca_loc = mu_1*u.y[]/sig; // (u.y[0,1] + 2.*u.y[] + u.y[0,-1])/4.
    			double _uy0 = 0.5*(u.y[0,-1] + u.y[-1,-1]);
    			double _uy1 = 0.5*(u.y[0,0] + u.y[-1,0]);
    			// double uy1 = linearInterpolation(-Delta/2., u.y[0,-1], Delta/2., u.y[0,0], loc_position);
    			// double uy1 = linearInterpolation(-Delta/2., _uy0, Delta/2., _uy1, loc_position);
    			double uy0 = quadraticInterpolation(-5.*Delta/2., u.y[0,-3], -3.*Delta/2., u.y[0,-2], -Delta/2., u.y[0,-1], loc_position);
    			double uy1 = quadraticInterpolation(-3.*Delta/2., u.y[0,-2], -Delta/2., u.y[0,-1], Delta/2., u.y[0,0], loc_position);
    			// double uy0 = linearInterpolation(-Delta/2., u.y[-1,-1], Delta/2., u.y[-1,0], loc_position);
    			// Ca_biq = (mu_1/sig)*mybiquadratic(point, uy_tmp, p_interp, 0);
    			Ca_biq0 = (mu_1/sig)*uy0;
    			Ca_biq = (mu_1/sig)*uy1;
    		}
    	}
    
    	double _x2 = 0., _y2 = 0., _u2 = 0., _x1 = 0., _y1 = 0., _u1 = 0., _x0 = 0., _y0 = 0., _u0 = 0.;
    	foreach (reduction(max:_x2) reduction(max:_y2) reduction(max:_u2)){
    		if ((h.y[] != nodata) & (f[]< (1. - 1e-6)) & (f[]> (1e-6)) & (x >= 2.1*Delta) & (x <= 2.9*Delta)){
    			double tmp_pos = y + Delta*height(h.y[]);
    			_x2 = x;
    			_y2 = tmp_pos;
    			_u2 = u.y[];
    		}
    	}
    	foreach (reduction(max:_x1) reduction(max:_y1) reduction(max:_u1)){
    		if ((h.y[] != nodata) & (f[]< (1. - 1e-6)) & (f[]> (1e-6)) & (x >= 1.1*Delta) & (x <= 1.9*Delta)){
    			double tmp_pos = y + Delta*height(h.y[]);
    			_x1 = x;
    			_y1 = tmp_pos;
    			_u1 = u.y[];
    		}
    	}
    	foreach_boundary (left, reduction(max:_x0) reduction(max:_y0) reduction(max:_u0)){
    		if ((h.y[] != nodata) & (f[]< (1. - 1e-6)) & (f[]> (1e-6))){
    			double tmp_pos = y + Delta*height(h.y[]);
    			_x0 = x;
    			_y0 = tmp_pos;
    			_u0 = u.y[];
    		}
    	}
    	double _Delta = L/pow(2, LEVEL);
    	double Ca_int = (mu_1/sig)*quadraticInterpolation(5*_Delta/2., _u2, 3.*_Delta/2., _u1, _Delta/2., _u0, 0.);
    	
    	#if GNBC
    	foreach_boundary(left, reduction(max:maxYS)){
    		double relative_position = y - position;
    		gnbc[] = V_s + (eps)*(sig/mu_1)*Young_stress(relative_position, eps, angle_extracted, angle_eq);
    		if (fabs(maxYS) < fabs(gnbc[]))
    			maxYS = gnbc[];
    	}
    	dynamic_angle = angle_extrapolated;
    	#endif
    
    	fflush(fp);
    	fprintf(fp,"%lf %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf\n", t/TCHAR, (position-h_0)/l_c, 180.*angle_above/pi, 180.*angle_extrapolated/pi, 180.*angle_extracted/pi, Ca_loc, curv, maxYS, Ca_biq0, Ca_biq, Ca_int);
    }
    
    event compute_stream (i++){
      scalar omega[];
      scalar _psi[];
    
      vorticity(u, omega);
    
      _psi[bottom] = dirichlet (0.);
      _psi[top]    = neumann (0.);
      _psi[left]  = dirichlet (0.);
      _psi[right]   = neumann (0.);
    
      poisson (_psi, omega);
      boundary ({_psi});
    
      foreach_vertex()
        psi[] = (_psi[0,-1] + _psi[-1,-1] + _psi[] + _psi[-1])/4.;
    }
    
    event snapshot (t = 0; t+=0.1*TCHAR; t <= TEND){
      char name[400];
    	sprintf (name, "s-GNBC%d_SLIP%d_Ca%g_LEVEL%d_eps%g_angle%g-%g", GNBC, SLIP, Ca, LEVEL, eps, angle_eq*180./pi, t/TCHAR);
    	dump (name);
    }
    
    event final (t = TEND){
    	char name[400], name2[400], name3[400], name4[400];
    	sprintf (name, "GNBC%d_SLIP%d_pressure_Ca%g_LEVEL%d_eps%g_angle%g_%d", GNBC, SLIP, Ca, LEVEL, eps, angle_eq*180./pi, tid());
    	sprintf (name2, "GNBC%d_SLIP%d_curvature_Ca%g_LEVEL%d_eps%g_angle%g_%d", GNBC, SLIP, Ca, LEVEL, eps, angle_eq*180./pi, tid());
    	sprintf (name3, "GNBC%d_SLIP%d_facets_Ca%g_LEVEL%d_eps%g_angle%g_%d", GNBC, SLIP, Ca, LEVEL, eps, angle_eq*180./pi, tid());
    	sprintf (name4, "GNBC%d_SLIP%d_dudy_Ca%g_LEVEL%d_eps%g_angle%g_%d", GNBC, SLIP, Ca, LEVEL, eps, angle_eq*180./pi, tid());
    	FILE * fp = fopen(name, "w");
    	FILE * fp2 = fopen(name2, "w");
    	FILE * fp3 = fopen(name3, "w");
    	FILE * fp4 = fopen(name4, "w");
    	scalar kappa[];
    	double position = 0.;
    
    	curvature (f,kappa);
    
    	foreach_boundary(left, reduction(max:position)){
    		if ((h.y[] != nodata) & (f[]< (1. - 1e-6)) & (f[]> (1e-6))){
    			position = y + Delta*height(h.y[]);
    		}
    		double dudy = (u.y[1,0] - u.y[])/Delta;
    		fprintf(fp4,"%lf %lf\n", y, dudy);
    	}
    
    	foreach(){
    		fprintf(fp,"%lf %lf %lf\n", x, y, p[]);
    		if ((h.y[] != nodata) & (f[]< (1. - 1e-6)) & (f[]> (1e-6))){
    			double ycl = y + Delta*height(h.y[]);
    			double r = sqrt(pow(x,2) + pow((ycl - position), 2));
    			coord n = {0};
    			n = interface_normal (point,f);
    			double theta = atan2(n.y, n.x);
    			fprintf(fp2,"%lf %lf %lf\n", r, kappa[], 180.*theta/pi);
    		}
    	}
    
    	output_facets (f, fp3);
    
    	fclose(fp);
    	fclose(fp2);
    	fclose(fp3);
    	fclose(fp4);
    }