sandbox/ghigo/src/myviscosity.h

    #include "mypoisson.h"
    
    struct Viscosity {
      vector u;
      face vector mu;
      scalar rho;
      double dt;
      int nrelax;
      scalar * res;
    #if EMBED
      void (* embed_stress_flux) (Point, vector, vector, coord *, coord *);
    #endif // EMBED
    };
    
    #if AXI
    // fixme: RHO here not correct
    # define lambda ((coord){1., 1. + dt/RHO*(mu.x[] + mu.x[1] + \
    					  mu.y[] + mu.y[0,1])/2./sq(y)})
    #else // not AXI
    # if dimension == 1
    #   define lambda ((coord){1.})
    # elif dimension == 2
    #   define lambda ((coord){1.,1.})
    # elif dimension == 3
    #   define lambda ((coord){1.,1.,1.})
    #endif
    #endif
    
    // Temporary placement for tangential face gradients
    
    #ifndef EMBED
    #define face_avg_gradient_t1_x(a,i)				\
      ((a[1,i-1] + a[1,i] - a[-1,i-1] - a[-1,i])/(4.*Delta))
    #define face_avg_gradient_t2_x(a,i) \
      ((a[1,0,i-1] + a[1,0,i] - a[-1,0,i-1] - a[-1,0,i])/(4.*Delta))
    
    #define face_avg_gradient_t1_y(a,i) \
      ((a[i-1,1] + a[i,1] - a[i-1,-1] - a[i,-1])/(4.*Delta))
    #define face_avg_gradient_t2_y(a,i) \
      ((a[0,1,i-1] + a[0,1,i] - a[0,-1,i-1] - a[0,-1,i])/(4.*Delta))
    
    #define face_avg_gradient_t1_z(a,i) \
      ((a[i-1,0,1] + a[i,0,1] - a[i-1,0,-1] - a[i,0,-1])/(4.*Delta))
    #define face_avg_gradient_t2_z(a,i) \
      ((a[0,i-1,1] + a[0,i,1] - a[i-1,0,-1] - a[0,i,-1])/(4.*Delta))
    #endif // EMBED
      
    // Note how the relaxation function uses "naive" gradients i.e. not
    // the face_gradient_* macros.
    
    static void relax_viscosity (scalar * a, scalar * b, int l, void * data)
    {
      struct Viscosity * p = (struct Viscosity *) data;
      (const) face vector mu = p->mu;
      (const) scalar rho = p->rho;
      double dt = p->dt;
      vector u = vector(a[0]), r = vector(b[0]);
    
    #if EMBED
      void (* embed_stress_flux) (Point, vector, vector,
    			      coord *, coord *) = p->embed_stress_flux;
    #endif // EMBED
    
    #if JACOBI
      vector w[];
    #else
      vector w = u;
    #endif
      
      foreach_level_or_leaf (l) {
        coord c = {0., 0., 0.}, d = {0., 0., 0.};
    #if EMBED
        if (embed_stress_flux)
          embed_stress_flux (point, u, mu, &c, &d);
    #endif // EMBED
        foreach_dimension() {
          w.x[] = (dt*(2.*mu.x[1]*u.x[1] + 2.*mu.x[]*u.x[-1]
                   #if dimension > 1
    		   + mu.y[0,1]*(u.x[0,1] +
    				face_avg_gradient_t1_x (u.y, 1)*Delta)
    		   - mu.y[]*(- u.x[0,-1] +
    			     face_avg_gradient_t1_x (u.y, 0)*Delta)
                   #endif
    	       #if dimension > 2
    		   + mu.z[0,0,1]*(u.x[0,0,1] +
    				  face_avg_gradient_t2_x (u.z, 1)*Delta)
    		   - mu.z[]*(- u.x[0,0,-1] +
    			     face_avg_gradient_t2_x (u.z, 0)*Delta)
                   #endif
    		   ) + (r.x[] - dt*c.x)*sq(Delta))/
    	(sq(Delta)*(rho[]*lambda.x + dt*d.x) + dt*(2.*mu.x[1] + 2.*mu.x[]
                                        #if dimension > 1
    						   + mu.y[0,1] + mu.y[]
                                        #endif
    			            #if dimension > 2
    						   + mu.z[0,0,1] + mu.z[]
    			            #endif
    						   ) + SEPS);
        }
      }
    
    #if JACOBI
      foreach_level_or_leaf (l)
        foreach_dimension()
          u.x[] = (u.x[] + 2.*w.x[])/3.;
    #endif
      
    #if TRASH
      vector u1[];
      foreach_level_or_leaf (l)
        foreach_dimension()
          u1.x[] = u.x[];
      trash ({u});
      foreach_level_or_leaf (l)
        foreach_dimension()
          u.x[] = u1.x[];
    #endif
    }
    
    static double residual_viscosity (scalar * a, scalar * b, scalar * resl, 
    				  void * data)
    {
      struct Viscosity * p = (struct Viscosity *) data;
      (const) face vector mu = p->mu;
      (const) scalar rho = p->rho;
      double dt = p->dt;
      vector u = vector(a[0]), r = vector(b[0]), res = vector(resl[0]);
      double maxres = 0.;
    
    #if EMBED
      void (* embed_stress_flux) (Point, vector, vector, coord *, coord *) = p->embed_stress_flux;
    #endif
        
    #if TREE
      /* conservative coarse/fine discretisation (2nd order) */
      foreach_dimension() {
        face vector taux[];
        foreach_face(x)
          taux.x[] = 2.*mu.x[]*face_gradient_x (u.x, 0);
        #if dimension > 1
          foreach_face(y)
    	taux.y[] = mu.y[]*(face_gradient_y (u.x, 0) + 
    			   face_avg_gradient_t1_x (u.y, 0));
        #endif
        #if dimension > 2
          foreach_face(z)
    	taux.z[] = mu.z[]*(face_gradient_z (u.x, 0) + 
    			   face_avg_gradient_t2_x (u.z, 0));
        #endif
        boundary_flux ({taux});
        foreach (reduction(max:maxres)) {
          double a = 0.;
          coord c = {0., 0., 0.}, d = {0., 0., 0.};
    #if EMBED
          if (embed_stress_flux)
    	embed_stress_flux (point, u, mu, &c, &d);
    #endif // EMBED
          foreach_dimension()
    	a += taux.x[1] - taux.x[];
          res.x[] = r.x[] - rho[]*lambda.x*u.x[] + dt*(a/Delta - (c.x + d.x*u.x[]));
          if (fabs (res.x[]) > maxres)
    	maxres = fabs (res.x[]);
        }
      }
      boundary (resl);
    #else
      /* "naive" discretisation (only 1st order on trees) */
      foreach (reduction(max:maxres)) {
        coord c = {0., 0., 0.}, d = {0., 0., 0.};
    #if EMBED
      if (embed_stress_flux)
        embed_stress_flux (point, u, mu, &c, &d);
    #endif // EMBED    
        foreach_dimension() {
          res.x[] = r.x[] - rho[]*lambda.x*u.x[] +
            dt*(2.*mu.x[1,0]*face_gradient_x (u.x, 1)
    	    - 2.*mu.x[]*face_gradient_x (u.x, 0)
            #if dimension > 1
    	    + mu.y[0,1]* (face_gradient_y (u.x, 1) +
    			  face_avg_gradient_t1_x (u.y, 1))
    	    - mu.y[]*(face_gradient_y (u.x, 0) +
    		      face_avg_gradient_t1_x (u.y, 0))
    	#endif
            #if dimension > 2
    	    + mu.z[0,0,1]*(face_gradient_z (u.x, 1) +
    			   face_avg_gradient_t2_x (u.z, 1))
    	    - mu.z[]*(face_gradient_z (u.x, 0) +
    		      face_avg_gradient_t2_x (u.z, 0))
    	#endif
    	    )/Delta - dt*(c.x + d.x*u.x[]);
          if (fabs (res.x[]) > maxres)
    	maxres = fabs (res.x[]);
        }
      }
    #endif
      return maxres;
    }
    
    #undef lambda
    
    double TOLERANCE_MU = 0.; // default to TOLERANCE
    
    trace
    mgstats viscosity (struct Viscosity p)
    {
      vector u = p.u, r[];
      scalar rho = p.rho;  
      foreach()
        foreach_dimension()
          r.x[] = rho[]*u.x[];
    
      face vector mu = p.mu;
      restriction ({mu, rho});
    
    #if EMBED
      p.embed_stress_flux = u.x.boundary[embed] != antisymmetry ? embed_stress_flux : NULL;
    #endif // EMBED
      return mg_solve ((scalar *){u}, (scalar *){r},
    		   residual_viscosity, relax_viscosity, &p, p.nrelax, p.res,
    		   minlevel = 1, // fixme: because of root level
                                     // BGHOSTS = 2 bug on trees
    		   tolerance = TOLERANCE_MU);
    }