From 6e0836d14b81f5e2e284967f823e58bc8d46d66f Mon Sep 17 00:00:00 2001
From: Dominic Kempf <dominic.kempf@iwr.uni-heidelberg.de>
Date: Wed, 2 Aug 2017 14:09:50 +0200
Subject: [PATCH] Rewrite driver generation

Do not annotate FiniteElements anymore, further split driver code
---
 .../dune/perftool/pdelab/driver/__init__.py   | 1532 +----------------
 .../perftool/pdelab/driver/constraints.py     |   41 +-
 python/dune/perftool/pdelab/driver/error.py   |  129 +-
 .../pdelab/driver/gridfunctionspace.py        |   57 +-
 .../perftool/pdelab/driver/gridoperator.py    |    9 +-
 .../perftool/pdelab/driver/instationary.py    |   60 +-
 .../perftool/pdelab/driver/interpolate.py     |   24 +-
 python/dune/perftool/pdelab/driver/solve.py   |   14 +-
 python/dune/perftool/pdelab/driver/vtk.py     |   19 +-
 9 files changed, 197 insertions(+), 1688 deletions(-)

diff --git a/python/dune/perftool/pdelab/driver/__init__.py b/python/dune/perftool/pdelab/driver/__init__.py
index 47603d74..e246e55e 100644
--- a/python/dune/perftool/pdelab/driver/__init__.py
+++ b/python/dune/perftool/pdelab/driver/__init__.py
@@ -47,6 +47,10 @@ def get_dimension():
     return _driver_data['form'].ufl_cell().geometric_dimension()
 
 
+def get_cell():
+    return _driver_data['form'].ufl_cell().cellname()
+
+
 def get_test_element():
     return _driver_data['form'].arguments()[0].ufl_element()
 
@@ -70,29 +74,8 @@ def form_name_suffix(name, formdata):
     return name + '_' + form_name
 
 
-def has_constraints(element):
-    from ufl import MixedElement, VectorElement
-    if isinstance(element, MixedElement) and not isinstance(element, VectorElement):
-        return any(has_constraints(el) for el in element.sub_elements())
-    return hasattr(element, "dirichlet_constraints")
-
-
-# Those symbol generators that depend on the meta data we hacked into
-# the ufl.FiniteElement should use fem_metadata_dependent_symbol instead of symbol.
-def get_constraints_metadata(element):
-    """
-    Normally, we suppress the constraints information on a finite element.
-    However, we might want to use it explicitly in those case where it matters
-    This function does the job!
-    """
-    dc = getattr(element, 'dirichlet_constraints', None)
-    de = getattr(element, 'dirichlet_expression', None)
-    return (element, (dc, de))
-
-
-fem_metadata_dependent_symbol = generator_factory(item_tags=("symbol",),
-                                                  cache_key_generator=get_constraints_metadata,
-                                                  )
+def get_object(name):
+    return _driver_data['data'].object_by_name.get(name, None)
 
 
 def mass_form_index(formdatas, data):
@@ -104,8 +87,9 @@ def mass_form_index(formdatas, data):
             continue
 
 
-def is_linear(form):
-    '''Test if form is linear in test function'''
+def is_linear():
+    '''Test if form is linear in trial function'''
+    form = get_formdata().original_form
     from ufl import derivative
     from ufl.algorithms import expand_derivatives
     jacform = expand_derivatives(derivative(form, form.coefficients()[0]))
@@ -120,20 +104,26 @@ def isLagrange(fem):
     return fem._short_name is 'CG'
 
 
-def isSimplical(fem):
-    return any(fem._cell._cellname in x for x in ["triangle", "tetrahedron"])
+def isSimplical(cell):
+    # Cells can be identified through strings *or* ufl objects
+    if not isinstance(cell, str):
+        cell = cell.cellname()
+    return cell in ["vertex", "interval", "triangle", "tetrahedron"]
 
 
-def isQuadrilateral(fem):
-    return any(fem._cell._cellname in x for x in ["vertex", "interval", "quadrilateral", "hexahedron"])
+def isQuadrilateral(cell):
+    # Cells can be identified through strings *or* ufl objects
+    if not isinstance(cell, str):
+        cell = cell.cellname()
+    return cell in ["vertex", "interval", "quadrilateral", "hexahedron"]
 
 
 def isPk(fem):
-    return isLagrange(fem) and isSimplical(fem)
+    return isLagrange(fem) and isSimplical(fem.cell())
 
 
 def isQk(fem):
-    return isLagrange(fem) and isQuadrilateral(fem)
+    return isLagrange(fem) and isQuadrilateral(fem.cell())
 
 
 def isDG(fem):
@@ -164,6 +154,40 @@ def FEM_name_mangling(fem):
     raise NotImplementedError("FEM NAME MANGLING")
 
 
+def _flatten_list(l):
+    if isinstance(l, (tuple, list)):
+        for i in l:
+            for ni in _flatten_list(i):
+                yield ni
+    else:
+        yield l
+
+
+def preprocess_leaf_data(element, data):
+    data = get_object(data)
+    from ufl import MixedElement
+    if isinstance(element, MixedElement):
+        # Dirichlet is None -> no dirichlet boundaries
+        if data is None:
+            return (0,) * element.value_size()
+        # Dirichlet for MixedElement is not iterable -> Same
+        # constraint on all the leafs.
+        elif not isinstance(data, (tuple, list)):
+            return (data,) * element.value_size()
+        # List sizes do not match -> flatten list
+        elif len(data) != element.value_size():
+            flattened = [i for i in _flatten_list(data)]
+            assert len(flattened) == element.value_size()
+            return flattened
+    else:
+        # Do not return lists for non-MixedElement
+        if not isinstance(data, (tuple, list)):
+            return (data,)
+        else:
+            assert len(data) == 1
+            return data
+
+
 def name_inifile():
     # TODO pass some other option here.
     return "argv[1]"
@@ -183,984 +207,6 @@ def name_initree():
     return "initree"
 
 
