src/atmosphere.h

    #include "utils.h"
    
    face vector u[], un[];
    scalar h[], hn[], zb[];
    
    // Default parameters
    // Coriolis parameter
    double F0 = 1.;
    // acceleration of gravity
    double G = 1.;
    // Viscosity
    double NU = 0.;
    
    trace
    void advection_centered (scalar f, vector u, scalar df)
    {
      foreach()
        df[] = ((f[] + f[-1,0])*u.x[] - 
    	    (f[] + f[1,0])*u.x[1,0] +
    	    (f[] + f[0,-1])*u.y[] - 
    	    (f[] + f[0,1])*u.y[0,1])/(2.*Delta);
    }
    
    trace
    void advection_upwind (scalar f, vector u, scalar df)
    {
      foreach()
        df[] = ((u.x[] < 0. ? f[] : f[-1,0])*u.x[] - 
    	    (u.x[1,0] > 0. ? f[] : f[1,0])*u.x[1,0] +
    	    (u.y[] < 0. ? f[] : f[0,-1])*u.y[] - 
    	    (u.y[0,1] > 0. ? f[] : f[0,1])*u.y[0,1])/Delta;
    }
    
    trace
    double timestep (void)
    {
      double dtmax = DT/CFL;
      dtmax *= dtmax;
      foreach(reduction(min:dtmax)) {
        Delta *= Delta;
        if (h[] > 0.) {
          double dt = Delta/(G*h[]);
          if (dt < dtmax) dtmax = dt;
        }
        foreach_dimension()
          if (u.x[] != 0.) {
    	double dt = Delta/sq(u.x[]);
    	if (dt < dtmax) dtmax = dt;
          }
      }
      return sqrt (dtmax)*CFL;
    }
    
    trace
    void momentum (vector u, scalar h, vector du)
    {
      scalar ke[];
      vertex scalar psi[];
      scalar dux[], dvy[];
      vector d;
      d.x = dux; d.y = dvy;
    
      foreach() {
    #if 1
        ke[] = (sq(u.x[] + u.x[1,0]) + sq(u.y[] + u.y[0,1]))/8.;
    #else
        double uc = u.x[]*u.x[] + u.x[1,0]*u.x[1,0];
        double vc = u.y[]*u.y[] + u.y[0,1]*u.y[0,1];
        ke[] = (uc + vc)/4.;
    #endif
        foreach_dimension()
          d.x[] = (u.x[1,0] - u.x[])/Delta;
      }
      foreach_vertex()
        psi[] = (u.y[] - u.y[-1,0] + u.x[0,-1] - u.x[])/Delta;  
    
      coord f = {1.,-1.};
      foreach_face()
        du.x[] = 
          - (G*(h[] + zb[]) + ke[] - G*(h[-1,0] + zb[-1,0]) - ke[-1,0])/Delta
          + f.x*(((psi[] + psi[0,1])/2. + F0)*
    	     (u.y[] + u.y[0,1] + u.y[-1,0] + u.y[-1,1])/4.)
          + NU*(u.x[0,1] + u.x[0,-1] - 2.*u.x[])/sq(Delta)
          + NU*(d.x[] - d.x[-1,0])/Delta;
    }
    
    trace
    void advance (double t, scalar * f, scalar * df)
    {
      vector u = {f[0], f[1]}, du = {df[0], df[1]};
      scalar h = f[2], dh = df[2];
    
      advection_centered (h, u, dh);
      momentum (u, h, du);
    }
    
    void update (double t, scalar * f)
    {
    }
    
    event defaults (i = 0)
    {
      foreach()
        h[] = 1.;
    }
    
    event init (i = 0)
    {
    }
    
    void run (void)
    {
      init_grid (N);
    
      timer start = timer_start();
      iter = 0, t = 0;
      while (events (true)) {
        double dt = dtnext (timestep ());
    #if 1
        advection_centered (h, u, hn);
        foreach()
          h[] += hn[]*dt;
        momentum (u, h, un);
        foreach_face()
          u.x[] += un.x[]*dt;
    #else /* unstable! */
        scalar f[3] = { u, v, h };
        scalar df[2][3] = {{ un,  vn,  hn },
    		       { un1, vn1, hn1 }};
        runge_kutta (2, t, dt, 3, f, df, advance, update);
    #endif
        iter = inext, t = tnext;
      }
      timer_print (start, iter, 0);
    
      free_grid ();
    }