sandbox/Antoonvh/adapt_field.h

    A flexible adaptation algorithm

    A special purpose adaptation algorithm. consider using adapt_wavelet() instead.

    struct Adapt_Field {
      scalar f;       // The field with leaf-filled values
      double max;     // refinement criterion
      double min;     // coarseing criterion 
      int maxlevel;   // maximum level of refinement
      int minlevel;   // minimum level of refinement (default 1)
      scalar * list;  // list of fields to update (default all)
    };
    
    astats adapt_field (struct Adapt_Field p);
    
    extern vector u;
    
    struct Adapt_Flow {
      double ue;
      int maxlevel;
      double p;
      double cfac;
    };
    
    attribute {
      void (* interpolant) (Point, scalar);
    }
    
    void wavelet_interpolant (scalar s, scalar w)
    {
      restriction ({s});
      for (int l = grid->maxdepth - 1; l >= 0; l--) {
        foreach_coarse_level (l) {
          foreach_child()
            w[] = s[];
          s.interpolant (point, s);
          foreach_child() {
            double sp = s[];
            s[] = w[];
            /* difference between fine value and its prolongation */
            w[] -= sp;
          }
        }
        boundary_level ({w}, l + 1);
      }
      /* root cell */
      foreach_level(0) 
        w[] = s[];
      boundary_level ({w}, 0);
    }
    
    astats adapt_flow (struct Adapt_Flow pa) {
      double ue = pa.ue;
      int maxlevel = pa.maxlevel;
      double p = pa.p;
      double uec = ue/1.5;
      if (pa.cfac)
        uec = ue/pa.cfac; 
      scalar w[];
      vector wv[];
      foreach_dimension() 
        wavelet_interpolant (u.x, wv.x);
        
      for (int l = 1; l < grid->maxdepth; l++)
        foreach_coarse_level (l) { 
          double maxw = 0.;
          foreach_child() {
    	double a = 0;
    	foreach_dimension()
    	  a += fabs(wv.x[]);
    	maxw = max(maxw, a);
          }
          w[] = maxw;
        }
    #if _MPI
      w.restriction = no_restriction;
      w.prolongation = no_restriction;
      boundary ({w});
    #endif
      for (int l = grid->maxdepth; l > 1; l--)  
        foreach_level(l)  {// 3x3(x3) Gaussian kernel
    #if (dimension == 2)
          w[] = pow(Delta, p)*(1.  * coarse(w,0,0,0)   +
    			   .5  *(coarse(w,1,0,0)   + coarse(w,0,1,0)   +
    				 coarse(w,-1,0,0)  + coarse(w,0,-1,0)) +
    			   0.25*(coarse(w,1,1,0)   + coarse(w,1,-1,0)  +
    				 coarse(w,-1,-1,0) + coarse(w,-1,1,0)))/4.;
    #else //(dimension == 3) 
          w[] = pow(Delta, p)*(1.   * coarse(w,0,0,0)   +
    			   .5   *(coarse(w,1,0,0)   + coarse(w,-1,0,0)  +
    				  coarse(w,0,1,0)   + coarse(w,0,-1,0)  +
    				  coarse(w,0,0,1)   + coarse(w,0,0,-1)) +
    			   0.25 *(coarse(w,1,1,0)   + coarse(w,1,-1,0)  +
    				  coarse(w,-1,-1,0) + coarse(w,-1,1,0)  +
    				  coarse(w,0,1,1)   + coarse(w,0,-1,1)  +
    				  coarse(w,0,-1,-1) + coarse(w,0,1,-1)  +
    				  coarse(w,1,0,1)   + coarse(w,1,0,-1)  +
    				  coarse(w,-1,0,-1) + coarse(w,-1,0,1)) +
    			   0.125*(coarse(w,1,1,1)   + coarse(w,-1,1,1)  +
    				  coarse(w,1,-1,1)  + coarse(w,1,1,-1)  +
    				  coarse(w,-1,-1,1) + coarse(w,-1,1,-1) +
    				  coarse(w,1,-1,-1) + coarse(w,-1,-1,-1)))/8.;
    #endif
        }
      return adapt_field (w, ue, uec, maxlevel);
    }
    
    
    
    struct Adapt_List {
      scalar * list;
      double * ues;
      int maxlevel;
      double p;
      double fac;
    };
    
    astats adapt_list (struct Adapt_List pa) {
      scalar * list = pa.list;
      double * ues = pa.ues;
      int maxlevel = pa.maxlevel;
      double p = pa.p;
      if (!pa.fac)
        pa.fac = 1.5;
      scalar w[], * wl = list_clone (list);
     scalar s, ws;
      for (s,ws in list,wl)
        wavelet (s, ws);
      for (int l = 1; l < depth() - 1; l++)
        foreach_coarse_level (l) { 
          double maxw = 0.;
          foreach_child() {
    	double a = 0;
    	scalar s, ws;
    	NOT_UNUSED(s);
    	int is = 0;
    	for (s, ws in list, wl) {
    	  a += fabs(ws[])/ues[is]; //scale w with ue
    	  is++;
    	}
    	maxw = max(maxw, a);
          }
          w[] = maxw;
        }
    #if _MPI
      w.restriction = no_restriction;
      w.prolongation = no_restriction;
      boundary ({w});
    #endif
      for (int l = depth(); l > 1; l--)  
        foreach_level(l)  {// 3x3(x3) Gaussian kernel
    #if (dimension == 2)
          w[] = pow(Delta, p)*(1.  * coarse(w,0,0,0)   +
    			   .5  *(coarse(w,1,0,0)   + coarse(w,0,1,0)   +
    				 coarse(w,-1,0,0)  + coarse(w,0,-1,0)) +
    			   0.25*(coarse(w,1,1,0)   + coarse(w,1,-1,0)  +
    				 coarse(w,-1,-1,0) + coarse(w,-1,1,0)))/4.;
    #else //(dimension == 3) 
          w[] = pow(Delta, p)*(1.   * coarse(w,0,0,0)   +
    			   .5   *(coarse(w,1,0,0)   + coarse(w,-1,0,0)  +
    				  coarse(w,0,1,0)   + coarse(w,0,-1,0)  +
    				  coarse(w,0,0,1)   + coarse(w,0,0,-1)) +
    			   0.25 *(coarse(w,1,1,0)   + coarse(w,1,-1,0)  +
    				  coarse(w,-1,-1,0) + coarse(w,-1,1,0)  +
    				  coarse(w,0,1,1)   + coarse(w,0,-1,1)  +
    				  coarse(w,0,-1,-1) + coarse(w,0,1,-1)  +
    				  coarse(w,1,0,1)   + coarse(w,1,0,-1)  +
    				  coarse(w,-1,0,-1) + coarse(w,-1,0,1)) +
    			   0.125*(coarse(w,1,1,1)   + coarse(w,-1,1,1)  +
    				  coarse(w,1,-1,1)  + coarse(w,1,1,-1)  +
    				  coarse(w,-1,-1,1) + coarse(w,-1,1,-1) +
    				  coarse(w,1,-1,-1) + coarse(w,-1,-1,-1)))/8.;
    #endif
        }
      return adapt_field (w, 1., 1./pa.fac, maxlevel); //w is already scaled
    }
    
    
    
    trace
    astats adapt_field (struct Adapt_Field p) {
      scalar f = p.f;
      if (p.list == NULL)
        p.list = all;
      scalar * listc = NULL;
      for (scalar s in p.list)
        if (!is_constant(s) && s.restriction != no_restriction)
          listc = list_add (listc, s);
      astats st = {0, 0};
      // refinement
      if (p.minlevel < 1)
        p.minlevel = 1;
      tree->refined.n = 0;
      static const int refined = 1 << user, too_fine = 1 << (user + 1);
      foreach_cell() {
        if (is_active(cell)) {
          static const int too_coarse = 1 << (user + 2);
          if (is_leaf (cell)) {
      	if (cell.flags & too_coarse) {
      	  cell.flags &= ~too_coarse;
      	  refine_cell (point, listc, refined, &tree->refined);
      	  st.nf++;
      	}
      	continue;
          }
          else { // !is_leaf (cell)
      	if (cell.flags & refined) {
      	  // cell has already been refined, skip its children
      	  cell.flags &= ~too_coarse;
      	  continue;
      	}
      	// check whether the cell or any of its children is local
      	bool local = is_local(cell);
      	if (!local)
      	  foreach_child()
      	    if (is_local(cell)) {
      	      local = true;
    	      break;
    	    }
      	if (local) {
      	  static const int just_fine = 1 << (user + 3);
    	  double max = p.max, min = p.min;
    	  foreach_child() {
    	    double e = fabs(f[]);
    	    if (e > max && level < p.maxlevel) {
    	      cell.flags &= ~too_fine;
    	      cell.flags |= too_coarse;
    	    }
    	    else if ((e <= min || level > p.maxlevel) &&
    		     !(cell.flags & (too_coarse|just_fine))) {
    	      if (level >= p.minlevel)
    		cell.flags |= too_fine;
    	    }
    	    else if (!(cell.flags & too_coarse)) {
    	      cell.flags &= ~too_fine;
    	      cell.flags |= just_fine;
    	    }
    	  }
    	  foreach_child() {
      	    cell.flags &= ~just_fine;
      	    if (!is_leaf(cell)) {
      	      cell.flags &= ~too_coarse;
      	      if (level >= p.maxlevel)
      		cell.flags |= too_fine;
      	    }
      	    else if (!is_active(cell))
      	      cell.flags &= ~too_coarse;
      	  }
      	}
          }
        }
        else // inactive cell
          continue;
      }
      mpi_boundary_refine (listc);
      
      // coarsening
      // the loop below is only necessary to ensure symmetry of 2:1 constraint
      for (int l = depth(); l >= 0; l--) {
        foreach_cell()
          if (!is_boundary(cell)) {
      	if (level == l) {
      	  if (!is_leaf(cell)) {
      	    if (cell.flags & refined)
      	      // cell was refined previously, unset the flag
      	      cell.flags &= ~(refined|too_fine);
      	    else if (cell.flags & too_fine) {
      	      if (is_local(cell) && coarsen_cell (point, listc))
      		st.nc++;
      	      cell.flags &= ~too_fine; // do not coarsen parent
      	    }
      	  }
      	  if (cell.flags & too_fine)
      	    cell.flags &= ~too_fine;
      	  else if (level > 0 && (aparent(0).flags & too_fine))
      	    aparent(0).flags &= ~too_fine;
      	  continue;
      	}
      	else if (is_leaf(cell))
      	  continue;
          }
        mpi_boundary_coarsen (l, too_fine);
        }
      free (listc);
      mpi_all_reduce (st.nf, MPI_INT, MPI_SUM);
      mpi_all_reduce (st.nc, MPI_INT, MPI_SUM);
      if (st.nc || st.nf)
        mpi_boundary_update (p.list);
      return st;
    }