-@preamble
-def define_dimension(name):
-    return "static const int {} = {};".format(name, get_dimension())
-
-
-def name_dimension():
-    define_dimension("dim")
-    return "dim"
-
-
-@preamble
-def typedef_grid(name):
-    dim = name_dimension()
-    if any(_driver_data['form'].ufl_cell().cellname() in x for x in ["vertex", "interval", "quadrilateral", "hexahedron"]):
-        # For Yasp Grids the jacobi of the transformation is diagonal and constant on each cell
-        from dune.perftool.options import set_option
-        set_option('diagonal_transformation_matrix', True)
-        set_option('constant_transformation_matrix', True)
-
-        range_type = type_range()
-        gridt = "Dune::YaspGrid<{}, Dune::EquidistantCoordinates<{},dim>>".format(dim, range_type)
-        include_file("dune/grid/yaspgrid.hh", filetag="driver")
-    else:
-        if any(_driver_data['form'].ufl_cell().cellname() in x for x in ["triangle", "tetrahedron"]):
-            # gridt = "Dune::UGGrid<{}>".format(dim)
-            # include_file("dune/grid/uggrid.hh", filetag="driver")
-            gridt = "Dune::ALUGrid<{}, {}, Dune::simplex, Dune::conforming>".format(dim, dim)
-            include_file("dune/alugrid/grid.hh", filetag="driver")
-        else:
-            raise PerftoolCodegenError("Cant match your geometry with a DUNE grid. Please report bug.")
-    return "using {} = {};".format(name, gridt)
-
-
-def type_grid():
-    typedef_grid("Grid")
-    return "Grid"
-
-
-@preamble
-def define_grid(name):
-    include_file("dune/testtools/gridconstruction.hh", filetag="driver")
-    ini = name_initree()
-    _type = type_grid()
-    return ["IniGridFactory<{}> factory({});".format(_type, ini),
-            "std::shared_ptr<{}> grid = factory.getGrid();".format(_type)]
-
-
-def name_grid():
-    define_grid("grid")
-    return "grid"
-
-
-@preamble
-def typedef_leafview(name):
-    grid = type_grid()
-    return "using {} = {}::LeafGridView;".format(name, grid)
-
-
-def type_leafview():
-    typedef_leafview("GV")
-    return "GV"
-
-
-@preamble
-def define_leafview(name):
-    _type = type_leafview()
-    grid = name_grid()
-    return "{} {} = {}->leafGridView();".format(_type, name, grid)
-
-
-def name_leafview():
-    define_leafview("gv")
-    return "gv"
-
-
-@preamble
-def typedef_vtkwriter(name):
-    include_file("dune/grid/io/file/vtk/subsamplingvtkwriter.hh", filetag="driver")
-    gv = type_leafview()
-    return "using {} = Dune::SubsamplingVTKWriter<{}>;".format(name, gv)
-
-
-def type_vtkwriter():
-    typedef_vtkwriter("VTKWriter")
-    return "VTKWriter"
-
-
-@preamble
-def define_subsamplinglevel(name):
-    ini = name_initree()
-    return "int {} = {}.get<int>(\"vtk.subsamplinglevel\", 0);".format(name, ini)
-
-
-def name_subsamplinglevel():
-    define_subsamplinglevel("sublevel")
-    return "sublevel"
-
-
-@preamble
-def define_vtkwriter(name):
-    _type = type_vtkwriter()
-    gv = name_leafview()
-    subsamp = name_subsamplinglevel()
-    return "{} {}({}, {});".format(_type, name, gv, subsamp)
-
-
-def name_vtkwriter():
-    define_vtkwriter("vtkwriter")
-    return "vtkwriter"
-
-
-@preamble
-def typedef_domainfield(name):
-    gridt = type_grid()
-    return "using {} = {}::ctype;".format(name, gridt)
-
-
-def type_domainfield():
-    typedef_domainfield("DF")
-    return "DF"
-
-
-@preamble
-def typedef_range(name):
-    if get_option('opcounter'):
-        from dune.perftool.pdelab.driver.timings import setup_timer
-        setup_timer()
-        return "using {} = oc::OpCounter<double>;".format(name)
-    else:
-        return "using {} = double;".format(name)
-
-
-def type_range():
-    typedef_range("RangeType")
-    return "RangeType"
-
-
-@preamble
-def typedef_fem(expr, name):
-    gv = type_leafview()
-    df = type_domainfield()
-    r = type_range()
-    dim = name_dimension()
-    if isPk(expr):
-        include_file("dune/pdelab/finiteelementmap/pkfem.hh", filetag="driver")
-        return "using {} = Dune::PDELab::PkLocalFiniteElementMap<{}, {}, {}, {}>;".format(name, gv, df, r, expr._degree)
-    if isQk(expr):
-        include_file("dune/pdelab/finiteelementmap/qkfem.hh", filetag="driver")
-        return "using {} = Dune::PDELab::QkLocalFiniteElementMap<{}, {}, {}, {}>;".format(name, gv, df, r, expr._degree)
-    if isDG(expr):
-        if isQuadrilateral(expr):
-            include_file("dune/pdelab/finiteelementmap/qkdg.hh", filetag="driver")
-            # TODO allow switching the basis here!
-            return "using {} = Dune::PDELab::QkDGLocalFiniteElementMap<{}, {}, {}, {}>;".format(name, df, r, expr._degree, dim)
-        if isSimplical(expr):
-            include_file("dune/pdelab/finiteelementmap/opbfem.hh", filetag="driver")
-            return "using {} = Dune::PDELab::OPBLocalFiniteElementMap<{}, {}, {}, {}, Dune::GeometryType::simplex>;".format(name, df, r, expr._degree, dim)
-        raise NotImplementedError("Geometry type not known in code generation")
-
-    raise NotImplementedError("FEM not implemented in dune-perftool")
-
-
-def type_fem(expr):
-    name = "{}_FEM".format(FEM_name_mangling(expr).upper())
-    typedef_fem(expr, name)
-    return name
-
-
-@preamble
-def define_fem(expr, name):
-    femtype = type_fem(expr)
-    if isDG(expr):
-        return "{} {};".format(femtype, name)
-    else:
-        gv = name_leafview()
-        return "{} {}({});".format(femtype, name, gv)
-
-
-def name_fem(expr):
-    name = "{}_fem".format(FEM_name_mangling(expr).lower())
-    define_fem(expr, name)
-    return name
-
-
-@preamble
-def define_blocksize(name, expr):
-    assert isDG(expr)
-    assert isQuadrilateral(expr)
-    dimension = name_dimension()
-    degree = expr._degree
-    return "static const int {} = Dune::QkStuff::QkSize<{}, {}>::value;".format(name, degree, dimension)
-
-
-def name_blocksize(expr):
-    name = "blocksize"
-    define_blocksize(name, expr)
-    return name
-
-
-@preamble
-def typedef_vectorbackend(name, expr):
-    include_file("dune/pdelab/backend/istl.hh", filetag="driver")
-    if get_option("fastdg"):
-        blocksize = name_blocksize(expr)
-        return "using {} = Dune::PDELab::istl::VectorBackend<Dune::PDELab::istl::Blocking::fixed, {}>;".format(name, blocksize)
-    else:
-        return "using {} = Dune::PDELab::istl::VectorBackend<Dune::PDELab::istl::Blocking::none, 1>;".format(name)
-
-
-def type_vectorbackend(expr):
-    name = "VectorBackend"
-    typedef_vectorbackend(name, expr)
-    return name
-
-
-def type_orderingtag():
-    return "Dune::PDELab::LexicographicOrderingTag"
-
-
-@preamble
-def typedef_dirichlet_constraintsassembler(name):
-    include_file("dune/pdelab/constraints/conforming.hh", filetag="driver")
-    return "using {} = Dune::PDELab::ConformingDirichletConstraints;".format(name)
-
-
-@preamble
-def typedef_no_constraintsassembler(name):
-    return "using {} = Dune::PDELab::NoConstraints;".format(name)
-
-
-def type_constraintsassembler(dirichlet):
-    if dirichlet[1]:
-        typedef_dirichlet_constraintsassembler("DirichletConstraintsAssember")
-        return "DirichletConstraintsAssember"
-    else:
-        typedef_no_constraintsassembler("NoConstraintsAssembler")
-        return "NoConstraintsAssembler"
-
-
-@preamble
-def typedef_constraintscontainer(element, name):
-    gfs = type_gfs(element)
-    r = type_range()
-    return "using {} = {}::ConstraintsContainer<{}>::Type;".format(name, gfs, r)
-
-
-def type_constraintscontainer(element):
-    name = "{}_cc".format(FEM_name_mangling(element)).upper()
-    typedef_constraintscontainer(element, name)
-    return name
-
-
-@preamble
-def define_constraintscontainer(expr, name):
-    cctype = type_constraintscontainer(expr)
-    return ["{} {};".format(cctype, name), "{}.clear();".format(name)]
-
-
-# TODO this does not yet fully support having same elements with different constraints!
-@fem_metadata_dependent_symbol
-def name_constraintscontainer(expr):
-    name = "{}{}_cc".format(FEM_name_mangling(expr), "_dirichlet" if has_constraints(expr) else "").lower()
-    define_constraintscontainer(expr, name)
-    return name
-
-
-@preamble
-def define_intersection_lambda(expression, name):
-    from dune.perftool.ufl.execution import Expression
-    from ufl.classes import Expr
-    if expression is None:
-        return "auto {} = [&](const auto& x){{ return 0.0; }};".format(name)
-    elif isinstance(expression, Expression):
-        if expression.is_global:
-            return "auto {} = [&](const auto& x){{ {} }};".format(name, expression.c_expr[0])
-        else:
-            return "auto {} = [&](const auto& is, const auto& x){{ {} }};".format(name, expression.c_expr[0])
-    elif isinstance(expression, Expr):
-        # Set up a visitor
-        with global_context(integral_type="exterior_facet", formdata=_driver_data["formdata"], driver=True):
-            from dune.perftool.ufl.visitor import UFL2LoopyVisitor
-            from dune.perftool.pdelab import PDELabInterface
-            visitor = UFL2LoopyVisitor(PDELabInterface(), "exterior_facet", {})
-            from pymbolic.mapper.c_code import CCodeMapper
-            ccm = CCodeMapper()
-            expr = visitor(expression)
-            return "auto {} = [&](const auto& x){{ return {}; }};".format(name, ccm(expr))
-
-    raise ValueError("Expression not understood")
-
-
-def name_bctype_lambda(name, dirichlet):
-    name = name + "_lambda"
-    define_intersection_lambda(dirichlet, name)
-    return name
-
-
-@preamble
-def define_bctype_function(dirichlet, name):
-    gv = name_leafview()
-    bctype_lambda = name_bctype_lambda(name, dirichlet)
-    include_file('dune/pdelab/function/callableadapter.hh', filetag='driver')
-    return "auto {} = Dune::PDELab::makeBoundaryConditionFromCallable({}, {});".format(name,
-                                                                                       gv,
-                                                                                       bctype_lambda,
-                                                                                       )
-
-
-@preamble
-def define_powergfs_constraints(name, child, dim):
-    include_file('dune/pdelab/constraints/common/constraintsparameters.hh', filetag='driver')
-    return "Dune::PDELab::PowerConstraintsParameters<decltype({}), {}> {}({});".format(child, dim, name, child)
-
-
-@preamble
-def define_compositegfs_constraints(name, *children):
-    include_file('dune/pdelab/constraints/common/constraintsparameters.hh', filetag='driver')
-    return "Dune::PDELab::CompositeConstraintsParameters<{}> {}({});".format(', '.join('decltype({})'.format(c) for c in children),
-                                                                             name,
-                                                                             ', '.join(c for c in children)
-                                                                             )
-
-
-@cached
-def name_bctype_function(expr):
-    from ufl import MixedElement, VectorElement, TensorElement
-    if isinstance(expr, (VectorElement, TensorElement)):
-        element, (dirichlet, _) = get_constraints_metadata(expr)
-        # get the correct name from the corresponding UFL file
-        from dune.perftool.generation import get_global_context_value
-        name = get_global_context_value("data").object_names.get(id(dirichlet), "everywhere")
-        define_bctype_function(dirichlet, name)
-        pgfs_name = '{}_{}'.format(name, expr.num_sub_elements())
-        define_powergfs_constraints(pgfs_name, name, expr.num_sub_elements())
-        return pgfs_name
-    if isinstance(expr, MixedElement):
-        children = tuple(name_bctype_function(el) for el in expr.sub_elements())
-        name = '_'.join(children)
-        define_compositegfs_constraints(name, *children)
-        return name
-
-    # So, this seems to be a leaf!
-    element, (dirichlet, _) = get_constraints_metadata(expr)
-
-    # get the correct name from the corresponding UFL file
-    from dune.perftool.generation import get_global_context_value
-    name = get_global_context_value("data").object_names.get(id(dirichlet), "everywhere")
-
-    define_bctype_function(dirichlet, name)
-    return name
-
-
-@preamble
-def assemble_constraints(name, expr):
-    bctype_function = name_bctype_function(expr)
-    gfs = name_gfs(expr)
-    return "Dune::PDELab::constraints({}, {}, {});".format(bctype_function,
-                                                           gfs,
-                                                           name,
-                                                           )
-
-
-def name_assembled_constraints(expr):
-    name = name_constraintscontainer(expr)
-    if has_constraints(expr):
-        assemble_constraints(name, expr)
-    return name
-
-
-@preamble
-def typedef_gfs(element, dirichlet, name):
-    vb = type_vectorbackend(element)
-    from ufl import FiniteElement, MixedElement, VectorElement, EnrichedElement, RestrictedElement, TensorElement
-    if isinstance(element, FiniteElement):
-        gv = type_leafview()
-        fem = type_fem(element)
-        cass = type_constraintsassembler(dirichlet)
-        return "using {} = Dune::PDELab::GridFunctionSpace<{}, {}, {}, {}>;".format(name, gv, fem, cass, vb)
-    if isinstance(element, (VectorElement, TensorElement)):
-        include_file("dune/pdelab/gridfunctionspace/vectorgridfunctionspace.hh", filetag="driver")
-        gv = type_leafview()
-        fem = type_fem(element.sub_elements()[0])
-        # TODO implement symmetry here
-        dim = element.num_sub_elements()
-        cass = type_constraintsassembler(dirichlet)
-        return "using {} = Dune::PDELab::VectorGridFunctionSpace<{}, {}, {}, {}, {}, {}>;".format(name, gv, fem, dim, vb, vb, cass)
-    if isinstance(element, MixedElement):
-        ot = type_orderingtag()
-        args = ", ".join(type_gfs(e) for e in element.sub_elements())
-        return "using {} = Dune::PDELab::CompositeGridFunctionSpace<{}, {}, {}>;".format(name, vb, ot, args)
-    if isinstance(element, EnrichedElement):
-        raise NotImplementedError("Dune does not support enriched elements!")
-    if isinstance(element, RestrictedElement):
-        raise NotImplementedError("Dune does not support restricted elements!")
-
-
-@fem_metadata_dependent_symbol
-def type_gfs(expr):
-    element, dirichlet = get_constraints_metadata(expr)
-    name = "{}{}_gfs".format(FEM_name_mangling(element), "_dirichlet" if dirichlet else "").upper()
-    typedef_gfs(element, dirichlet, name)
-    return name
-
-
-@preamble
-def define_gfs(element, dirichlet, name):
-    gfstype = type_gfs(element)
-    from ufl import FiniteElement, MixedElement, VectorElement, EnrichedElement, RestrictedElement, TensorElement
-    if isinstance(element, FiniteElement):
-        gv = name_leafview()
-        fem = name_fem(element)
-        return "{} {}({}, {});".format(gfstype, name, gv, fem)
-    if isinstance(element, (VectorElement, TensorElement)):
-        gv = name_leafview()
-        fem = name_fem(element.sub_elements()[0])
-        return "{} {}({}, {});".format(gfstype, name, gv, fem)
-    if isinstance(element, MixedElement):
-        args = ", ".join(name_gfs(childgfs) for childgfs in element.sub_elements())
-        return "{} {}({});".format(gfstype, name, args)
-    raise NotImplementedError("Dune does not support this type of finite element!")
-
-
-@fem_metadata_dependent_symbol
-def name_gfs(expr):
-    element, dirichlet = get_constraints_metadata(expr)
-    name = "{}{}_gfs".format(FEM_name_mangling(element), "_dirichlet" if dirichlet else "").lower()
-    define_gfs(element, dirichlet, name)
-    return name
-
-
-@preamble
-def define_dofestimate(name):
-    # Provide a worstcase estimate for the number of entries per row based on the given gridfunction space and cell geometry
-    if isQuadrilateral(get_trial_element()):
-        geo_factor = "4"
-    else:
-        geo_factor = "6"
-    gfs = name_gfs(get_trial_element())
-    ini = name_initree()
-
-    # Assure that gfs in initialized
-    formdata = _driver_data['formdata']
-    x = name_vector(formdata)
-    define_vector(x, formdata)
-
-    return ["int generic_dof_estimate =  {} * {}.maxLocalSize();".format(geo_factor, gfs),
-            "int {} = {}.get<int>(\"istl.number_of_nnz\", generic_dof_estimate);".format(name, ini)]
-
-
-def name_dofestimate():
-    define_dofestimate("dofestimate")
-    return "dofestimate"
-
-
-@preamble
-def typedef_matrixbackend(name):
-    include_file("dune/pdelab/backend/istl.hh", filetag="driver")
-    return "using {} = Dune::PDELab::istl::BCRSMatrixBackend<>;".format(name)
-
-
-def type_matrixbackend():
-    typedef_matrixbackend("MatrixBackend")
-    return "MatrixBackend"
-
-
-@preamble
-def define_matrixbackend(name):
-    mbtype = type_matrixbackend()
-    dof = name_dofestimate()
-    return "{} {}({});".format(mbtype, name, dof)
-
-
-def name_matrixbackend():
-    define_matrixbackend("mb")
-    return "mb"
-
-
-def type_parameters(formdata):
-    from dune.perftool.generation import get_global_context_value
-    data = get_global_context_value("data")
-    from dune.perftool.pdelab.parameter import parameterclass_basename
-    name = parameterclass_basename(formdata, data)
-    return name
-
-
-@preamble
-def define_parameters(name, formdata):
-    partype = type_parameters(formdata)
-    return "{} {};".format(partype, name)
-
-
-def name_parameters(formdata):
-    name = form_name_suffix("params", formdata)
-    define_parameters(name, formdata)
-    return name
-
-
-@preamble
-def typedef_localoperator(name, formdata):
-    # No Parameter class here, yet
-    # params = type_parameters()
-    # return "using {} = LocalOperator<{}>;".format(name, params)
-    ugfs = type_gfs(get_trial_element())
-    vgfs = type_gfs(get_test_element())
-    from dune.perftool.generation import get_global_context_value
-    data = get_global_context_value("data")
-    filename = get_option("operator_file")
-    include_file(filename, filetag="driver")
-    from dune.perftool.pdelab.localoperator import localoperator_basename
-    lopname = localoperator_basename(formdata, data)
-    range_type = type_range()
-    return "using {} = {}<{}, {}, {}>;".format(name, lopname, ugfs, vgfs, range_type)
-
-
-def type_localoperator(formdata):
-    name = form_name_suffix("LOP", formdata).upper()
-    typedef_localoperator(name, formdata)
-    return name
-
-
-@preamble
-def define_localoperator(name, formdata):
-    loptype = type_localoperator(formdata)
-    ini = name_initree()
-    params = name_parameters(formdata)
-    return "{} {}({}, {});".format(loptype, name, ini, params)
-
-
-def name_localoperator(formdata):
-    name = form_name_suffix("lop", formdata)
-    define_localoperator(name, formdata)
-    return name
-
-
-@preamble
-def typedef_gridoperator(name, formdata):
-    ugfs = type_gfs(get_trial_element())
-    vgfs = type_gfs(get_test_element())
-    lop = type_localoperator(formdata)
-    ucc = type_constraintscontainer(get_trial_element())
-    vcc = type_constraintscontainer(get_test_element())
-    mb = type_matrixbackend()
-    df = type_domainfield()
-    r = type_range()
-    if get_option("fastdg"):
-        if not get_option("sumfact"):
-            raise PerftoolCodegenError("FastDGGridOperator is only implemented for sumfactorization.")
-        include_file("dune/pdelab/gridoperator/fastdg.hh", filetag="driver")
-        return "using {} = Dune::PDELab::FastDGGridOperator<{}, {}, {}, {}, {}, {}, {}, {}, {}>;".format(name, ugfs, vgfs, lop, mb, df, r, r, ucc, vcc)
-    else:
-        include_file("dune/pdelab/gridoperator/gridoperator.hh", filetag="driver")
-        return "using {} = Dune::PDELab::GridOperator<{}, {}, {}, {}, {}, {}, {}, {}, {}>;".format(name, ugfs, vgfs, lop, mb, df, r, r, ucc, vcc)
-
-
-def type_gridoperator(formdata):
-    name = form_name_suffix("GO", formdata).upper()
-    typedef_gridoperator(name, formdata)
-    return name
-
-
-@preamble
-def define_gridoperator(name, formdata):
-    gotype = type_gridoperator(formdata)
-    # TODO use formdata insteat of _driver_data object
-    ugfs = name_gfs(get_trial_element())
-    ucc = name_assembled_constraints(get_trial_element())
-    vgfs = name_gfs(get_test_element())
-    vcc = name_assembled_constraints(get_test_element())
-    lop = name_localoperator(formdata)
-    mb = name_matrixbackend()
-    return ["{} {}({}, {}, {}, {}, {}, {});".format(gotype, name, ugfs, ucc, vgfs, vcc, lop, mb),
-            "std::cout << \"gfs with \" << {}.size() << \" dofs generated  \"<< std::endl;".format(ugfs),
-            "std::cout << \"cc with \" << {}.size() << \" dofs generated  \"<< std::endl;".format(ucc)]
-
-
-def name_gridoperator(formdata):
-    name = form_name_suffix("go", formdata)
-    define_gridoperator(name, formdata)
-    return name
-
-
-@preamble
-def typedef_vector(name, formdata):
-    go_type = type_gridoperator(formdata)
-    return "using {} = {}::Traits::Domain;".format(name, go_type)
-
-
-def type_vector(formdata):
-    name = form_name_suffix("V", formdata).upper()
-    typedef_vector(name, formdata)
-    return name
-
-
-@preamble
-def define_vector(name, formdata):
-    vtype = type_vector(formdata)
-    gfs = name_gfs(get_trial_element())
-    return ["{} {}({});".format(vtype, name, gfs), "{} = 0.0;".format(name)]
-
-
-@preamble
-def define_boundary_lambda(boundary, name):
-    from dune.perftool.ufl.execution import Expression
-    from ufl.classes import Expr
-    if boundary is None:
-        return "auto {} = [&](const auto& x){{ return 0.0; }};".format(name)
-    elif isinstance(boundary, Expression):
-        if boundary.is_global:
-            return "auto {} = [&](const auto& x){{ {} }};".format(name, boundary.c_expr[0])
-        else:
-            return "auto {} = [&](const auto& e, const auto& x){{ {} }};".format(name, boundary.c_expr[0])
-    elif isinstance(boundary, Expr):
-        # Set up a visitor
-        with global_context(integral_type="exterior_facet", formdata=_driver_data["formdata"], driver=True):
-            from dune.perftool.ufl.visitor import UFL2LoopyVisitor
-            from dune.perftool.pdelab import PDELabInterface
-            visitor = UFL2LoopyVisitor(PDELabInterface(), "exterior_facet", {})
-            from dune.perftool.loopy.target import numpy_to_cpp_dtype
-            return "auto {} = [&](const auto& x){{ return ({}){}; }};".format(name,
-                                                                              numpy_to_cpp_dtype("float64"),
-                                                                              visitor(boundary))
-
-    raise ValueError("Expression not understood")
-
-
-def name_boundary_lambda(boundary, name):
-    define_boundary_lambda(boundary, name + "lambda")
-    return name + "lambda"
-
-
-@preamble
-def define_boundary_function(boundary, name):
-    gv = name_leafview()
-    lambdaname = name_boundary_lambda(boundary, name)
-    include_file('dune/pdelab/function/callableadapter.hh', filetag='driver')
-    if is_stationary():
-        return "auto {} = Dune::PDELab::makeGridFunctionFromCallable({}, {});".format(name,
-                                                                                      gv,
-                                                                                      lambdaname,
-                                                                                      )
-    else:
-        params = name_parameters(_driver_data['formdata'])
-        return "auto {} = Dune::PDELab::makeInstationaryGridFunctionFromCallable({}, {}, {});".format(name,
-                                                                                                      gv,
-                                                                                                      lambdaname,
-                                                                                                      params)
-
-
-@preamble
-def define_compositegfs_parameterfunction(name, *children):
-    return "Dune::PDELab::CompositeGridFunction<{}> {}({});".format(', '.join('decltype({})'.format(c) for c in children),
-                                                                    name,
-                                                                    ', '.join(children))
-
-
-def expression_splitter(expr, length):
-    if expr is None:
-        return (None,) * length
-    else:
-        from dune.perftool.ufl.execution import Expression, split_expression
-        from ufl.classes import ListTensor
-        if isinstance(expr, Expression):
-            return split_expression(expr)
-        elif isinstance(expr, ListTensor):
-            return expr.ufl_operands
-
-        raise TypeError("No idea how to split {} in components".format(type(expr)))
-
-
-@cached
-def _name_boundary_function(element, boundary, name=None):
-    from ufl import MixedElement, VectorElement, TensorElement
-    if isinstance(element, (VectorElement, TensorElement)):
-        from dune.perftool.generation import get_global_context_value
-        basename = get_global_context_value("data").object_names.get(id(boundary), "veczero")
-        children = tuple(_name_boundary_function(el, exp, basename + '_' + str(i)) for el, exp, i in zip(element.sub_elements(), expression_splitter(boundary, element.num_sub_elements()), range(element.num_sub_elements())))
-        define_compositegfs_parameterfunction(basename, *children)
-        return basename
-    if isinstance(element, MixedElement):
-        children = tuple(name_boundary_function(el) for el in element.sub_elements())
-        name = '_'.join(children)
-        define_compositegfs_parameterfunction(name, *children)
-        return name
-
-    from dune.perftool.generation import get_global_context_value
-    if name is None:
-        name = get_global_context_value("data").object_names.get(id(boundary), "zero")
-
-    define_boundary_function(boundary, name)
-    return name
-
-
-def name_boundary_function(expr):
-    # This is a scalar leaf of the ansatz function tree
-    element, (_, boundary) = get_constraints_metadata(expr)
-
-    return _name_boundary_function(element, boundary)
-
-
-@cached
-def name_solution_function(tree_path=()):
-    from dune.perftool.generation import get_global_context_value
-    expr = get_global_context_value("data").object_by_name[get_option("exact_solution_expression")]
-
-    from dune.perftool.ufl.execution import Expression, split_expression
-    from ufl.classes import ListTensor
-    for i in tree_path:
-        if isinstance(expr, Expression):
-            expr = split_expression(expr)[int(i)]
-        elif isinstance(expr, tuple):
-            expr = expr[int(i)]
-        elif isinstance(expr, ListTensor):
-            expr = expr.ufl_operands[int(i)]
-        else:
-            raise TypeError("No idea how to split {}".format(type(expr)))
-
-    from dune.perftool.generation import get_global_context_value
-    try:
-        name = get_global_context_value("data").object_names[id(expr)]
-    except KeyError:
-        from dune.perftool.generation import get_counter
-        name = 'generic_{}'.format(get_counter('__generic'))
-
-    define_boundary_function(expr, name)
-
-    return name
-
-
-@preamble
-def interpolate_vector(name, formdata):
-    define_vector(name, formdata)
-    element = get_trial_element()
-    bf = name_boundary_function(element)
-    gfs = name_gfs(element)
-    return "Dune::PDELab::interpolate({}, {}, {});".format(bf,
-                                                           gfs,
-                                                           name,
-                                                           )
-
-
-@preamble
-def interpolate_solution_expression(name):
-    formdata = _driver_data['formdata']
-    define_vector(name, formdata)
-    element = get_trial_element()
-    sol = name_solution_function()
-    gfs = name_gfs(element)
-    return "Dune::PDELab::interpolate({}, {}, {});".format(sol,
-                                                           gfs,
-                                                           name,
-                                                           )
-
-
-def maybe_interpolate_vector(name, formdata):
-    element = get_trial_element()
-    if has_constraints(element):
-        interpolate_vector(name, formdata)
-    else:
-        define_vector(name, formdata)
-
-
-def name_vector(formdata):
-    name = form_name_suffix("x", formdata)
-    maybe_interpolate_vector(name, formdata)
-    return name
-
-
-def name_vector_from_solution_expression():
-    interpolate_solution_expression("solution")
-    return "solution"
-
-
-@preamble
-def typedef_linearsolver(name):
-    include_file("dune/pdelab/backend/istl.hh", filetag="driver")
-    return "using {} = Dune::PDELab::ISTLBackend_SEQ_UMFPack;".format(name)
-
-
-def type_linearsolver():
-    typedef_linearsolver("LinearSolver")
-    return "LinearSolver"
-
-
-@preamble
-def define_linearsolver(name):
-    lstype = type_linearsolver()
-    return "{} {}(false);".format(lstype, name)
-
-
-def name_linearsolver():
-    define_linearsolver("ls")
-    return "ls"
-
-
-@preamble
-def define_reduction(name):
-    ini = name_initree()
-    return "double {} = {}.get<double>(\"reduction\", 1e-12);".format(name, ini)
-
-
-def name_reduction():
-    define_reduction("reduction")
-    return "reduction"
-
-
-@preamble
-def typedef_stationarylinearproblemsolver(name):
-    include_file("dune/pdelab/stationary/linearproblem.hh", filetag="driver")
-    gotype = type_gridoperator(_driver_data['formdata'])
-    lstype = type_linearsolver()
-    xtype = type_vector(_driver_data['formdata'])
-    return "using {} = Dune::PDELab::StationaryLinearProblemSolver<{}, {}, {}>;".format(name, gotype, lstype, xtype)
-
-
-def type_stationarylinearproblemsolver():
-    typedef_stationarylinearproblemsolver("SLP")
-    return "SLP"
-
-
-@preamble
-def define_stationarylinearproblemsolver(name):
-    slptype = type_stationarylinearproblemsolver()
-    formdata = _driver_data['formdata']
-    go = name_gridoperator(formdata)
-    ls = name_linearsolver()
-    x = name_vector(formdata)
-    red = name_reduction()
-    return "{} {}({}, {}, {}, {});".format(slptype, name, go, ls, x, red)
-
-
-def name_stationarylinearproblemsolver():
-    define_stationarylinearproblemsolver("slp")
-    return "slp"
-
-
-@preamble
-def typedef_stationarynonlinearproblemsolver(name, go_type):
-    include_file("dune/pdelab/newton/newton.hh", filetag="driver")
-    ls_type = type_linearsolver()
-    x_type = type_vector(_driver_data['formdata'])
-    return "using {} = Dune::PDELab::Newton<{}, {}, {}>;".format(name, go_type, ls_type, x_type)
-
-
-def type_stationarynonlinearproblemssolver(go_type):
-    typedef_stationarynonlinearproblemsolver("SNP", go_type)
-    return "SNP"
-
-
-@preamble
-def define_stationarynonlinearproblemsolver(name, go_type, go):
-    snptype = type_stationarynonlinearproblemssolver(go_type)
-    x = name_vector(_driver_data['formdata'])
-    ls = name_linearsolver()
-    return "{} {}({}, {}, {});".format(snptype, name, go, x, ls)
-
-
-def name_stationarynonlinearproblemsolver(go_type, go):
-    define_stationarynonlinearproblemsolver("snp", go_type, go)
-    return "snp"
-
-
-@preamble
-def typedef_timesteppingmethod(name):
-    r_type = type_range()
-    explicit = get_option('explicit_time_stepping')
-    if explicit:
-        return "using {} = Dune::PDELab::ExplicitEulerParameter<{}>;".format(name, r_type)
-    else:
-        return "using {} = Dune::PDELab::OneStepThetaParameter<{}>;".format(name, r_type)
-
-
-def type_timesteppingmethod():
-    typedef_timesteppingmethod("TSM")
-    return "TSM"
-
-
-@preamble
-def define_timesteppingmethod(name):
-    tsm_type = type_timesteppingmethod()
-    explicit = get_option('explicit_time_stepping')
-    if explicit:
-        return "{} {};".format(tsm_type, name)
-    else:
-        return "{} {}(1.0);".format(tsm_type, name)
-
-
-def name_timesteppingmethod():
-    define_timesteppingmethod("tsm")
-    return "tsm"
-
-
-@preamble
-def typedef_instationarygridoperator(name):
-    include_file("dune/pdelab/gridoperator/onestep.hh", filetag="driver")
-    go_type = type_gridoperator(_driver_data['formdata'])
-    mass_go_type = type_gridoperator(_driver_data['mass_formdata'])
-    explicit = get_option('explicit_time_stepping')
-    if explicit:
-        return "using {} = Dune::PDELab::OneStepGridOperator<{},{},false>;".format(name, go_type, mass_go_type)
-    else:
-        return "using {} = Dune::PDELab::OneStepGridOperator<{},{}>;".format(name, go_type, mass_go_type)
-
-
-def type_instationarygridoperator():
-    typedef_instationarygridoperator("IGO")
-    return "IGO"
-
-
-@preamble
-def define_instationarygridoperator(name):
-    igo_type = type_instationarygridoperator()
-    go = name_gridoperator(_driver_data['formdata'])
-    mass_go = name_gridoperator(_driver_data['mass_formdata'])
-    return "{} {}({}, {});".format(igo_type, name, go, mass_go)
-
-
-def name_instationarygridoperator():
-    define_instationarygridoperator("igo")
-    return "igo"
-
-
-@preamble
-def typedef_onestepmethod(name):
-    r_type = type_range()
-    igo_type = type_instationarygridoperator()
-    snp_type = type_stationarynonlinearproblemssolver(igo_type)
-    vector_type = type_vector(_driver_data['formdata'])
-    return "using {} = Dune::PDELab::OneStepMethod<{}, {}, {}, {}, {}>;".format(name, r_type, igo_type, snp_type, vector_type, vector_type)
-
-
-def type_onestepmethod():
-    typedef_onestepmethod("OSM")
-    return "OSM"
-
-
-@preamble
-def define_onestepmethod(name):
-    ilptype = type_onestepmethod()
-    tsm = name_timesteppingmethod()
-    igo_type = type_instationarygridoperator()
-    igo = name_instationarygridoperator()
-    snp = name_stationarynonlinearproblemsolver(igo_type, igo)
-    return "{} {}({},{},{});".format(ilptype, name, tsm, igo, snp)
-
-
-def name_onestepmethod():
-    define_onestepmethod("osm")
-    return "osm"
-
-
-@preamble
-def typedef_explicitonestepmethod(name):
-    r_type = type_range()
-    igo_type = type_instationarygridoperator()
-    ls_type = type_linearsolver()
-    vector_type = type_vector(_driver_data['formdata'])
-    return "using {} = Dune::PDELab::ExplicitOneStepMethod<{}, {}, {}, {}>;".format(name, r_type, igo_type, ls_type, vector_type)
-
-
-def type_explicitonestepmethod():
-    typedef_explicitonestepmethod("EOSM")
-    return "EOSM"
-
-
-@preamble
-def define_explicitonestepmethod(name):
-    eosm_type = type_explicitonestepmethod()
-    tsm = name_timesteppingmethod()
-    igo = name_instationarygridoperator()
-    ls = name_linearsolver()
-    return "{} {}({}, {}, {});".format(eosm_type, name, tsm, igo, ls)
-
-
-def name_explicitonestepmethod():
-    define_explicitonestepmethod("eosm")
-    return "eosm"
-
-
 @preamble
 def define_mpihelper(name):
     include_file("dune/common/parallel/mpihelper.hh", filetag="driver")
