src/axi.h

    Axisymmetric coordinates

    For problems with a symmetry of revolution around the z-axis of a cylindrical coordinate system. The longitudinal coordinate (z-axis) is x and the radial coordinate (\rho- or r-axis) is y. Note that y (and so Y0) cannot be negative.

    We first define a macro which will be used in some geometry-specific code (e.g. curvature computation).

    #define AXI 1

    On trees we need refinement functions.

    #if TREE
    static void refine_cm_axi (Point point, scalar cm)
    {
    #if !EMBED
      fine(cm,0,0) = fine(cm,1,0) = y - Delta/4.;
      fine(cm,0,1) = fine(cm,1,1) = y + Delta/4.;
    #else // EMBED
      if (cs[] > 0. && cs[] < 1.) {
        coord n = interface_normal (point, cs);
        // Better? involve fs (troubles w prolongation)
        // coord n = facet_normal (point, cs, fs);
        foreach_child() {
          if (cs[] > 0. && cs[] < 1.) {
    	coord p;
        	double alpha = plane_alpha (cs[], n);
    	plane_center (n, alpha, cs[], &p);
    	cm[] = (y + Delta*p.y)*cs[];
          }
          else
    	cm[] = y*cs[];
        }
      }
      else
        foreach_child()
          cm[] = y*cs[];
    #endif // EMBED
    }
    
    static void refine_face_x_axi (Point point, scalar fm)
    {
    #if !EMBED
      if (!is_refined(neighbor(-1))) {
        fine(fm,0,0) = y - Delta/4.;
        fine(fm,0,1) = y + Delta/4.;
      }
      if (!is_refined(neighbor(1)) && neighbor(1).neighbors) {
        fine(fm,2,0) = y - Delta/4.;
        fine(fm,2,1) = y + Delta/4.;
      }
      fine(fm,1,0) = y - Delta/4.;
      fine(fm,1,1) = y + Delta/4.;
    #else // EMBED
      double sig = 0., ff = 0.;
      if (cs[] > 0. && cs[] < 1.) {
        coord n = facet_normal (point, cs, fs);
        sig = sign(n.y)*Delta/4.;
      }
      if (!is_refined(neighbor(-1))) {
        ff = fine(fs.x,0,0);
        fine(fm,0,0) = (y - Delta/4. - sig*(1. - ff))*ff;
        ff = fine(fs.x,0,1);
        fine(fm,0,1) = (y + Delta/4. - sig*(1. - ff))*ff;
      }
      if (!is_refined(neighbor(1)) && neighbor(1).neighbors) {
        ff = fine(fs.x,2,0);
        fine(fm,2,0) = (y - Delta/4. - sig*(1. - ff))*ff;
        ff = fine(fs.x,2,1);
        fine(fm,2,1) = (y + Delta/4. - sig*(1. - ff))*ff;
      }
      ff = fine(fs.x,1,0);
      fine(fm,1,0) = (y - Delta/4. - sig*(1. - ff))*ff;
      ff = fine(fs.x,1,1);
      fine(fm,1,1) = (y + Delta/4. - sig*(1. - ff))*ff;
    #endif // EMBED
    }
    
    static void refine_face_y_axi (Point point, scalar fm)
    {
    #if !EMBED
      if (!is_refined(neighbor(0,-1)))
        fine(fm,0,0) = fine(fm,1,0) = max(y - Delta/2., 1e-20);
      if (!is_refined(neighbor(0,1)) && neighbor(0,1).neighbors)
        fine(fm,0,2) = fine(fm,1,2) = y + Delta/2.;
      fine(fm,0,1) = fine(fm,1,1) = y;
    #else // EMBED
      if (!is_refined(neighbor(0,-1))) {
        fine(fm,0,0) = (max(y - Delta/2., 1e-20))*fine(fs.y,0,0) ;
        fine(fm,1,0) = (max(y - Delta/2., 1e-20))*fine(fs.y,1,0);
      }
      if (!is_refined(neighbor(0,1)) && neighbor(0,1).neighbors) {
        fine(fm,0,2) = (y + Delta/2.)*fine(fs.y,0,2);
        fine(fm,1,2) = (y + Delta/2.)*fine(fs.y,1,2);
      }
      fine(fm,0,1) = y*fine(fs.y,0,1);
      fine(fm,1,1) = y*fine(fs.y,1,1);
    #endif // EMBED
    }
    #endif

    If embedded solids are presents, cm, fm and the fluxes need to be updated consistently with the axisymmetric cylindrical coordinates and the solid fractions.

    #if EMBED
    double axi_factor (Point point, coord p) {
      return (y + p.y*Delta);
    }
    
    void cm_update (scalar cm, scalar cs, face vector fs)
    {
      foreach() {
        if (cs[] > 0. && cs[] < 1.) {
          coord p, n = facet_normal (point, cs, fs);
          double alpha = plane_alpha (cs[], n);
          plane_center (n, alpha, cs[], &p);
          cm[] = (y + Delta*p.y)*cs[];
        }
        else
          cm[] = y*cs[];
      }
      cm[top] = dirichlet(y*cs[]);
      cm[bottom] = dirichlet(y*cs[]);
    }
    
    void fm_update (face vector fm, scalar cs, face vector fs)
    {
      foreach_face(x) {
        double sig = 0.;
        if (cs[] > 0. && cs[] < 1.) {
          coord n = facet_normal (point, cs, fs);
          sig = sign(n.y)*Delta/2.;
        }
        fm.x[] = (y - sig*(1. - fs.x[]))*fs.x[];
      }
      foreach_face(y)
        fm.y[] = max(y, 1e-20)*fs.y[];
      fm.t[top] = dirichlet(y*fs.t[]);
      fm.t[bottom] = dirichlet(y*fs.t[]);
    }
    #endif // EMBED
    
    event metric (i = 0) {

    By default cm is a constant scalar field. To make it variable, we need to allocate a new field. We also move it at the begining of the list of variables: this is important to ensure the metric is defined before other fields.

      if (is_constant(cm)) {
        scalar * l = list_copy (all);
        cm = new scalar;
        free (all);
        all = list_concat ({cm}, l);
        free (l);
      }

    Metric factors must be taken into account for fluxes on embedded boundaries.

    #if EMBED
      metric_embed_factor = axi_factor;
    #endif

    The volume/area of a cell is proportional to r (i.e. y). We need to set boundary conditions at the top and bottom so that cm is interpolated properly when refining/coarsening the mesh.

      scalar cmv = cm;
      foreach()
        cmv[] = y;
      cm[top] = dirichlet(y);
      cm[bottom] = dirichlet(y);

    We do the same for the length scale factors. The “length” of faces on the axis of revolution is zero (y=r=0 on the axis). To avoid division by zero we set it to epsilon (note that mathematically the limit is well posed).

      if (is_constant(fm.x)) {
        scalar * l = list_copy (all);
        fm = new face vector;
        free (all);
        all = list_concat ((scalar *){fm}, l);
        free (l);
      }
      face vector fmv = fm;
      foreach_face()
        fmv.x[] = max(y, 1./HUGE);
      fm.t[top] = dirichlet(y);
      fm.t[bottom] = dirichlet(y);

    We set our refinement/prolongation functions on trees.

    #if TREE
      cm.refine = cm.prolongation = refine_cm_axi;
      fm.x.prolongation = refine_face_x_axi;
      fm.y.prolongation = refine_face_y_axi;
    #endif
    }

    See also

    Usage

    Examples

    Tests