sandbox/Antoonvh/ekman.c

    Convergence test forthe ekman spiral using an adaptive grid

    Very similar to the approach we took for the fixed-grid convergence testing, we check the spatial order of convergence of the ‘dynamical-core’ of the single collumn model, i.e. the diffusion solver. We use a one-dimensional bi-tree adaptive grid and the generic timeloop header file together with the aforementioned solver.

    #include "grid/bitree.h"
    #include "run.h"
    #include "diffusion.h"

    For reasons to do with brevity, this page only accentuates the differences in the set-up compared to the fixed-grid-testing approach. If you have any questions regarding the set-up and you have not read the corresponding fixed-grid-test page, than please look there first.

    double ekmanexv (double x){
      return sin(x)*exp(-x);
    }
    
    double ekmanexu (double x){
      return 1-(cos(x)*exp(-x));
    }
    
    double Ekmanvdx (double x){
      return -0.5*exp(-x)*(cos(x)+sin(x));
    }
    
    double Ekmanudx (double x){
      return 0.5*exp(-x)*(2.*exp(x)*x-sin(x)+cos(x));
    }
    
    double solv(double x, double delt){
      double x1 = x-delt/2.;
      double x2 = x+delt/2.; 
      return (Ekmanvdx(x2)-Ekmanvdx(x1))/delt;
    }
    
    double solu(double x, double delt){
      double x1=x-delt/2.;
      double x2=x+delt/2.;
      return (Ekmanudx(x2)-Ekmanudx(x1))/delt;
    }
    
    
    int maxlevel;
    scalar u[],v[];
    const face vector mum[]={0.5};
    int j;
    FILE * fpo;

    The used adaptation algorithm requires an error threshold or refinenent criterion for the velocity components \zeta, that is declared below.

    double zeta;
    
    int main()	
    {
      X0=0.;
      L0=100.;
      fpo = fopen ("overviewagekman","w");

    The calculations on this case are repeated 20 times over so that the maximum grid size and refinement criterion can be reduced iteratively.

      for (j=0;j<20;j++){
        run();
      }
    }	
    
    event init(t=0){
      u[left]=dirichlet(0.);
      v[left]=dirichlet(0.);
      u[right]=dirichlet(ekmanexu(L0));
      v[right]=dirichlet(ekmanexv(L0));

    The grid is initialized with a relatively coarse resolution, employing 32 points. The maximum level is doubled each iteration and the refinement criterion is halved each iteration, starting from 0.1.

      init_grid(1<<(4));
      maxlevel = 5+j;
      zeta = 0.1/pow(2,(double)j);
      dt=0.01;
      DT=0.01;
      foreach(){
        u[]=solu(x,Delta);
        v[]=solv(x,Delta);
      }
      boundary(all);

    Before the run is started, the solution is initialized on a grid that is consistent with the adaptations settings.

      while(adapt_wavelet({u,v},(double []){zeta,zeta},maxlevel).nf){
        foreach(){
          u[]=solu(x,Delta);
          v[]=solv(x,Delta);
        }
        boundary(all);
      }
    }
    
    event Diffusion(i++){
      scalar rx[],ry[];
      foreach(){
        rx[]=v[];
        ry[]=(1.-u[]);
      }
      boundary({ry,rx});
      dt=dtnext(DT);
      diffusion(u,dt,mum,rx);
      diffusion(v,dt,mum,ry);
    }

    The fidelity in the representation of the solution by the grid is evaluated each timestep. The grid is adapted, if necessarry.

    event adapt(i++){
      adapt_wavelet({u,v},(double []){zeta,zeta},maxlevel);
    }

    The details of the solution are evaluated at the end of each `refinement iteration’ and written to a file named; ekmanadaptive.dat.

    event eval(t=(10)){
      static FILE * fp = fopen("ekmanadaptive.dat","w");
      double eta = 0;
      int n = 0;
      foreach(){
        eta+=fabs(u[]-solu(x,Delta))*Delta;
        eta+=fabs(v[]-solv(x,Delta))*Delta;
        n++;
      }
      fprintf(fp,"%d\t%g\t%g\n",n,eta,perf.t);
      fflush(fp);
      scalar wu[], wv[];
      wavelet(u,wu);
      wavelet(v,wv);
      foreach()
        fprintf(fpo,"%g\t%g\t%g\t%g\t%g\t%g\t%g\n",x,Delta,fabs(u[]-solu(x,Delta)),fabs(v[]-solv(x,Delta)),wu[],wv[],zeta);
      fflush(fpo);
    }

    Results

    We can check if everything has gone according to the intended set-up by plotting the number of grid cells and the corresponding error for each iteration.

    set logscale x
    set logscale y
    set xlabel 'Number of grid cells'
    set ylabel 'Total error'
    plot 'ekmanadaptive.dat' u 1:2 w l lw 3 t 'Adaptive' ,\
          x**-2 lw 3 t '{/Symbol \265} N^{-2}'
    (script)

    (script)

    We can conclude that the error (agian) scales inversely propotional to the square of the number of grid cells. We also look at the error vs esitmated error in v:

    set xlabel 'Xsi for v'
    set ylabel 'Error in v'
    set key off
    plot 'overviewagekman' u 4:6 pt 5
    this is (in part) the same data as fig. 2a in the GMD paper (script)

    this is (in part) the same data as fig. 2a in the GMD paper (script)

    We observe a correlation along the 1:1 line. Compared to the plot in the paper, the are additonal scatter points with very low error, I doubt this is due to the newer version of Basilisk. I will look into this…