@@ -1173,468 +219,6 @@ def name_mpihelper():
     return name
 
 
-@preamble
-def dune_solve():
-    # Test if form is linear in ansatzfunction
-    linear = is_linear(_driver_data['formdata'].original_form)
-
-    # Test wether we want to do matrix free operator evaluation
-    matrix_free = get_option('matrix_free')
-
-    # Get right solve command
-    if linear and matrix_free:
-        formdata = _driver_data['formdata']
-        go = name_gridoperator(formdata)
-        x = name_vector(formdata)
-        include_file("dune/perftool/matrixfree.hh", filetag="driver")
-        solve = "solveMatrixFree({},{});".format(go, x)
-    elif linear and not matrix_free:
-        slp = name_stationarylinearproblemsolver()
-        solve = "{}.apply();".format(slp)
-    elif not linear and matrix_free:
-        # TODO copy of linear case and obviously broken, used to generate something ;)
-        formdata = _driver_data['formdata']
-        go = name_gridoperator(formdata)
-        x = name_vector(formdata)
-        include_file("dune/perftool/matrixfree.hh", filetag="driver")
-        solve = "solveNonlinearMatrixFree({},{});".format(go, x)
-    elif not linear and not matrix_free:
-        go_type = type_gridoperator(_driver_data['formdata'])
-        go = name_gridoperator(_driver_data['formdata'])
-        snp = name_stationarynonlinearproblemsolver(go_type, go)
-        solve = "{}.apply();".format(snp)
-
-    if get_option('instrumentation_level') >= 2:
-        from dune.perftool.pdelab.driver.timings import setup_timer, name_timing_stream
-        setup_timer()
-        from dune.perftool.generation import post_include
-        post_include("HP_DECLARE_TIMER(solve);", filetag="driver")
-
-        # Print times after solving
-        from dune.perftool.generation import get_global_context_value
-        formdatas = get_global_context_value("formdatas")
-        print_times = []
-        for formdata in formdatas:
-            lop_name = name_localoperator(formdata)
-            timestream = name_timing_stream()
-            print_times.append("{}.dump_timers({}, {}, true);".format(lop_name, timestream, name_timing_identifier()))
-
-        solve = ["HP_TIMER_START(solve);",
-                 "{}".format(solve),
-                 "HP_TIMER_STOP(solve);",
-                 "DUMP_TIMER(solve, {}, true);".format(timestream),
-                 ]
-        if get_option('instrumentation_level') >= 3:
-            solve.extend(print_times)
-
-    return solve
-
-
-@preamble
-def define_vtkfile(name):
-    ini = name_initree()
-    include_file("string", filetag="driver")
-    return "std::string {} = {}.get<std::string>(\"wrapper.vtkcompare.name\", \"output\");".format(name, ini)
-
-
-def name_vtkfile():
-    define_vtkfile("vtkfile")
-    return "vtkfile"
-
-
-@preamble
-def compare_dofs():
-    v = name_vector(_driver_data['formdata'])
-    solution = name_vector_from_solution_expression()
-    fail = name_test_fail_variable()
-    return ["",
-            "// Maximum norm of difference between dof vectors of the",
-            "// numerical solution and the interpolation of the exact solution",
-            "using Dune::PDELab::Backend::native;",
-            "double maxerror(0.0);",
-            "for (std::size_t i=0; i<native({}).size(); ++i)".format(v),
-            "  if (std::abs(native({})[i]-native({})[i]) > maxerror)".format(v, solution),
-            "    maxerror = std::abs(native({})[i]-native({})[i]);".format(v, solution),
-            "std::cout << std::endl << \"Maxerror: \" << maxerror << std::endl;",
-            "if (maxerror>{})".format(get_option("compare_dofs")),
-            "  {} = true;".format(fail)]
-
-
-def type_discrete_grid_function(gfs):
-    return "DGF_{}".format(gfs.upper())
-
-
-@preamble
-def define_discrete_grid_function(gfs, vector_name, dgf_name):
-    dgf_type = type_discrete_grid_function(gfs)
-    return ["using {} = Dune::PDELab::DiscreteGridFunction<decltype({}),decltype({})>;".format(dgf_type, gfs, vector_name),
-            "{} {}({},{});".format(dgf_type, dgf_name, gfs, vector_name)]
-
-
-def name_discrete_grid_function(gfs, vector_name):
-    dgf_name = gfs + "_dgf"
-    define_discrete_grid_function(gfs, vector_name, dgf_name)
-    return dgf_name
-
-
-def type_subgfs(element, tree_path):
-    include_file('dune/pdelab/gridfunctionspace/subspace.hh', filetag='driver')
-    gfs = type_gfs(element)
-    return "Dune::PDELab::GridFunctionSubSpace<{}, Dune::TypeTree::TreePath<{}> >".format(gfs, ', '.join(tree_path))
-
-
-@preamble
-def define_subgfs(name, element, tree_path):
-    t = type_subgfs(element, tree_path)
-    gfs = name_gfs(element)
-
-    return '{} {}({});'.format(t, name, gfs)
-
-
-def name_subgfs(element, tree_path):
-    gfs = name_gfs(element)
-    if len(tree_path) == 0:
-        return gfs
-    else:
-        name = "subgfs_{}_{}".format(gfs, '_'.join(tree_path))
-        define_subgfs(name, element, tree_path)
-        return name
-
-
-@preamble
-def typedef_difference_squared_adapter(name, tree_path):
-    element = get_trial_element()
-    formdata = _driver_data['formdata']
-
-    solution_function = name_solution_function(tree_path)
-    gfs = name_subgfs(element, tree_path)
-    vector = name_vector(formdata)
-    dgf = name_discrete_grid_function(gfs, vector)
-
-    return 'using {} = Dune::PDELab::DifferenceSquaredAdapter<decltype({}), decltype({})>;'.format(name, solution_function, dgf)
-
-
-def type_difference_squared_adapter(tree_path):
-    t = 'DifferenceSquared_{}'.format('_'.join(tree_path))
-    typedef_difference_squared_adapter(t, tree_path)
-    return t
-
-
-@preamble
-def define_difference_squared_adapter(name, tree_path):
-    element = get_trial_element()
-    formdata = _driver_data['formdata']
-
-    t = type_difference_squared_adapter(tree_path)
-    solution_function = name_solution_function(tree_path)
-    gfs = name_subgfs(element, tree_path)
-    vector = name_vector(formdata)
-    dgf = name_discrete_grid_function(gfs, vector)
-
-    return '{} {}({}, {});'.format(t, name, solution_function, dgf)
-
-
-def name_difference_squared_adapter(tree_path):
-    name = 'differencesquared_{}'.format('_'.join(tree_path))
-    define_difference_squared_adapter(name, tree_path)
-    return name
-
-
-@preamble
-def _accumulate_L2_squared(tree_path):
-    dsa = name_difference_squared_adapter(tree_path)
-    t_dsa = type_difference_squared_adapter(tree_path)
-    accum_error = name_accumulated_L2_error()
-
-    include_file("dune/pdelab/gridfunctionspace/gridfunctionadapter.hh", filetag="driver")
-    include_file("dune/pdelab/common/functionutilities.hh", filetag="driver")
-
-    return ["{",
-            "  // L2 error squared of difference between numerical",
-            "  // solution and the interpolation of exact solution",
-            "  // only subgfs with treepath: {}".format(', '.join(tree_path)),
-            "  typename {}::Traits::RangeType err(0.0);".format(t_dsa),
-            "  Dune::PDELab::integrateGridFunction({}, err, 10);".format(dsa),
-            "  {} += err;".format(accum_error),
-            "  std::cout << \"Accumlated L2 Error for tree path {}: \" << err << std::endl;".format(tree_path),
-            "}"]
-
-
-def accumulate_L2_squared(tree_path=()):
-    element = get_trial_element()
-    from ufl.functionview import select_subelement
-    from ufl.classes import MultiIndex, FixedIndex
-    element = select_subelement(element, MultiIndex(tuple(FixedIndex(int(i)) for i in tree_path)))
-
-    from ufl import MixedElement
-    if isinstance(element, MixedElement):
-        for i, subel in enumerate(element.sub_elements()):
-            accumulate_L2_squared(tree_path + (str(i),))
-    else:
-        _accumulate_L2_squared(tree_path)
-
-
-@preamble
-def define_accumulated_L2_error(name):
-    return "double {}(0.0);".format(name)
-
-
-def name_accumulated_L2_error():
-    name = 'l2error'
-    define_accumulated_L2_error(name)
-    return name
-
-
-@preamble
-def compare_L2_squared():
-    accumulate_L2_squared()
-
-    accum_error = name_accumulated_L2_error()
-    fail = name_test_fail_variable()
-    return ["std::cout << \"l2errorsquared: \" << {} << std::endl;".format(accum_error),
-            "if (std::isnan({0}) or std::abs({0})>{1})".format(accum_error, get_option("compare_l2errorsquared")),
-            "  {} = true;".format(fail)]
-
-
-@preamble
-def define_test_fail_variable(name):
-    return 'bool {}(false);'.format(name)
-
-
-def name_test_fail_variable():
-    name = "testfail"
-    define_test_fail_variable(name)
-    return name
-
-
-@preamble
-def print_residual():
-    ini = name_initree()
-    formdata = _driver_data['formdata']
-    n_go = name_gridoperator(formdata)
-    v = name_vector(formdata)
-    t_v = type_vector(formdata)
-    include_file("random", system=True, filetag="driver")
-
-    return ["if ({}.get<bool>(\"printresidual\", false)) {{".format(ini),
-            "  using Dune::PDELab::Backend::native;",
-            "  {} r({});".format(t_v, v),
-            "  // Setup random input",
-            "  std::size_t seed = 0;",
-            "  auto rng = std::mt19937_64(seed);",
-            "  auto dist = std::uniform_real_distribution<>(-1., 1.);",
-            "  for (auto& v : {})".format(v),
-            "    v = dist(rng);",
-            "  r=0.0;",
-            "  {}.residual({}, r);".format(n_go, v),
-            "  Dune::printvector(std::cout, native(r), \"residual vector\", \"row\");",
-            "}"]
-
-
-@preamble
-def print_matrix():
-    formdata = _driver_data['formdata']
-    ini = name_initree()
-    t_go = type_gridoperator(formdata)
-    n_go = name_gridoperator(formdata)
-    v = name_vector(formdata)
-    t_v = type_vector(formdata)
-
-    return ["if ({}.get<bool>(\"printmatrix\", false)) {{".format(ini),
-            "  using M = typename {}::Traits::Jacobian;".format(t_go),
-            "  M m({});".format(n_go),
-            "  {}.jacobian({},m);".format(n_go, v),
-            "  using Dune::PDELab::Backend::native;",
-            "  Dune::printmatrix(std::cout, native(m),\"global stiffness matrix\",\"row\",9,1);",
-            "}"]
-
-
-@preamble
-def define_gfs_name(element, prefix=()):
-    from ufl import MixedElement, VectorElement, TensorElement
-    if isinstance(element, (VectorElement, TensorElement)):
-        gfs = name_gfs(element)
-        return "{}.name(\"data_{}\");".format(gfs, "_".join(str(p) for p in prefix))
-    if isinstance(element, MixedElement):
-        for (i, el) in enumerate(element.sub_elements()):
-            define_gfs_name(el, prefix + (i,))
-        return ""
-    # This is a scalar leaf
-    gfs = name_gfs(element)
-    return "{}.name(\"data_{}\");".format(gfs, "_".join(str(p) for p in prefix))
-
-
-def type_predicate():
-    include_file("dune/perftool/vtkpredicate.hh", filetag="driver")
-    return "CuttingPredicate"
-
-
-@preamble
-def define_predicate(name):
-    t = type_predicate()
-    return "{} {};".format(t, name)
-
-
-def name_predicate():
-    define_predicate("predicate")
-    return "predicate"
-
-
-@preamble
-def vtkoutput():
-    element = get_trial_element()
-    define_gfs_name(element)
-    include_file("dune/pdelab/gridfunctionspace/vtk.hh", filetag="driver")
-    vtkwriter = name_vtkwriter()
-    gfs = name_gfs(element)
-    vec = name_vector(_driver_data['formdata'])
-    vtkfile = name_vtkfile()
-    predicate = name_predicate()
-    dune_solve()
-    print_residual()
-    print_matrix()
-
-    if get_option("exact_solution_expression"):
-        if get_option("compare_dofs"):
-            compare_dofs()
-        if get_option("compare_l2errorsquared"):
-            compare_L2_squared()
-
-    return ["Dune::PDELab::addSolutionToVTKWriter({}, {}, {}, Dune::PDELab::vtk::defaultNameScheme(), {});".format(vtkwriter, gfs, vec, predicate),
-            "{}.write({}, Dune::VTK::ascii);".format(vtkwriter, vtkfile)]
-
-
-@preamble
-def define_time(name):
-    return "double {} = 0.0;".format(name)
-
-
-def name_time():
-    define_time("time")
-    return "time"
-
-
-@preamble
-def typedef_vtk_sequence_writer(name):
-    include_file("dune/grid/io/file/vtk/vtksequencewriter.hh", filetag="driver")
-    gv_type = type_leafview()
-    return "using {} = Dune::VTKSequenceWriter<{}>;".format(name, gv_type)
-
-
-def type_vtk_sequence_writer():
-    typedef_vtk_sequence_writer("VTKSW")
-    return "VTKSW"
-
-
-@preamble
-def define_vtk_sequence_writer(name):
-    vtksw_type = type_vtk_sequence_writer()
-    vtkw_type = type_vtkwriter()
-    vtkw = name_vtkwriter()
-    vtkfile = name_vtkfile()
-    return "{} {}(std::make_shared<{}>({}), {});".format(vtksw_type, name, vtkw_type, vtkw, vtkfile)
-
-
-def name_vtk_sequence_writer():
-    define_vtk_sequence_writer("vtkSequenceWriter")
-    return "vtkSequenceWriter"
-
-
-@preamble
-def visualize_initial_condition():
-    include_file("dune/pdelab/gridfunctionspace/vtk.hh", filetag="driver")
-    vtkwriter = name_vtk_sequence_writer()
-    element = get_trial_element()
-    define_gfs_name(element)
-    gfs = name_gfs(element)
-    vector = name_vector(_driver_data['formdata'])
-    predicate = name_predicate()
-    time = name_time()
-    return ["Dune::PDELab::addSolutionToVTKWriter({}, {}, {}, Dune::PDELab::vtk::defaultNameScheme(), {});".format(vtkwriter, gfs, vector, predicate),
-            "{}.write({}, Dune::VTK::appendedraw);".format(vtkwriter, time)]
-
-
-@preamble
-def time_loop():
-    ini = name_initree()
-    formdata = _driver_data['formdata']
-    params = name_parameters(formdata)
-    time = name_time()
-    expr = get_trial_element()
-    bctype = name_bctype_function(expr)
-    gfs = name_gfs(expr)
-    cc = name_constraintscontainer(expr)
-    vector_type = type_vector(formdata)
-    vector = name_vector(formdata)
-
-    # Choose between explicit and implicit time stepping
-    explicit = get_option('explicit_time_stepping')
-    if explicit:
-        osm = name_explicitonestepmethod()
-        apply_call = "{}.apply(time, dt, {}, {}new);".format(osm, vector, vector)
-    else:
-        boundary = name_boundary_function(expr)
-        osm = name_onestepmethod()
-        apply_call = "{}.apply(time, dt, {}, {}, {}new);".format(osm, vector, boundary, vector)
-
-    # Setup visualization
-    visualize_initial_condition()
-    vtk_sequence_writer = name_vtk_sequence_writer()
-
-    return ["",
-            "double T = {}.get<double>(\"instat.T\", 1.0);".format(ini),
-            "double dt = {}.get<double>(\"instat.dt\", 0.1);".format(ini),
-            "while (time<T-1e-8){",
-            "  // Assemble constraints for new time step",
-            "  {}.setTime({}+dt);".format(params, time),
-            "  Dune::PDELab::constraints({}, {}, {});".format(bctype, gfs, cc),
-            "",
-            "  // Do time step",
-            "  {} {}new({});".format(vector_type, vector, vector),
-            "  {}".format(apply_call),
-            "",
-            "  // Accept new time step",
-            "  {} = {}new;".format(vector, vector),
-            "  time += dt;",
-            "",
-            "  // Output to VTK File",
-            "  {}.write({}, Dune::VTK::appendedraw);".format(vtk_sequence_writer, time),
-            "}",
-            ""]
-
-
-def solve_instationary():
-    # Test if form is linear in ansatzfunction
-    linear = is_linear(_driver_data['formdata'].original_form)
-
-    # Test wether we want to do matrix free operator evaluation
-    matrix_free = get_option('matrix_free')
-
-    # Create time loop
-    if linear and matrix_free:
-        assert False
-    elif linear and not matrix_free:
-        time_loop()
-    if not linear and matrix_free:
-        assert False
-    elif not linear and not matrix_free:
-        assert False
-
-    print_residual()
-    print_matrix()
-    if get_option("exact_solution_expression"):
-        if get_option("compare_dofs"):
-            compare_dofs()
-        if get_option("compare_l2errorsquared"):
-            compare_L2_squared()
-
-
-@preamble
-def return_statement():
-    fail = name_test_fail_variable()
-    return "return {};".format(fail)
-
-
 def generate_driver(formdatas, data):
     # The driver module uses a global dictionary for storing necessary data
     set_driver_data(formdatas, data)
