From b8b82c0173fce4b492dec58708f2dd9af480ae33 Mon Sep 17 00:00:00 2001
From: Dominic Kempf <dominic.kempf@iwr.uni-heidelberg.de>
Date: Fri, 15 Jan 2016 13:54:16 +0100
Subject: [PATCH] One more iteration

---
 dune/perftool/vectorization/CMakeLists.txt    |   2 +-
 python/CMakeLists.txt                         |   1 -
 python/dune/perftool/compile.py               |  23 +--
 python/dune/perftool/file.py                  |  56 ++++---
 python/dune/perftool/generation.py            |  41 ++++-
 python/dune/perftool/pdelab/argument.py       |   2 +-
 python/dune/perftool/pdelab/driver.py         | 153 +++++++++---------
 python/dune/perftool/pdelab/localoperator.py  |  18 +--
 .../perftool/ufl/transformations/__init__.py  |   3 +-
 .../transformations/argument_elimination.py   |   1 -
 python/setup.py                               |   2 +-
 11 files changed, 171 insertions(+), 131 deletions(-)

diff --git a/dune/perftool/vectorization/CMakeLists.txt b/dune/perftool/vectorization/CMakeLists.txt
index fb3e48fb..a3d7d417 100644
--- a/dune/perftool/vectorization/CMakeLists.txt
+++ b/dune/perftool/vectorization/CMakeLists.txt
@@ -23,4 +23,4 @@ install(FILES complexvec.h
               vectormath_hyp.h
               vectormath_lib.h
               vectormath_trig.h
-        DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/dune/vectorization)
+        DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/dune/perftool/vectorization)
diff --git a/python/CMakeLists.txt b/python/CMakeLists.txt
index a76e429d..12966e6b 100644
--- a/python/CMakeLists.txt
+++ b/python/CMakeLists.txt
@@ -15,7 +15,6 @@ dune_install_python_package(PATH cgen MAJOR_VERSION 2)
 dune_install_python_package(PATH loopy MAJOR_VERSION 2)
 dune_install_python_package(PATH ufl MAJOR_VERSION 2)
 
-
 # Install out python package
 dune_install_python_package(PATH . MAJOR_VERSION 2)
 
diff --git a/python/dune/perftool/compile.py b/python/dune/perftool/compile.py
index ba636abf..33ee3d07 100644
--- a/python/dune/perftool/compile.py
+++ b/python/dune/perftool/compile.py
@@ -61,24 +61,13 @@ def generate_driver(form, filename):
     vtkoutput()
 
     from dune.perftool.generation import retrieve_cache_items
+    from cgen import FunctionDeclaration, FunctionBody, Block, Value
+    driver_signature = FunctionDeclaration(Value('void', 'driver'), [Value('int', 'argc'), Value('char**', 'argv')])
+    driver_body = Block(contents=[i for i in retrieve_cache_items(("driver", "preamble"), union=False, make_generable=True)])
+    driver = FunctionBody(driver_signature, driver_body)
 
-    # Get all preambles for the driver and sort them.
-    driver_content = [i[1] for i in sorted(retrieve_cache_items("preamble"), key=lambda x : x[0])]
-
-    # And flatten out those, that contained nested lists
-    def flatjoin(l):
-        if isinstance(l, str):
-            return "\n" + l
-        return "".join(flatjoin(i) for i in l)
-
-    from cgen import LiteralBlock
-    driver = LiteralBlock(flatjoin(driver_content))
-
-    # Write the file.
-    f = open(filename, 'w')
-    f.write("\n".join(retrieve_cache_items("include")))
-    f.write("\n\nvoid driver(int argc, char** argv)\n")
-    f.write("\n".join(driver.generate()))
+    from dune.perftool.file import generate_file
+    generate_file(filename, "driver", [driver])
 
     # Reset the caching data structure
     from dune.perftool.generation import delete_cache
diff --git a/python/dune/perftool/file.py b/python/dune/perftool/file.py
index 590c6102..d0e751d0 100644
--- a/python/dune/perftool/file.py
+++ b/python/dune/perftool/file.py
@@ -1,22 +1,38 @@
 """ Manages the generation of C++ header files """
 
