Dynamic Local Grid Refinement and Coarsening

For refining and coarsening a grid locally the dune.fem module provides a functon adapt. The storage of all discrete functions will be automatically resized to accommodate the changes in the grid but the resulting dof vector will not be initialized. To prolong and restrict data from the old to the new grid, the corresponding discrete functions have to be passed to the dune.fem.adapt method:

fem.adapt(u1,u2,...,uN)

The module dune.fem also provides a globalRefine(level,*dfs) method, where a negative level globally coarsens the grid. If discrete functions are passed in they will be prolong (restricted), the dof vectors of all other dof vectors will be resized.

Note

if the underlying storage of a discrete function is stored on the Python side as a numpy array, i.e., vec = uh.as_numpy was called, then access to vec will be undefined after a grid modification since the underlying buffer change will not have been registered.

The module dune.fem provides a function for marking elements for refinement/coarsening:

def mark(indicator, refineTolerance, coarsenTolerance=0,
    minLevel=0, maxLevel=None):

where indicator is a grid function. An element \(T\) is marked for refinement if the value of indicator on \(T\) is greater then refineTolerance and coarsened if the value is less then coarsenTolerance. The element \(T\) is not refined if its level is already at maxLevel and not coarsened if its level it at minLevel. This method can for example be used to refine the grid according to an equal distribution strategy by invoking

dune.fem.mark(indicator, theta/grid.size(0))

where theta is a given tolerance.

A layered Doerfler strategy is also available

def doerflerMark(indicator, theta, maxLevel=None, layered=0.05):

The following two examples showcase adaptivity: the first one using a residual a-posteriori estimator for an elliptic problem, the second one shows adaptivity for a time dependent phase field model for crystal growth. At the end of this section a dual weighted residual approach is used to optimize the grid with respect to the error at a given point. While the first two examples can be implemented completely using the available Python bindings the final example requires using a small C++ snippet which is easy to integrate into the Python code.

Moving Grids

Todo

add some explanation on GridParts

Using C++ Code Snipetts

Todo

add some explanation on algorithms and closeness of Python/C++ interface

Todo

add something on compilerflag setting, e.g., explain

` import dune.generator as generator generator.addToFlags("-DWANT_CACHED_COMM_MANAGER=0",noChecks=True) algorithm(...) generator.setFlags("-g -Wfatal-errors",noChecks=True) algorithm(...) generator.reset() `

… todo:: mention use of ccache and gdb (possibly in section for developers?)

… todo:: mention rmgenerated script

def calcRadius(surface):
    R,vol = 0, 0
    for e in surface.elements:
        rule = geometry.quadratureRule(e.type, 4)
        for p in rule:
            geo = e.geometry
            weight = geo.volume * p.weight
            R   += geo.toGlobal(p.position).two_norm * weight
            vol += weight
    return R/vol
#include <dune/geometry/quadraturerules.hh>

template< class Surface >
double calcRadius( const Surface &surface )
{
  double R = 0.;
  double vol = 0.;
  for( const auto &entity : elements( surface ) )
  {
    const auto& rule = Dune::QuadratureRules<double, 2>::rule(entity.type(), 4);
    for ( const auto &p : rule )
    {
      const auto geo = entity.geometry();
      const double weight = geo.volume() * p.weight();
      R   += geo.global(p.position()).two_norm() * weight;
      vol += weight;
    }
  }
  return R/vol;
}