@@ -1651,9 +235,12 @@ def generate_driver(formdatas, data):
         evaluate_residual_timer()
         apply_jacobian_timer()
     elif is_stationary():
-        # We could also use solve if we are not interested in visualization
+        from dune.perftool.pdelab.driver.solve import dune_solve
+        vec = dune_solve()
+        from dune.perftool.pdelab.driver.vtk import vtkoutput
         vtkoutput()
     else:
+        from dune.perftool.pdelab.driver.instationary import solve_instationary
         solve_instationary()
 
     # Make sure that timestream is declared before retrieving chache items
@@ -1662,6 +249,7 @@ def generate_driver(formdatas, data):
         setup_timer()
         timestream = name_timing_stream()
 
+    from dune.perftool.pdelab.driver.error import return_statement
     return_statement()
 
     from dune.perftool.generation import retrieve_cache_items
diff --git a/python/dune/perftool/pdelab/driver/constraints.py b/python/dune/perftool/pdelab/driver/constraints.py
index 2a093a9c..a75016c2 100644
--- a/python/dune/perftool/pdelab/driver/constraints.py
+++ b/python/dune/perftool/pdelab/driver/constraints.py
@@ -1,13 +1,11 @@
-from dune.perftool.generation import (global_context,
-                                      include_file,
+from dune.perftool.generation import (include_file,
                                       preamble,
                                       )
 from dune.perftool.pdelab.driver import (FEM_name_mangling,
                                          get_formdata,
                                          get_trial_element,
                                          )
-from dune.perftool.pdelab.driver.gridfunctionspace import (name_gfs,
-                                                           name_leafview,
+from dune.perftool.pdelab.driver.gridfunctionspace import (name_leafview,
                                                            name_trial_gfs,
                                                            type_range,
                                                            type_trial_gfs,
@@ -29,31 +27,28 @@ def assemble_constraints(name):
     element = get_trial_element()
     gfs = name_trial_gfs()
     is_dirichlet = preprocess_leaf_data(element, "is_dirichlet")
-    if bool(is_dirichlet[0]):
-        bctype_function = name_bctype_function(element, is_dirichlet)
-        return "Dune::PDELab::constraints({}, {}, {});".format(bctype_function,
-                                                               gfs,
-                                                               name,
-                                                               )
-    else:
-        return []
+    bctype_function = name_bctype_function(element, is_dirichlet)
+    return "Dune::PDELab::constraints({}, {}, {});".format(bctype_function,
+                                                           gfs,
+                                                           name,
+                                                           )
 
 
 def name_bctype_function(element, is_dirichlet):
     if isinstance(element, (VectorElement, TensorElement)):
-        subel = element.sub_elements()[0]
-        child = name_bctype_function(subel, is_dirichlet[:subel.value_size()])
-        name = "{}_pow{}bctype".format(child, element.num_sub_elements())
-        define_power_bctype_function(element, name, child)
+        subel = element.sub_element()[0]
+        subgfs = name_bctype_function(subel, is_dirichlet[:subel.value_size()])
+        name = "{}_pow{}bctype".format(subgfs, element.num_sub_elements())
+        define_power_bctype_function(element, name, subgfs)
         return name
     if isinstance(element, MixedElement):
         k = 0
-        childs = []
+        subgfs = []
         for subel in element.sub_elements():
-            childs.append(name_bctype_function(subel, is_dirichlet[k:k + subel.value_size()]))
+            subgfs.append(name_gfs(subel, is_dirichlet[k:k + subel.value_size()]))
             k = k + subel.value_size()
-        name = "{}_bctype".format("_".join(childs))
-        define_composite_bctype_function(element, is_dirichlet, name, tuple(childs))
+        name = "_".join(subgfs)
+        define_composite_bctype_function(element, is_dirichlet, name, subgfs)
         return name
     else:
         assert isinstance(element, FiniteElement)
@@ -96,11 +91,17 @@ def name_bctype_lambda(name, func):
 
 @preamble
 def define_intersection_lambda(name, func):
+    from dune.perftool.ufl.execution import Expression
     from ufl.classes import Expr
     if func is None:
         func = 0.
     if isinstance(func, (int, float)):
         return "auto {} = [&](const auto& x){{ return {}; }};".format(name, float(func))
+    elif isinstance(func, Expression):
+        if expression.is_global:
+            return "auto {} = [&](const auto& x){{ {} }};".format(name, func.c_expr[0])
+        else:
+            return "auto {} = [&](const auto& is, const auto& x){{ {} }};".format(name, func.c_expr[0])
     elif isinstance(func, Expr):
         # Set up a visitor
         with global_context(integral_type="exterior_facet", formdata=get_formdata(), driver=True):
diff --git a/python/dune/perftool/pdelab/driver/error.py b/python/dune/perftool/pdelab/driver/error.py
index 2a8f35b4..dbbb0b9c 100644
--- a/python/dune/perftool/pdelab/driver/error.py
+++ b/python/dune/perftool/pdelab/driver/error.py
@@ -9,19 +9,13 @@ from dune.perftool.pdelab.driver import (get_formdata,
                                          get_trial_element,
                                          preprocess_leaf_data,
                                          )
-from dune.perftool.pdelab.driver.gridfunctionspace import (name_gfs,
-                                                           name_trial_gfs,
-                                                           name_trial_subgfs,
-                                                           type_range,
-                                                           )
+from dune.perftool.pdelab.driver.gridfunctionspace import name_gfs
 from dune.perftool.pdelab.driver.interpolate import (interpolate_vector,
                                                      name_boundary_function,
                                                      )
 from dune.perftool.pdelab.driver.solve import (define_vector,
-                                               dune_solve,
                                                name_vector,
                                                )
-from ufl import MixedElement, TensorElement, VectorElement
 
 
 @preamble
@@ -35,18 +29,43 @@ def name_test_fail_variable():
     return name
 
 
-def name_exact_solution_gridfunction(treepath):
+def name_exact_solution():
+    name = "solution"
+    define_vector(name, get_formdata())
+    interpolate_exact_solution(name)
+    return name
+
+
+def interpolate_exact_solution(name):
     element = get_trial_element()
-    func = preprocess_leaf_data(element, "exact_solution")
-    if isinstance(element, MixedElement):
-        index = treepath_to_index(element, treepath)
-        func = (func[index],)
-        element = element.extract_component(index)[1]
-    return name_boundary_function(element, func)
+    is_dirichlet = preprocess_leaf_data(element, "is_dirichlet")
+    gfs = name_gfs(element, is_dirichlet)
+    sol = preprocess_leaf_data(element, "exact_solution")
+    func = name_boundary_function(element, sol)
+    interpolate_vector(func, gfs, name)
+
+
+@preamble
+def compare_dofs():
+    v = name_vector(get_formdata())
+    solution = name_exact_solution()
+    fail = name_test_fail_variable()
+
+    return ["",
+            "// Maximum norm of difference between dof vectors of the",
+            "// numerical solution and the interpolation of the exact solution",
+            "using Dune::PDELab::Backend::native;",
+            "double maxerror(0.0);",
+            "for (std::size_t i=0; i<native({}).size(); ++i)".format(v),
+            "  if (std::abs(native({})[i]-native({})[i]) > maxerror)".format(v, solution),
+            "    maxerror = std::abs(native({})[i]-native({})[i]);".format(v, solution),
+            "std::cout << std::endl << \"Maxerror: \" << maxerror << std::endl;",
+            "if (maxerror>{})".format(get_option("compare_dofs")),
+            "  {} = true;".format(fail)]
 
 
 def type_discrete_grid_function(gfs):
-    return "{}_DGF".format(gfs.upper())
+    return "DGF_{}".format(gfs.upper())
 
 
 @preamble
@@ -63,93 +82,53 @@ def name_discrete_grid_function(gfs, vector_name):
 
 
 @preamble
-def typedef_difference_squared_adapter(name, treepath):
-    sol = name_exact_solution_gridfunction(treepath)
+def typedef_difference_squared_adapter(name):
+    sol = name_exact_solution()
     vector = name_vector(get_formdata())
-    gfs = name_trial_subgfs(treepath)
     dgf = name_discrete_grid_function(gfs, vector)
 
     return 'using {} = Dune::PDELab::DifferenceSquaredAdapter<decltype({}), decltype({})>;'.format(name, sol, dgf)
 
 
-def type_difference_squared_adapter(treepath):
-    name = 'DifferenceSquaredAdapter_{}'.format("_".join(str(t) for t in treepath))
-    typedef_difference_squared_adapter(name, treepath)
+def type_difference_squared_adapter():
+    name = 'DifferenceSquaredAdapter'
+    typedef_difference_squared_adapter(name)
     return name
 
 
 @preamble
-def define_difference_squared_adapter(name, treepath):
-    t = type_difference_squared_adapter(treepath)
-    sol = name_exact_solution_gridfunction(treepath)
+def define_difference_squared_adapter(name):
+    t = type_difference_squared_adapter()
+    sol = name_exact_solution()
     vector = name_vector(get_formdata())
-    gfs = name_trial_subgfs(treepath)
     dgf = name_discrete_grid_function(gfs, vector)
 
     return '{} {}({}, {});'.format(t, name, sol, dgf)
 
 
-def name_difference_squared_adapter(treepath):
-    name = 'dsa_{}'.format("_".join(str(t) for t in treepath))
-    define_difference_squared_adapter(name, treepath)
+def name_difference_squared_adapter():
+    name = 'differencesquared_adapter'
+    define_difference_squared_adapter(name)
     return name
 
 
 @preamble
-def _accumulate_L2_squared(treepath):
-    dsa = name_difference_squared_adapter(treepath)
+def accumulate_L2_squared():
+    dsa = name_difference_squared_adapter()
     accum_error = name_accumulated_L2_error()
 
     include_file("dune/pdelab/gridfunctionspace/gridfunctionadapter.hh", filetag="driver")
     include_file("dune/pdelab/common/functionutilities.hh", filetag="driver")
 
-    strtp = ", ".join(str(t) for t in treepath)
-
-    return ["{",
-            "  // L2 error squared of difference between numerical",
-            "  // solution and the interpolation of exact solution",
-            "  // for treepath ({})".format(strtp),
-            "  typename decltype({})::Traits::RangeType err(0.0);".format(dsa),
-            "  Dune::PDELab::integrateGridFunction({}, err, 10);".format(dsa),
-            "  {} += err;".format(accum_error),
-            "  std::cout << \"L2 Error for treepath {}: \" << err << std::endl;".format(strtp),
-            "}",
+    return ["// L2 error squared of difference between numerical",
+            "// solution and the interpolation of exact solution",
+            "  Dune::PDELab::integrateGridFunction({}, {}, 10);".format(dsa, accum_error),
             ]
 
 
-def get_treepath(element, index):
-    if isinstance(element, (VectorElement, TensorElement)):
-        return (index,)
-    if isinstance(element, MixedElement):
-        pos, rest = element.extract_subelement_component(index)
-        offset = sum(element.sub_elements()[i].value_size() for i in range(pos))
-        return (pos,) + get_treepath(element.sub_elements()[pos], index - offset)
-    else:
-        return ()
-
-
-def treepath_to_index(element, treepath, offset=0):
-    if len(treepath) == 0:
-        return offset
-    index = treepath[0]
-    offset = offset + sum(element.sub_elements()[i].value_size() for i in range(index))
-    subel = element.sub_elements()[index]
-    return treepath_to_index(subel, treepath[1:], offset)
-
-
-def accumulate_L2_squared():
-    element = get_trial_element()
-    if isinstance(element, MixedElement):
-        for i in range(element.value_size()):
-            _accumulate_L2_squared(get_treepath(element, i))
-    else:
-        _accumulate_L2_squared(())
-
-
 @preamble
 def define_accumulated_L2_error(name):
-    t = type_range()
-    return "{} {}(0.0);".format(t, name)
+    return "double {}(0.0);".format(name)
 
 
 def name_accumulated_L2_error():
@@ -164,10 +143,8 @@ def compare_L2_squared():
 
     accum_error = name_accumulated_L2_error()
     fail = name_test_fail_variable()
-    return ["using std::abs;",
-            "using std::isnan;",
-            "std::cout << \"\\nl2errorsquared: \" << {} << std::endl << std::endl;".format(accum_error),
-            "if (isnan({0}) or abs({0})>{1})".format(accum_error, get_option("compare_l2errorsquared")),
+    return ["std::cout << \"l2errorsquared: \" << {} << std::endl;".format(accum_error),
+            "if (std::isnan({0}) or std::abs({0})>{1})".format(accum_error, get_option("compare_l2errorsquared")),
             "  {} = true;".format(fail)]
 
 
diff --git a/python/dune/perftool/pdelab/driver/gridfunctionspace.py b/python/dune/perftool/pdelab/driver/gridfunctionspace.py
index 8509b30f..b439ded1 100644
--- a/python/dune/perftool/pdelab/driver/gridfunctionspace.py
+++ b/python/dune/perftool/pdelab/driver/gridfunctionspace.py
@@ -30,18 +30,14 @@ def type_domainfield():
     return "DF"
 
 
-def basetype_range():
+@preamble
+def typedef_range(name):
     if get_option('opcounter'):
         from dune.perftool.pdelab.driver.timings import setup_timer
         setup_timer()
-        return "oc::OpCounter<double>"
+        return "using {} = oc::OpCounter<double>;".format(name)
     else:
-        return "double"
-
-
-@preamble
-def typedef_range(name):
-    return "using {} = {};".format(name, basetype_range())
+        return "using {} = double;".format(name)
 
 
 def type_range():
@@ -124,9 +120,6 @@ def typedef_fem(element, name):
     df = type_domainfield()
     r = type_range()
     dim = get_dimension()
-    if get_option("blockstructured"):
-        include_file("dune/perftool/blockstructured/blockstructuredqkfem.hh", filetag="driver")
-        return "using {} = Dune::PDELab::BlockstructuredQkLocalFiniteElementMap<{}, {}, {}, {}>;".format(name, gv, df, r, element.degree())
     if isQk(element):
         include_file("dune/pdelab/finiteelementmap/qkfem.hh", filetag="driver")
         return "using {} = Dune::PDELab::QkLocalFiniteElementMap<{}, {}, {}, {}>;".format(name, gv, df, r, element.degree())
@@ -184,7 +177,7 @@ def name_test_gfs():
 
 def name_gfs(element, is_dirichlet):
     if isinstance(element, (VectorElement, TensorElement)):
-        subel = element.sub_elements()[0]
+        subel = element.sub_element()[0]
         subgfs = name_gfs(subel, is_dirichlet[:subel.value_size()])
         name = "{}_pow{}gfs".format(subgfs, element.num_sub_elements())
         define_power_gfs(element, is_dirichlet, name, subgfs)
@@ -196,12 +189,12 @@ def name_gfs(element, is_dirichlet):
             subgfs.append(name_gfs(subel, is_dirichlet[k:k + subel.value_size()]))
             k = k + subel.value_size()
         name = "_".join(subgfs)
-        define_composite_gfs(element, is_dirichlet, name, tuple(subgfs))
+        define_composite_gfs(element, is_dirichlet, name, subgfs)
         return name
     else:
         assert isinstance(element, FiniteElement)
         name = "{}{}_gfs".format(FEM_name_mangling(element).lower(),
-                                 "_dirichlet" if is_dirichlet[0] else "",
+                                 "_dirichlet" if is_dirichlet else "",
                                  )
         define_gfs(element, is_dirichlet, name)
         return name
@@ -221,7 +214,7 @@ def type_trial_gfs():
 
 def type_gfs(element, is_dirichlet):
     if isinstance(element, (VectorElement, TensorElement)):
-        subel = element.sub_elements()[0]
+        subel = element.sub_element()[0]
         subgfs = type_gfs(subel, is_dirichlet[:subel.value_size()])
         name = "{}_POW{}GFS".format(subgfs, element.num_sub_elements())
         typedef_power_gfs(element, is_dirichlet, name, subgfs)
@@ -233,12 +226,12 @@ def type_gfs(element, is_dirichlet):
             subgfs.append(type_gfs(subel, is_dirichlet[k:k + subel.value_size()]))
             k = k + subel.value_size()
         name = "_".join(subgfs)
-        typedef_composite_gfs(element, name, tuple(subgfs))
+        typedef_composite_gfs(element, name, subgfs)
         return name
     else:
         assert isinstance(element, FiniteElement)
         name = "{}{}_GFS".format(FEM_name_mangling(element).upper(),
-                                 "_dirichlet" if is_dirichlet[0] else "",
+                                 "_dirichlet" if is_dirichlet else "",
                                  )
         typedef_gfs(element, is_dirichlet, name)
         return name
@@ -256,7 +249,6 @@ def define_gfs(element, is_dirichlet, name):
 def define_power_gfs(element, is_dirichlet, name, subgfs):
     gv = name_leafview()
     fem = name_fem(element.sub_elements()[0])
-    gfstype = type_gfs(element, is_dirichlet)
     return "{} {}({}, {});".format(gfstype, name, gv, fem)
 
 
@@ -271,7 +263,7 @@ def typedef_gfs(element, is_dirichlet, name):
     vb = type_vectorbackend(element)
     gv = type_leafview()
     fem = type_fem(element)
-    cass = type_constraintsassembler(bool(is_dirichlet[0]))
+    cass = type_constraintsassembler(bool(is_dirichlet))
     return "using {} = Dune::PDELab::GridFunctionSpace<{}, {}, {}, {}>;".format(name, gv, fem, cass, vb)
 
 
@@ -351,30 +343,3 @@ def type_constraintsassembler(is_dirichlet):
         name = "NoConstraintsAssembler"
         typedef_no_constraintsassembler(name)
         return name
-
-
-def name_trial_subgfs(treepath):
-    if len(treepath) == 0:
-        return name_trial_gfs()
-    else:
-        return name_subgfs(treepath)
-
-
-def name_subgfs(treepath):
-    gfs = name_trial_gfs()
-    name = "{}_{}".format(gfs, "_".join(str(t) for t in treepath))
-    define_subgfs(name, treepath)
-    return name
-
-
-@preamble
-def define_subgfs(name, treepath):
-    t = type_subgfs(treepath)
-    gfs = name_trial_gfs()
-    return "{} {}({});".format(t, name, gfs)
-
-
-def type_subgfs(tree_path):
-    include_file('dune/pdelab/gridfunctionspace/subspace.hh', filetag='driver')
-    gfs = type_trial_gfs()
-    return "Dune::PDELab::GridFunctionSubSpace<{}, Dune::TypeTree::TreePath<{}> >".format(gfs, ', '.join(str(t) for t in tree_path))
diff --git a/python/dune/perftool/pdelab/driver/gridoperator.py b/python/dune/perftool/pdelab/driver/gridoperator.py
index b701ceca..500d8bc7 100644
--- a/python/dune/perftool/pdelab/driver/gridoperator.py
+++ b/python/dune/perftool/pdelab/driver/gridoperator.py
@@ -104,12 +104,6 @@ def name_localoperator(formdata):
     return name
 
 
-@preamble
-def update_gfs(gfs):
-    return ["// Update the GFS to trigger GFS initialization",
-            "{}.update();".format(gfs)]
-
-
 @preamble
 def define_dofestimate(name):
     # Provide a worstcase estimate for the number of entries per row based
@@ -118,14 +112,13 @@ def define_dofestimate(name):
         geo_factor = 2**get_dimension()
     else:
         if get_dimension() < 3:
-            geo_factor = 3 * get_dimension()
+            geo_factor = 3*get_dimension()
         else:
             # TODO no idea how a generic estimate for 3D simplices looks like
             geo_factor = 12
 
     gfs = name_trial_gfs()
     ini = name_initree()
-    update_gfs(gfs)
 
     return ["int generic_dof_estimate =  {} * {}.maxLocalSize();".format(geo_factor, gfs),
             "int {} = {}.get<int>(\"istl.number_of_nnz\", generic_dof_estimate);".format(name, ini)]
diff --git a/python/dune/perftool/pdelab/driver/instationary.py b/python/dune/perftool/pdelab/driver/instationary.py
index 9ab49c9c..bf8759e7 100644
--- a/python/dune/perftool/pdelab/driver/instationary.py
+++ b/python/dune/perftool/pdelab/driver/instationary.py
@@ -1,35 +1,11 @@
-from dune.perftool.generation import (include_file,
-                                      preamble,
-                                      )
+from dune.perftool.generation import preamble
 from dune.perftool.pdelab.driver import (get_formdata,
-                                         get_mass_formdata,
-                                         get_trial_element,
                                          is_linear,
-                                         name_initree,
-                                         preprocess_leaf_data,
                                          )
-from dune.perftool.pdelab.driver.gridfunctionspace import (name_gfs,
-                                                           type_range,
-                                                           )
-from dune.perftool.pdelab.driver.gridoperator import (name_gridoperator,
-                                                      name_parameters,
-                                                      type_gridoperator,)
-from dune.perftool.pdelab.driver.constraints import (name_bctype_function,
-                                                     name_constraintscontainer,
-                                                     )
-from dune.perftool.pdelab.driver.interpolate import (interpolate_dirichlet_data,
-                                                     name_boundary_function,
-                                                     )
+from dune.perftool.pdelab.driver.gridoperator import (type_gridoperator,)
 from dune.perftool.pdelab.driver.solve import (print_matrix,
                                                print_residual,
-                                               name_stationarynonlinearproblemsolver,
-                                               name_vector,
-                                               type_stationarynonlinearproblemssolver,
-                                               type_vector,
                                                )
-from dune.perftool.pdelab.driver.vtk import (name_vtk_sequence_writer,
-                                             visualize_initial_condition,
-                                             )
 from dune.perftool.options import get_option
 
 
@@ -52,6 +28,12 @@ def solve_instationary():
 
     print_residual()
     print_matrix()
+    from dune.perftool.pdelab.driver.error import compare_dofs, compare_L2_squared
+    if get_option("exact_solution_expression"):
+        if get_option("compare_dofs"):
+            compare_dofs()
+        if get_option("compare_l2errorsquared"):
+            compare_L2_squared()
 
 
 @preamble
@@ -60,14 +42,12 @@ def time_loop():
     formdata = get_formdata()
     params = name_parameters(formdata)
     time = name_time()
-    element = get_trial_element()
-    is_dirichlet = preprocess_leaf_data(element, "is_dirichlet")
-    bctype = name_bctype_function(element, is_dirichlet)
-    gfs = name_gfs(element, is_dirichlet)
-    cc = name_constraintscontainer()
+    expr = get_trial_element()
+    bctype = name_bctype_function(expr)
+    gfs = name_gfs(expr)
+    cc = name_constraintscontainer(expr)
     vector_type = type_vector(formdata)
     vector = name_vector(formdata)
-    interpolate_dirichlet_data(vector)
 
     # Choose between explicit and implicit time stepping
     explicit = get_option('explicit_time_stepping')
@@ -75,8 +55,7 @@ def time_loop():
         osm = name_explicitonestepmethod()
         apply_call = "{}.apply(time, dt, {}, {}new);".format(osm, vector, vector)
     else:
-        dirichlet = preprocess_leaf_data(element, "dirichlet_expression")
-        boundary = name_boundary_function(element, dirichlet)
+        boundary = name_boundary_function(expr)
         osm = name_onestepmethod()
         apply_call = "{}.apply(time, dt, {}, {}, {}new);".format(osm, vector, boundary, vector)
 
@@ -116,6 +95,7 @@ def name_time():
     return "time"
 
 
+
 @preamble
 def typedef_timesteppingmethod(name):
     r_type = type_range()
@@ -149,8 +129,8 @@ def name_timesteppingmethod():
 @preamble
 def typedef_instationarygridoperator(name):
     include_file("dune/pdelab/gridoperator/onestep.hh", filetag="driver")
-    go_type = type_gridoperator(get_formdata())
-    mass_go_type = type_gridoperator(get_mass_formdata())
+    go_type = type_gridoperator(_driver_data['formdata'])
+    mass_go_type = type_gridoperator(_driver_data['mass_formdata'])
     explicit = get_option('explicit_time_stepping')
     if explicit:
         return "using {} = Dune::PDELab::OneStepGridOperator<{},{},false>;".format(name, go_type, mass_go_type)
@@ -166,8 +146,8 @@ def type_instationarygridoperator():
 @preamble
 def define_instationarygridoperator(name):
     igo_type = type_instationarygridoperator()
-    go = name_gridoperator(get_formdata())
-    mass_go = name_gridoperator(get_mass_formdata())
+    go = name_gridoperator(_driver_data['formdata'])
+    mass_go = name_gridoperator(_driver_data['mass_formdata'])
     return "{} {}({}, {});".format(igo_type, name, go, mass_go)
 
 
@@ -181,7 +161,7 @@ def typedef_onestepmethod(name):
     r_type = type_range()
     igo_type = type_instationarygridoperator()
     snp_type = type_stationarynonlinearproblemssolver(igo_type)
-    vector_type = type_vector(get_formdata())
+    vector_type = type_vector(_driver_data['formdata'])
     return "using {} = Dune::PDELab::OneStepMethod<{}, {}, {}, {}, {}>;".format(name, r_type, igo_type, snp_type, vector_type, vector_type)
 
 
@@ -210,7 +190,7 @@ def typedef_explicitonestepmethod(name):
     r_type = type_range()
     igo_type = type_instationarygridoperator()
     ls_type = type_linearsolver()
-    vector_type = type_vector(get_formdata())
+    vector_type = type_vector(_driver_data['formdata'])
     return "using {} = Dune::PDELab::ExplicitOneStepMethod<{}, {}, {}, {}>;".format(name, r_type, igo_type, ls_type, vector_type)
 
 
diff --git a/python/dune/perftool/pdelab/driver/interpolate.py b/python/dune/perftool/pdelab/driver/interpolate.py
index 763283c1..424388a0 100644
--- a/python/dune/perftool/pdelab/driver/interpolate.py
+++ b/python/dune/perftool/pdelab/driver/interpolate.py
@@ -43,21 +43,20 @@ def interpolate_vector(func, gfs, name):
                                                            )
 
 
-@cached
-def name_boundary_function(element, func):
+def name_boundary_function(element, dirichlet):
     if isinstance(element, MixedElement):
         k = 0
         childs = []
         for subel in element.sub_elements():
-            childs.append(name_boundary_function(subel, func[k:k + subel.value_size()]))
+            childs.append(name_boundary_function(subel, dirichlet[k:k + subel.value_size()]))
             k = k + subel.value_size()
         name = "_".join(childs)
-        define_compositegfs_parameterfunction(name, tuple(childs))
+        define_composite_boundary_function(name, childs)
         return name
     else:
         assert isinstance(element, FiniteElement)
-        name = get_counted_variable("func")
-        define_boundary_function(name, func[0])
+        name = "{}_boundary".format(FEM_name_mangling(element).lower())
+        define_boundary_function(name, dirichlet[0])
         return name
 
 
@@ -95,13 +94,16 @@ def name_boundary_lambda(boundary):
 
 @preamble
 def define_boundary_lambda(name, boundary):
+    from dune.perftool.ufl.execution import Expression
     from ufl.classes import Expr
     if boundary is None:
-        boundary = 0.0
-    if isinstance(boundary, (int, float)):
-        return "auto {} = [&](const auto& x){{ return {}; }};".format(name, boundary)
-    else:
-        assert isinstance(boundary, Expr)
+        return "auto {} = [&](const auto& x){{ return 0.0; }};".format(name)
+    elif isinstance(boundary, Expression):
+        if boundary.is_global:
+            return "auto {} = [&](const auto& x){{ {} }};".format(name, boundary.c_expr[0])
+        else:
+            return "auto {} = [&](const auto& e, const auto& x){{ {} }};".format(name, boundary.c_expr[0])
+    elif isinstance(boundary, Expr):
         # Set up a visitor
         with global_context(integral_type="exterior_facet", formdata=get_formdata(), driver=True):
             from dune.perftool.ufl.visitor import UFL2LoopyVisitor
diff --git a/python/dune/perftool/pdelab/driver/solve.py b/python/dune/perftool/pdelab/driver/solve.py
index 59ef32eb..5e602827 100644
--- a/python/dune/perftool/pdelab/driver/solve.py
+++ b/python/dune/perftool/pdelab/driver/solve.py
@@ -40,14 +40,21 @@ def dune_solve():
         include_file("dune/perftool/matrixfree.hh", filetag="driver")
         solve = "solveNonlinearMatrixFree({},{});".format(go, x)
     elif not linear and not matrix_free:
-        go_type = type_gridoperator(get_formdata())
-        go = name_gridoperator(get_formdata())
+        go_type = type_gridoperator(_driver_data['formdata'])
+        go = name_gridoperator(_driver_data['formdata'])
         snp = name_stationarynonlinearproblemsolver(go_type, go)
         solve = "{}.apply();".format(snp)
 
     print_residual()
     print_matrix()
 
+    from dune.perftool.pdelab.driver.error import compare_dofs, compare_L2_squared
+    if get_option("exact_solution_expression"):
+        if get_option("compare_dofs"):
+            compare_dofs()
+        if get_option("compare_l2errorsquared"):
+            compare_L2_squared()
+
     if get_option('instrumentation_level') >= 2:
         from dune.perftool.pdelab.driver.timings import setup_timer, name_timing_stream
         setup_timer()
@@ -101,6 +108,7 @@ def define_vector(name, formdata):
     return ["{} {}({});".format(vtype, name, gfs), "{} = 0.0;".format(name)]
 
 
+
 @preamble
 def typedef_linearsolver(name):
     include_file("dune/pdelab/backend/istl.hh", filetag="driver")
@@ -171,7 +179,7 @@ def name_stationarylinearproblemsolver():
 def typedef_stationarynonlinearproblemsolver(name, go_type):
     include_file("dune/pdelab/newton/newton.hh", filetag="driver")
     ls_type = type_linearsolver()
-    x_type = type_vector(get_formdata())
+    x_type = type_vector(_driver_data['formdata'])
     return "using {} = Dune::PDELab::Newton<{}, {}, {}>;".format(name, go_type, ls_type, x_type)
 
 
diff --git a/python/dune/perftool/pdelab/driver/vtk.py b/python/dune/perftool/pdelab/driver/vtk.py
index 276570de..2f68140e 100644
--- a/python/dune/perftool/pdelab/driver/vtk.py
+++ b/python/dune/perftool/pdelab/driver/vtk.py
@@ -4,10 +4,8 @@ from dune.perftool.generation import (include_file,
 from dune.perftool.pdelab.driver import (get_formdata,
                                          get_trial_element,
                                          name_initree,
-                                         preprocess_leaf_data,
                                          )
 from dune.perftool.pdelab.driver.gridfunctionspace import (name_leafview,
-                                                           name_gfs,
                                                            name_trial_gfs,
                                                            type_leafview,
                                                            )
@@ -67,7 +65,6 @@ def vtkoutput():
     include_file("dune/pdelab/gridfunctionspace/vtk.hh", filetag="driver")
     vtkwriter = name_vtkwriter()
     gfs = name_trial_gfs()
-    define_gfs_names(get_trial_element())
     vtkfile = name_vtkfile()
     predicate = name_predicate()
     vec = name_vector(get_formdata())
@@ -92,6 +89,7 @@ def name_predicate():
     return "predicate"
 
 
+
 @preamble
 def typedef_vtk_sequence_writer(name):
     include_file("dune/grid/io/file/vtk/vtksequencewriter.hh", filetag="driver")
@@ -124,7 +122,7 @@ def visualize_initial_condition():
     vtkwriter = name_vtk_sequence_writer()
     element = get_trial_element()
     define_gfs_names(element)
-    gfs = name_trial_gfs()
+    gfs = name_gfs(element)
     vector = name_vector(get_formdata())
     predicate = name_predicate()
     from dune.perftool.pdelab.driver.instationary import name_time
@@ -134,15 +132,12 @@ def visualize_initial_condition():
 
 
 @preamble
-def _define_gfs_name(element, is_dirichlet, offset):
-    from ufl import MixedElement, VectorElement
-    if isinstance(element, VectorElement):
-        gfs = name_gfs(element, is_dirichlet)
-        return "{}.name(\"data_{}to{}\");".format(gfs, offset, offset + element.value_size())
-    elif isinstance(element, MixedElement):
+def _define_gfs_name(element, is_dirichlet, offset=0):
+    from ufl import MixedElement
+    if isinstance(element, MixedElement):
         k = 0
         for subel in element.sub_elements():
-            _define_gfs_name(subel, is_dirichlet[k:k + subel.value_size()], offset + k)
+            define_gfs_name(subel, is_dirichlet[k:k + subel.value_size()], offset=offset + k)
             k = k + subel.value_size()
         return []
     else:
@@ -153,4 +148,4 @@ def _define_gfs_name(element, is_dirichlet, offset):
 
 def define_gfs_names(element):
     is_dirichlet = preprocess_leaf_data(element, "is_dirichlet")
-    return _define_gfs_name(element, is_dirichlet, 0)
+    return _define_gfs_name(element, is_dirichlet)
\ No newline at end of file
-- 
GitLab