-class FileGenerator(object):
-    def __init__(self, filename, headerguard=True):
-        self.filename = filename
-        self.content = []
-        self.includes = {}
-        
-    def generate(self):
-        with open(self.filename) as f:
-            if self.headerguard:
-                macro = self.filename.upper().replace("/", "_").replace(".", "_")
-                f.write("#ifndef {}\n#define {}\n\n".format(macro))
-
-            for inc in self.includes:
-                f.write("#include {}\n".format(inc))
-#                 
-#             for c in self.content:
-#                 generate_code(c)
-#             
-            if self.headerguard:
-                f.write("\n\n#endif")
\ No newline at end of file
+from dune.perftool.generation import retrieve_cache_items
+
+def generate_file(filename, tag, content, headerguard=True):
+    """
+    Write a file from the generation cache:
+
+    Arguments:
+    ----------
+
+    Keyword Arguments:
+    ------------------
+    """
+    with open(filename, 'w') as f:
+        # Add a double inclusion protection header
+        if headerguard:
+            macro = filename.upper().replace("/", "_").replace(".", "_")
+            f.write("#ifndef {0}\n#define {0}\n\n".format(macro))
+
+        # Add the includes from the cache
+        for inc in retrieve_cache_items((tag, 'include'), union=False):
+            from cgen import Include
+            assert isinstance(inc, Include)
+            for line in inc.generate():
+                f.write(line)
+            f.write('\n')
+
+        f.write('\n\n')
+
+        for c in content:
+            from cgen import Generable
+            assert isinstance(c, Generable)
+            for line in c.generate():
+                f.write(line)
+
+        if headerguard:
+            f.write("\n\n#endif //{}".format(macro))
diff --git a/python/dune/perftool/generation.py b/python/dune/perftool/generation.py
index 25d2425e..03b791e3 100644
--- a/python/dune/perftool/generation.py
+++ b/python/dune/perftool/generation.py
@@ -67,14 +67,15 @@ class _CacheItemMeta(type):
         def _init(s, x):
             s.content = on_store(x)
             s.tags = item_tags
+            s.counted = counted
 
         setattr(rettype, '__init__', _init)
 
         return rettype
 
 
-from pytools import memoize as _memo
-@_memo(use_kwargs=True)
+from pytools import memoize
+@memoize(use_kwargs=True)
 def _construct_cache_item_type(name, **kwargs):
     """ Wrap the generation of cache item types from the meta class.
     At the same time, memoization assures that types are the same for
@@ -161,17 +162,22 @@ def generator_factory(**factory_kwargs):
         return _dec
 
 
-def retrieve_cache_items(tags, union=True):
+def retrieve_cache_items(tags, union=True, make_generable=False):
     """ Retrieve items from the cache.
 
     If union is True, all items that match one of the given tags are
     returned. If unions is False, only items that match all tags are
     returned. The items do remain in the cache.
+
+    If make_generable is True, any strings are wrapped as cgen.Line
     """
     if isinstance(tags, str):
         tags = (tags,)
 
+    choice = []
+
     for item in _cache.values():
+        # Determine whether this item is a match with the given tags and the union parameter
         match = False
         if union:
             for t in item.tags:
@@ -182,8 +188,34 @@ def retrieve_cache_items(tags, union=True):
             for t in item.tags:
                 if t not in tags:
                     match = False
+
+        # Append the item to the list
         if match:
-            yield item.content
+            choice.append(item)
+
+    def as_generable(content):
+        if make_generable:
+            from cgen import Generable, Line
+            if isinstance(content, Generable):
+                return content
+            if isinstance(content, str):
+                return Line(text=content + '\n')
+            assert False
+        else:
+            return content
+
+    # First yield all those items that are not sorted
+    for item in choice:
+        if not item.counted:
+            yield as_generable(item.content)
+
+    for item in sorted([i for i in choice if i.counted], key = lambda i: i.content[0]):
+        from collections import Iterable
+        if isinstance(item.content[1], Iterable) and not isinstance(item.content[1], str):
+            for l in item.content[1]:
+                yield as_generable(l)
+        else:
+            yield as_generable(item.content[1])
 
 
 def delete_cache_items(tags, union=True):
@@ -198,6 +230,7 @@ def delete_cache_items(tags, union=True):
     global _cache
     _cache = {k: v for k,v in _cache.items() if v not in removing}
 
+
 def delete_cache(tags=[], union=True):
     # TODO this implementation is horribly inefficient, but does the job
     keeping = retrieve_cache_items(tags, union)
diff --git a/python/dune/perftool/pdelab/argument.py b/python/dune/perftool/pdelab/argument.py
index 71d989cb..7b2ba8f4 100644
--- a/python/dune/perftool/pdelab/argument.py
+++ b/python/dune/perftool/pdelab/argument.py
@@ -6,7 +6,7 @@ from dune.perftool.ufl.modified_terminals import ModifiedArgumentDescriptor
 @dune_symbol
 def name_testfunction(modarg):
     ma = ModifiedArgumentDescriptor(modarg)
-    if len(ma.expr.ufl_element().sub_elements()) > 0:
+    if len(ma.expr.element().sub_elements()) > 0:
         pass
     return "{}a{}".format("grad_" if ma.grad else "", ma.expr.number())
 
diff --git a/python/dune/perftool/pdelab/driver.py b/python/dune/perftool/pdelab/driver.py
index 4dd55ca8..7ac76ee0 100644
--- a/python/dune/perftool/pdelab/driver.py
+++ b/python/dune/perftool/pdelab/driver.py
@@ -6,8 +6,13 @@ Currently, these are hardcoded as strings. It would be possible
 to switch these to cgen expression. OTOH, there is not much to be
 gained there.
 """
+from dune.perftool.generation import generator_factory
+from dune.perftool.pdelab import dune_symbol
 
-from dune.perftool.pdelab import dune_symbol, dune_preamble, dune_include
+from cgen import Include
+
+driver_include = generator_factory(on_store=lambda i: Include(i), item_tags=("driver", "include"), no_deco=True)
+driver_preamble = generator_factory(item_tags=("driver", "preamble"), counted=True)
 
 # Have a global variable with the entire form data. This allows functions that depend
 # deterministically on the entire data set to directly access it instead of passing it
@@ -58,10 +63,10 @@ def name_inifile():
     # TODO pass some other option here.
     return "argv[1]"
 
-@dune_preamble
+@driver_preamble
 def parse_initree(varname):
-    dune_include("dune/common/parametertree.hh")
-    dune_include("dune/common/parametertreeparser.hh")
+    driver_include("dune/common/parametertree.hh")
+    driver_include("dune/common/parametertreeparser.hh")
     filename = name_inifile()
     return ["Dune::ParameterTree initree;", "Dune::ParameterTreeParser::readINITree({}, {});".format(filename, varname)]
 
@@ -71,25 +76,25 @@ def name_initree():
     #TODO we can get some other ini file here.
     return "initree"
 
-@dune_preamble
+@driver_preamble
 def define_dimension(name):
-    return "static const int {} = {};".format(name, __form.geometric_dimension)
+    return "static const int {} = {};".format(name, _form.cell().geometric_dimension())
 
 @dune_symbol
 def name_dimension():
     define_dimension("dim")
     return "dim"
 
-@dune_preamble
+@driver_preamble
 def typedef_grid(name):
     dim = name_dimension()
-    if any(_form.unique_elements[0].cell().cellname() in x for x in ["vertex", "interval", "quadrilateral", "hexalateral"]):
+    if any(_form.cell().cellname() in x for x in ["vertex", "interval", "quadrilateral", "hexalateral"]):
         gridt = "Dune::YaspGrid<{}>".format(dim)
-        dune_include("dune/grid/yaspgrid.hh")
+        driver_include("dune/grid/yaspgrid.hh")
     else:
-        if any(_form.unique_elements[0].cell().cellname() in x for x in ["triangle", "tetrahedron"]):
+        if any(_form.cell().cellname() in x for x in ["triangle", "tetrahedron"]):
             gridt = "Dune::UGGrid<{}>".format(dim)
-            dune_include("dune/grid/uggrid.hh")
+            driver_include("dune/grid/uggrid.hh")
         else:
             raise ValueError("Cant match your geometry with a DUNE grid. Please report bug.")
     return "typedef {} {};".format(gridt, name)
@@ -99,9 +104,9 @@ def type_grid():
     typedef_grid("Grid")
     return "Grid"
 
-@dune_preamble
+@driver_preamble
 def define_grid(name):
-    dune_include("dune/testtools/gridconstruction.hh")
+    driver_include("dune/testtools/gridconstruction.hh")
     ini = name_initree()
     _type = type_grid()
     return ["IniGridFactory<{}> factory({});".format(_type, ini),
@@ -112,7 +117,7 @@ def name_grid():
     define_grid("grid")
     return "grid"
 
-@dune_preamble
+@driver_preamble
 def typedef_leafview(name):
     grid = type_grid()
     return "typedef {}::LeafGridView {};".format(grid, name)
@@ -122,7 +127,7 @@ def type_leafview():
     typedef_leafview("GV")
     return "GV"
 
-@dune_preamble
+@driver_preamble
 def define_leafview(name):
     _type = type_leafview()
     grid = name_grid()
@@ -133,9 +138,9 @@ def name_leafview():
     define_leafview("gv")
     return "gv"
 
-@dune_preamble
+@driver_preamble
 def typedef_vtkwriter(name):
-    dune_include("dune/grid/io/file/vtk/subsamplingvtkwriter.hh")
+    driver_include("dune/grid/io/file/vtk/subsamplingvtkwriter.hh")
     gv = type_leafview()
     return "typedef Dune::SubsamplingVTKWriter<{}> {}".format(gv, name)
 
@@ -144,7 +149,7 @@ def type_vtkwriter():
     typedef_vtkwriter("VTKWriter")
     return "VTKWriter"
 
-@dune_preamble
+@driver_preamble
 def define_subsamplinglevel(name):
     ini = name_initree()
     return "int {} = {}.get<int>(\"vtk.subsamplinglevel\", 0);".format(name, ini)
@@ -154,7 +159,7 @@ def name_subsamplinglevel():
     define_subsamplinglevel("sublevel")
     return "sublevel"
 
-@dune_preamble
+@driver_preamble
 def define_vtkwriter(name):
     _type = type_vtkwriter()
     gv = name_leafview()
@@ -166,7 +171,7 @@ def name_vtkwriter():
     define_vtkwriter("vtkwriter")
     return "vtkwriter"
 
-@dune_preamble
+@driver_preamble
 def typedef_domainfield(name):
     gridt = type_grid()
     return "typedef {}::ctype {};".format(gridt, name)
@@ -176,7 +181,7 @@ def type_domainfield():
     typedef_domainfield("DF")
     return "DF"
 
-@dune_preamble
+@driver_preamble
 def typedef_range(name):
     return "typedef double {};".format(name)
 
@@ -185,16 +190,16 @@ def type_range():
     typedef_range("R")
     return "R"
 
-@dune_preamble
+@driver_preamble
 def typedef_fem(expr, name):
     gv = type_leafview()
     df = type_domainfield()
     r = type_range()
     if isPk(expr):
-        dune_include("dune/pdelab/finiteelementmap/pkfem.hh")
+        driver_include("dune/pdelab/finiteelementmap/pkfem.hh")
         return "typedef Dune::PDELab::PkLocalFiniteElementMap<{}, {}, {}, {}> {};".format(gv, df, r, expr._degree, name)
     if isQk(generator._kwargs['expr']):
-        dune_include("dune/pdelab/finiteelementmap/qkfem.hh")
+        driver_include("dune/pdelab/finiteelementmap/qkfem.hh")
         return "typedef Dune::PDELab::QkLocalFiniteElementMap<{}, {}, {}, {}> {};".format(gv, df, r, expr._degree, name)
     raise NotImplementedError("FEM not implemented in dune-perftool")
 
@@ -204,7 +209,7 @@ def type_fem(expr):
     typedef_fem(expr, name)
     return "{}_fem".format(name)
 
-@dune_preamble
+@driver_preamble
 def define_fem(expr, name):
     femtype = type_fem(expr)
     gv = name_leafview()
@@ -216,10 +221,10 @@ def name_fem(expr):
     define_fem(expr, name)
     return "{}_fem".format(name)
 
-@dune_preamble
+@driver_preamble
 def typedef_vectorbackend(name):
-    dune_include("dune/pdelab/backend/istlvectorbackend.hh")
-    return "typedef Dune::PDELab::ISTLVectorBacken<Dune::PDELab::ISTLParameters::no_blocking, 1> {}".format(name)
+    driver_include("dune/pdelab/backend/istlvectorbackend.hh")
+    return "typedef Dune::PDELab::ISTLVectorBacken<Dune::PDELab::ISTLParameters::no_blocking, 1> {};".format(name)
 
 @dune_symbol
 def type_vectorbackend():
@@ -230,9 +235,9 @@ def type_vectorbackend():
 def type_orderingtag():
     return "Dune::PDELab::LexicographicOrderingTag"
 
-@dune_preamble
+@driver_preamble
 def typedef_constraintsassembler(name):
-    dune_include("dune/pdelab/constraints/conforming.hh")
+    driver_include("dune/pdelab/constraints/conforming.hh")
     return "typedef Dune::PDELab::ConformingDirichletConstraints {}".format(name)
 
 @dune_symbol
@@ -240,7 +245,7 @@ def type_constraintsassembler():
     typedef_constraintsassembler("ConstraintsAssembler")
     return "ConstraintsAssembler"
 
-@dune_preamble
+@driver_preamble
 def typedef_constraintscontainer(expr, name):
     gfs = type_gfs(expr)
     r = type_range()
@@ -252,7 +257,7 @@ def type_constraintscontainer(expr):
     typedef_constraintscontainer(expr, name)
     return name
 
-@dune_preamble
+@driver_preamble
 def define_constraintscontainer(expr, name):
     cctype = type_constraintscontainer(expr)
     return ["{} {};".format(cctype, name), "{}.clear();".format(name)]
@@ -263,7 +268,7 @@ def name_constraintscontainer(expr):
     define_constraintscontainer(expr, name)
     return name
 
-@dune_preamble
+@driver_preamble
 def typedef_gfs(expr, name):
     vb = type_vectorbackend()
     from ufl import FiniteElement, MixedElement, VectorElement, EnrichedElement, RestrictedElement
@@ -277,7 +282,7 @@ def typedef_gfs(expr, name):
         args = ", ".join(type_gfs(e) for e in expr._sub_elements)
         return "typedef Dune::PDELab::CompositeGridFunctionSpace<{}, {}, {}> {}".format(vb, ot, args, name)
     if isinstance(expr, VectorElement):
-        dune_include("dune/pdelab/gridfunctionspace/vectorgridfunctionspace.hh")
+        driver_include("dune/pdelab/gridfunctionspace/vectorgridfunctionspace.hh")
         gv = type_leafview()
         fem = type_fem(expr._sub_elements[0])
         dim = name_dimension()
@@ -294,7 +299,7 @@ def type_gfs(expr):
     typedef_gfs(expr, name)
     return "{}_GFS".format(name)
 
-@dune_preamble
+@driver_preamble
 def define_gfs(expr, name):
     gfstype = type_gfs(expr)
     from ufl import FiniteElement, MixedElement, VectorElement, EnrichedElement, RestrictedElement
@@ -320,14 +325,14 @@ def name_gfs(expr):
     define_gfs(expr, name)
     return name
 
-@dune_preamble
+@driver_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(_form.coefficient_elements[0]):
+    if isQuadrilateral(_form.coefficients()[0].element()):
         geo_factor = "4"
     else:
         geo_factor = "6"
-    gfs = name_gfs(_form.coefficient_elements[0])
+    gfs = name_gfs(_form.coefficients()[0].element())
     ini = name_initree()
     return ["int generic_dof_estimate =  {} * {}.maxLocalSize();".format(geo_factor, gfs),
             "int dof_estimate = {}.get<int>(\"istl.number_of_nnz\", generic_dof_estimate);".format(ini)]
@@ -337,9 +342,9 @@ def name_dofestimate():
     define_dofestimate("dofestimate")
     return "dofestimate"
 
-@dune_preamble
+@driver_preamble
 def typedef_matrixbackend(name):
-    dune_include("dune/pdelab/backend/istl/bcrsmatrixbackend.hh")
+    driver_include("dune/pdelab/backend/istl/bcrsmatrixbackend.hh")
     return "typedef Dune::PDELab::istl::BCRSMatrixBackend<> {};".format(name)
 
 @dune_symbol
@@ -347,7 +352,7 @@ def type_matrixbackend():
     typedef_matrixbackend("MatrixBackend")
     return "MatrixBackend"
 
-@dune_preamble
+@driver_preamble
 def define_matrixbackend(name):
     mbtype = type_matrixbackend()
     dof = name_dofestimate()
@@ -358,7 +363,7 @@ def name_matrixbackend():
     define_matrixbackend("mb")
     return "mb"
 
-@dune_preamble
+@driver_preamble
 def typedef_parameters(name):
     return "typedef LocalOperatorParameters {}".format(name)
 
@@ -367,7 +372,7 @@ def type_parameters():
     typedef_parameters("Params")
     return "Params"
 
-@dune_preamble
+@driver_preamble
 def define_parameters(name):
     partype = type_parameters()
     return "{} {}();".format(partype, name)
@@ -377,7 +382,7 @@ def name_parameters():
     define_parameters("params")
     return "params"
 
-@dune_preamble
+@driver_preamble
 def typedef_localoperator(name):
     params = type_parameters()
     return "typedef LocalOperator<{}> {}".format(params, name)
@@ -387,7 +392,7 @@ def type_localoperator():
     typedef_localoperator("LocalOperator")
     return "LocalOperator"
 
-@dune_preamble
+@driver_preamble
 def define_localoperator(name):
     loptype = type_localoperator()
     ini = name_initree()
@@ -399,17 +404,17 @@ def name_localoperator():
     define_localoperator("lop")
     return "lop"
 
-@dune_preamble
+@driver_preamble
 def typedef_gridoperator(name):
-    ugfs = type_gfs(_form.coefficient_elements[0])
-    vgfs = type_gfs(_form.argument_elements[0])
+    ugfs = type_gfs(_form.coefficients()[0].element())
+    vgfs = type_gfs(_form.arguments()[0].element())
     lop = type_localoperator()
-    ucc = type_constraintscontainer(_form.coefficient_elements[0])
-    vcc = type_constraintscontainer(_form.argument_elements[0])
+    ucc = type_constraintscontainer(_form.coefficients()[0].element())
+    vcc = type_constraintscontainer(_form.arguments()[0].element())
     mb = type_matrixbackend()
     df = type_domainfield()
     r = type_range()
-    dune_include("dune/pdelab/gridoperator/gridoperator.hh")
+    driver_include("dune/pdelab/gridoperator/gridoperator.hh")
     return "typedef Dune::PDELab::GridOperator<{}, {}, {}, {}, {}, {}, {}, {}, {}> {}".format(ugfs, vgfs, lop, mb, df, r, r, ucc, vcc, name)
 
 @dune_symbol
@@ -417,13 +422,13 @@ def type_gridoperator():
     typedef_gridoperator("GO")
     return "GO"
 
-@dune_preamble
+@driver_preamble
 def define_gridoperator(name):
     gotype = type_gridoperator()
-    ugfs = name_gfs(_form.coefficient_elements[0])
-    ucc = name_constraintscontainer(_form.coefficient_elements[0])
-    vgfs = name_gfs(_form.argument_elements[0])
-    vcc = name_constraintscontainer(_form.argument_elements[0])
+    ugfs = name_gfs(_form.coefficients()[0].element())
+    ucc = name_constraintscontainer(_form.coefficients()[0].element())
+    vgfs = name_gfs(_form.arguments()[0].element())
+    vcc = name_constraintscontainer(_form.arguments()[0].element())
     lop = name_localoperator()
     mb = name_matrixbackend()
     return "{} {}({}, {}, {}, {}, {}, {});".format(gotype, name, ugfs, ucc, vgfs, vcc, lop, mb)
@@ -433,7 +438,7 @@ def name_gridoperator():
     define_gridoperator("go")
     return "go"
 
-@dune_preamble
+@driver_preamble
 def typedef_vector(name):
     gotype = type_gridoperator()
     return "typedef {}::Traits::Domain {}".format(gotype, name)
@@ -443,10 +448,10 @@ def type_vector():
     typedef_vector("V")
     return "V"
 
-@dune_preamble
+@driver_preamble
 def define_vector(name):
     vtype = type_vector()
-    gfs = name_gfs(_form.coefficient_elements[0])
+    gfs = name_gfs(_form.coefficients()[0].element())
     return ["{} {}({});".format(vtype, name, gfs), "{} = 0.0;".format(name)]
 
 @dune_symbol
@@ -454,9 +459,9 @@ def name_vector():
     define_vector("x")
     return "x"
 
-@dune_preamble
+@driver_preamble
 def typedef_linearsolver(name):
-    dune_include("dune/pdelab/backend/istlsolverbackend.hh")
+    driver_include("dune/pdelab/backend/istlsolverbackend.hh")
     return "typedef Dune::PDELab::ISTLBackend_SEQ_UMFPack {};".format(name)
 
 @dune_symbol
@@ -464,7 +469,7 @@ def type_linearsolver():
     typedef_linearsolver("LinearSolver")
     return "LinearSolver"
 
-@dune_preamble
+@driver_preamble
 def define_linearsolver(name):
     lstype = type_linearsolver()
     return "{} {}(false);".format(lstype, name)
@@ -474,7 +479,7 @@ def name_linearsolver():
     define_linearsolver("ls")
     return "ls"
 
-@dune_preamble
+@driver_preamble
 def define_reduction(name):
     ini = name_initree()
     return "double {} = {}.get<double>(\"reduction\", 1e-12);".format(name, ini)
@@ -486,7 +491,7 @@ def name_reduction():
 
 @dune_symbol
 def typedef_stationarylinearproblemsolver(name):
-    dune_include("dune/pdelab/stationary/linearproblem.hh")
+    driver_include("dune/pdelab/stationary/linearproblem.hh")
     gotype = type_gridoperator()
     lstype = type_linearsolver()
     xtype = type_vector()
@@ -497,7 +502,7 @@ def type_stationarylinearproblemsolver():
     typedef_stationarylinearproblemsolver("SLP")
     return "SLP"
 
-@dune_preamble
+@driver_preamble
 def define_stationarylinearproblemsolver(name):
     slptype = type_stationarylinearproblemsolver()
     go = name_gridoperator()
@@ -511,19 +516,21 @@ def name_stationarylinearproblemsolver():
     define_stationarylinearproblemsolver("slp")
     return "slp"
 
-@dune_preamble
+@driver_preamble
 def dune_solve():
     from ufl.algorithms.predicates import is_multilinear
-    if is_multilinear(_form.preprocessed_form):
+    # This is crap as it does check for linearity of the rank 1 form,
+    # which is by definition True.
+    if is_multilinear(_form):
         slp = name_stationarylinearproblemsolver()
         return "{}.apply();".format(slp)
     else:
-        pass
+        raise NotImplementedError
 
-@dune_preamble
+@driver_preamble
 def define_vtkfile(name):
     ini = name_initree()
-    dune_include("string")
+    driver_include("string")
     return "std::string {} = {}.get<std::string>(\"vtk.filename\", \"output\");".format(name, ini)
 
 @dune_symbol
@@ -531,11 +538,11 @@ def name_vtkfile():
     define_vtkfile("vtkfile")
     return "vtkfile"
 
-@dune_preamble
+@driver_preamble
 def vtkoutput():
-    dune_include("dune/pdelab/gridfunctionspace/vtk.hh")
+    driver_include("dune/pdelab/gridfunctionspace/vtk.hh")
     vtkwriter = name_vtkwriter()
-    gfs = name_gfs(_form.coefficient_elements[0])
+    gfs = name_gfs(_form.coefficients()[0].element())
     vec = name_vector()
     vtkfile = name_vtkfile()
     dune_solve()
diff --git a/python/dune/perftool/pdelab/localoperator.py b/python/dune/perftool/pdelab/localoperator.py
index fc3e3844..ad52006a 100644
--- a/python/dune/perftool/pdelab/localoperator.py
+++ b/python/dune/perftool/pdelab/localoperator.py
@@ -1,13 +1,18 @@
 from __future__ import absolute_import
-from pytools import memoize
+
 from dune.perftool.options import get_option
 from dune.perftool.generation import generator_factory
 from dune.perftool.pdelab import dune_symbol
 
+from cgen import Include
+
+from pytools import memoize
+
 # Define the generators used in-here
-operator_include = generator_factory(item_tags=("pdelab", "include", "operator"), on_store=lambda i: "#include<{}>".format(i), no_deco=True)
+operator_include = generator_factory(item_tags=("pdelab", "include", "operator"), on_store=lambda i: Include(i), no_deco=True)
 base_class = generator_factory(item_tags=("pdelab", "baseclass", "operator"), counted=True, no_deco=True)
 initializer_list = generator_factory(item_tags=("pdelab", "initializer", "operator"), counted=True, no_deco=True)
+
 # TODO definition
 #private_member = generator_factory(item_tags=("pdelab", "member", "privatemember"))
 
@@ -79,10 +84,6 @@ def generate_term(integrand=None, measure=None):
     # Get the measure specifics
     specifics = measure_specific_details(measure)
 
-#     from dune.perftool.ufl.rank import ufl_rank
-#     if ufl_rank(integrand) == 2:
-#         from IPython import embed; embed()
-
     # Now split the given integrand into accumulation expressions
     from dune.perftool.ufl.transformations.extract_accumulation_terms import split_into_accumulation_terms
     accterms = split_into_accumulation_terms(integrand)
@@ -91,10 +92,6 @@ def generate_term(integrand=None, measure=None):
     for term in accterms:
         from dune.perftool.loopy.transformer import transform_accumulation_term
         transform_accumulation_term(term)
-#
-#     # Transform the expression. All relevant results are then in the cache
-#     from dune.perftool.loopy.transformer import transform_expression
-#     transform_expression(integrand)
 
     # Extract the information, which is needed to create a loopy kernel.
     # First extracting it, might be useful to alter it before kernel generation.
@@ -148,7 +145,6 @@ def generate_localoperator(form, operatorfile):
             signature = measure_specific_details(integral.integral_type())["jacobian_signature"]
             operator_methods.append((signature, body))
 
-
     # TODO: JacobianApply for matrix-free computations.
 
     # Manage includes and base classes that we always need
diff --git a/python/dune/perftool/ufl/transformations/__init__.py b/python/dune/perftool/ufl/transformations/__init__.py
index f9ff45ae..d67f112b 100644
--- a/python/dune/perftool/ufl/transformations/__init__.py
+++ b/python/dune/perftool/ufl/transformations/__init__.py
@@ -1,3 +1,5 @@
+""" Define the general infrastructure for debuggable UFL transformations"""
+
 class TransformationWrapper(object):
     def __init__(self, func, **kwargs):
         # Store the decorated function
@@ -37,7 +39,6 @@ class TransformationWrapper(object):
         assert isinstance(expr, Expr)
 
         # Maybe output the input expression!
-        from dune.perftool.options import get_option
         self.write_trafo([expr], True)
 
         # Call the original function
diff --git a/python/dune/perftool/ufl/transformations/argument_elimination.py b/python/dune/perftool/ufl/transformations/argument_elimination.py
index b2e0afa9..70cc660c 100644
--- a/python/dune/perftool/ufl/transformations/argument_elimination.py
+++ b/python/dune/perftool/ufl/transformations/argument_elimination.py
@@ -8,7 +8,6 @@ class EliminateArguments(MultiFunction):
 
     def __call__(self, o):
         from dune.perftool.ufl.modified_terminals import ModifiedArgumentExtractor
-        from dune.perftool.ufl.rank import ufl_rank
 
         self.arguments = ModifiedArgumentExtractor()(o)
         e = self.call(o)
diff --git a/python/setup.py b/python/setup.py
index 8ed37cb0..2ef4dc99 100644
--- a/python/setup.py
+++ b/python/setup.py
@@ -30,7 +30,7 @@ setup(name='dune.perftool',
       author='Dominic Kempf <dominic.kempf@iwr.uni-heidelberg.de>',
       url='http://conan2.iwr.uni-heidelberg.de/git/dominic/dune-perftool',
       packages=['dune.perftool'],
-      install_requires=[],
+      install_requires=['sympy'],
       tests_require=['pytest'],
       cmdclass={'test': PyTest},
       entry_points = {
-- 
GitLab