diff --git a/.gitmodules b/.gitmodules
index 0de93ddeb2191afbd96edcb149447785602fbb95..982bfd26f3903235440402a9fedd5777b2a21785 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -11,3 +11,6 @@
 	path = python/ufl
 	url = https://bitbucket.org/fenics-project/ufl.git
     ignore = untracked
+[submodule "python/pymbolic"]
+	path = python/pymbolic
+	url = https://github.com/inducer/pymbolic.git
diff --git a/python/dune/perftool/__init__.py b/python/dune/perftool/__init__.py
index eb279cf11e48b26b210e9e010b4371635c939f61..02ef874ff476ba7fc9bca5ecf261f0fcf7073edb 100644
--- a/python/dune/perftool/__init__.py
+++ b/python/dune/perftool/__init__.py
@@ -1,4 +1,4 @@
 class Restriction:
     NONE = 0
-    INSIDE = 1
-    OUTSIDE = 2
+    NEGATIVE = 1
+    POSITIVE = 2
diff --git a/python/dune/perftool/compile.py b/python/dune/perftool/compile.py
index 83265ae709953d9731f41ee069acb1768f2b1b04..231792238a7e4e7c60494a241775e178881c3ec2 100644
--- a/python/dune/perftool/compile.py
+++ b/python/dune/perftool/compile.py
@@ -49,6 +49,8 @@ def read_ufl(uflfile):
     form = transform_form(form, reindexing)
 #    form = transform_form(form, split_arguments)
 
+    formdata.preprocessed_form = form
+
     return formdata, data.object_names
 
 
diff --git a/python/dune/perftool/interactive.py b/python/dune/perftool/interactive.py
index a492bc12d0bd564c65efdb837a8fd5fd3ee09647..b84edff8377f366bb051a4ef91db5942c8bf53be 100644
--- a/python/dune/perftool/interactive.py
+++ b/python/dune/perftool/interactive.py
@@ -73,9 +73,11 @@ def show_code(which, kernel):
     clear()
     print("Showing the generated dune-pdelab code for {}:\n".format(kernel_name(which)))
 
-    from dune.perftool.pdelab.localoperator import measure_specific_details, AssemblyMethod
-    signature = measure_specific_details(which[0])["{}_signature".format(which[1])]
-    print("".join(AssemblyMethod(signature, kernel).generate()))
+    from dune.perftool.generation import global_context
+    with global_context(integral_type=which[0], form_type=which[1]):
+        from dune.perftool.pdelab.localoperator import assembly_routine_signature, AssemblyMethod
+        signature = assembly_routine_signature()
+        print("".join(AssemblyMethod(signature, kernel).generate()))
 
     print("Press Return to return to the previous menu")
     input()
diff --git a/python/dune/perftool/loopy/transformer.py b/python/dune/perftool/loopy/transformer.py
index 21c2265d0ebac22dbe7ca454ae20fdd330021203..271abc12123f1e15eb79fc120c545016f9a5e800 100644
--- a/python/dune/perftool/loopy/transformer.py
+++ b/python/dune/perftool/loopy/transformer.py
@@ -8,8 +8,9 @@ from __future__ import absolute_import
 from dune.perftool import Restriction
 from dune.perftool.ufl.modified_terminals import ModifiedTerminalTracker
 from dune.perftool.pymbolic.uflmapper import UFL2PymbolicMapper
-
+from dune.perftool.pdelab.geometry import GeometryMapper
 from dune.perftool.generation import (domain,
+                                      global_context,
                                       globalarg,
                                       iname,
                                       instruction,
@@ -31,7 +32,7 @@ def index_sum_iname(i):
     return name_index(i)
 
 
-class UFL2LoopyVisitor(ModifiedTerminalTracker, UFL2PymbolicMapper):
+class UFL2LoopyVisitor(ModifiedTerminalTracker, UFL2PymbolicMapper, GeometryMapper):
     def __init__(self):
         super(UFL2LoopyVisitor, self).__init__()
 
@@ -73,12 +74,6 @@ class UFL2LoopyVisitor(ModifiedTerminalTracker, UFL2PymbolicMapper):
         # Now continue processing the expression
         return self.call(o.ufl_operands[0])
 
-    # TODO use multiple inheritance and have a geometry transformer in the pdelab subpackage
-    def facet_area(self, o):
-        from pymbolic.primitives import Variable
-        from dune.perftool.pdelab.geometry import name_facetarea
-        return Variable(name_facetarea())
-
 
 class _Counter:
     counter = 0
@@ -106,19 +101,21 @@ def transform_accumulation_term(term, measure, subdomain_id):
 
     rmap = {}
     for ma in test_ma:
-        # Set up the local function space structure
-        traverse_lfs_tree(ma)
+        with global_context(restriction=ma.restriction):
+            # Set up the local function space structure
+            traverse_lfs_tree(ma)
 
-        # Get the expression for the modified argument representing the test function
-        from dune.perftool.pdelab.argument import pymbolic_testfunction
-        rmap[ma.expr] = pymbolic_testfunction(ma)
+            # Get the expression for the modified argument representing the test function
+            from dune.perftool.pdelab.argument import pymbolic_testfunction
+            rmap[ma.expr] = pymbolic_testfunction(ma)
     for ma in trial_ma:
-        # Set up the local function space structure
-        traverse_lfs_tree(ma)
+        with global_context(restriction=ma.restriction):
+            # Set up the local function space structure
+            traverse_lfs_tree(ma)
 
-        # Get the expression for the modified argument representing the trial function
-        from dune.perftool.pdelab.argument import pymbolic_trialfunction
-        rmap[ma.expr] = pymbolic_trialfunction(ma)
+            # Get the expression for the modified argument representing the trial function
+            from dune.perftool.pdelab.argument import pymbolic_trialfunction
+            rmap[ma.expr] = pymbolic_trialfunction(ma)
 
     # Get the transformer!
     ufl2l_mf = UFL2LoopyVisitor()
diff --git a/python/dune/perftool/pdelab/__init__.py b/python/dune/perftool/pdelab/__init__.py
index 4d5762dd4687a2e7fa8cd7b8e4d2a4865484c3e6..801c50f8ed32307a8018b62bc2d5c91e3e170643 100644
--- a/python/dune/perftool/pdelab/__init__.py
+++ b/python/dune/perftool/pdelab/__init__.py
@@ -10,7 +10,10 @@ from dune.perftool.generation import (preamble,
 def name_index(index):
     from ufl.classes import MultiIndex, Index
     if isinstance(index, Index):
-        return str(index)
+        # This failed for index > 9 because ufl placed curly brackets around
+        # return str(index)
+        return "i_{}".format(index.count())
     if isinstance(index, MultiIndex):
         assert len(index) == 1
-        return str(index._indices[0])
+        # return str(index._indices[0])
+        return "i_{}".format(index._indices[0].count())
diff --git a/python/dune/perftool/pdelab/basis.py b/python/dune/perftool/pdelab/basis.py
index 2015ac7322debd8ddd2d477cac755ef8cc9e3140..b8d5a07c6b4e2a24e4ffd7f34d903f4afc26cf43 100644
--- a/python/dune/perftool/pdelab/basis.py
+++ b/python/dune/perftool/pdelab/basis.py
@@ -269,7 +269,7 @@ def evaluate_trialfunction(element, name):
     temporary_variable(name, shape=())
     lfs = name_lfs(element)
     index = lfs_iname(element)
-    basis = name_basis()
+    basis = name_basis(element)
     instruction(inames=(quadrature_iname(),
                         index,
                         ),
diff --git a/python/dune/perftool/pdelab/driver.py b/python/dune/perftool/pdelab/driver.py
index 556fbfb818ed12ab3efb2f226afb2b448c9971e3..56dfb86092a6c2cae9b151cbb68e94e227528c50 100644
--- a/python/dune/perftool/pdelab/driver.py
+++ b/python/dune/perftool/pdelab/driver.py
@@ -63,6 +63,10 @@ def isQk(fem):
     return isLagrange(fem) and isQuadrilateral(fem)
 
 
+def isDG(fem):
+    return fem._short_name is 'DG'
+
+
 def FEM_name_mangling(fem):
     from ufl import MixedElement, VectorElement, FiniteElement
     if isinstance(fem, MixedElement):
@@ -79,6 +83,9 @@ def FEM_name_mangling(fem):
             return "P" + str(fem._degree)
         if isQk(fem):
             return "Q" + str(fem._degree)
+        if isDG(fem):
+            return "DG" + str(fem._degree)
+
     raise NotImplementedError("FEM NAME MANGLING")
 
 
@@ -242,12 +249,23 @@ 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 "typedef Dune::PDELab::PkLocalFiniteElementMap<{}, {}, {}, {}> {};".format(gv, df, r, expr._degree, name)
-    if isQk(generator._kwargs['expr']):
+    if isQk(expr):
         include_file("dune/pdelab/finiteelementmap/qkfem.hh", filetag="driver")
         return "typedef Dune::PDELab::QkLocalFiniteElementMap<{}, {}, {}, {}> {};".format(gv, df, r, expr._degree, name)
+    if isDG(expr):
+        if isQuadrilateral(expr):
+            include_file("dune/pdelab/finiteelementmap/qkdg.hh", filetag="driver")
+            # TODO allow switching the basis here!
+            return "typedef Dune::PDELab::QkDGLocalFiniteElementMap<{}, {}, {}, {}> {}".format(df, r, expr._degree, dim, name)
+        if isSimplical(expr):
+            include_file("dune/pdelab/finiteelementmap/opbfem.hh", filetag="driver")
+            return "typedef Dune::PDELab::OPBLocalFiniteElementMap<{}, {}, {}, {}, Dune::GeometryType::cube> {}".format(df, r, expr._degree, dim, name)
+        raise NotImplementedError("Geometry type not known in code generation")
+
     raise NotImplementedError("FEM not implemented in dune-perftool")
 
 
@@ -261,8 +279,11 @@ def type_fem(expr):
 @preamble
 def define_fem(expr, name):
     femtype = type_fem(expr)
-    gv = name_leafview()
-    return "{} {}({});".format(femtype, name, gv)
+    if isDG(expr):
+        return "{} {};".format(femtype, name)
+    else:
+        gv = name_leafview()
+        return "{} {}({});".format(femtype, name, gv)
 
 
 @symbol
diff --git a/python/dune/perftool/pdelab/geometry.py b/python/dune/perftool/pdelab/geometry.py
index 4e0f5ab6e75b70f644bbfa44e6c8993ce63700ab..4bbfa6d54d5d25a28e139da8ffe46383f91b389a 100644
--- a/python/dune/perftool/pdelab/geometry.py
+++ b/python/dune/perftool/pdelab/geometry.py
@@ -6,6 +6,37 @@ from dune.perftool.generation import (preamble,
 from dune.perftool.pdelab.quadrature import (name_quadrature_position,
                                              quadrature_preamble,
                                              )
+from ufl.algorithms import MultiFunction
+
+
+class GeometryMapper(MultiFunction):
+    """
+    A collection of visitors for geometry related UFL nodes
+    NB: This is kind of 'abstract' as it needs to be combined
+        with a ModifiedTerminalTracker through multi inheritance.
+    """
+    def __init__(self):
+        super(GeometryMapper, self).__init__()
+
+    def facet_normal(self, o):
+        # The normal must be restricted to be well-defined
+        assert self.restriction is not Restriction.NONE
+
+        from pymbolic.primitives import Variable
+        if self.restriction == Restriction.POSITIVE:
+            return Variable(name_unit_outer_normal())
+        if self.restriction == Restriction.NEGATIVE:
+            # It is highly unnatural to have this generator function,
+            # but I do run into subtle trouble with return -1*outer
+            # as the indexing into the normal happens only later.
+            # Not investing more time into this cornercase right now.
+            return Variable(name_unit_inner_normal())
+
+    # TODO This one was just copied over so, it might need some tweaking
+    def facet_area(self, o):
+        from pymbolic.primitives import Variable
+        from dune.perftool.pdelab.geometry import name_facetarea
+        return Variable(name_facetarea())
 
 
 @symbol
@@ -55,7 +86,7 @@ def type_geometry_wrapper():
 @preamble
 def define_restricted_cell(name, restriction):
     ig = name_intersection_geometry_wrapper()
-    which = "inside" if restriction == Restriction.INSIDE else "outside"
+    which = "inside" if restriction == Restriction.NEGATIVE else "outside"
     return "const auto& {} = {}.{}();".format(name,
                                               ig,
                                               which,
@@ -68,7 +99,7 @@ def _name_cell(restriction):
         eg = name_element_geometry_wrapper()
         return "{}.entity()".format(eg)
 
-    which = "inside" if restriction == Restriction.INSIDE else "outside"
+    which = "inside" if restriction == Restriction.NEGATIVE else "outside"
     name = "cell_{}".format(which)
     define_restricted_cell(name, restriction)
     return name
@@ -81,7 +112,7 @@ def name_cell():
     if it == 'cell':
         r = Restriction.NONE
     if it == 'exterior_facet':
-        r = Restriction.INSIDE
+        r = Restriction.NEGATIVE
     if it == 'interior_facet':
         raise NotImplementedError
 
@@ -138,7 +169,7 @@ def name_geometry():
 def define_in_cell_geometry(restriction, name):
     cell = _name_cell(restriction)
     ig = name_intersection_geometry_wrapper()
-    which = "In" if restriction == Restriction.INSIDE else "Out"
+    which = "In" if restriction == Restriction.NEGATIVE else "Out"
     return "auto {} = {}.geometryIn{}side();".format(name,
                                                      ig,
                                                      which
@@ -149,7 +180,7 @@ def define_in_cell_geometry(restriction, name):
 def name_in_cell_geometry(restriction):
     assert restriction is not Restriction.NONE
 
-    name = "geo_in_{}side".format("in" if restriction is Restriction.INSIDE else "out")
+    name = "geo_in_{}side".format("in" if restriction is Restriction.NEGATIVE else "out")
     define_in_cell_geometry(restriction, name)
     return name
 
@@ -168,7 +199,7 @@ def apply_in_cell_transformation(name, local, restriction):
 def name_in_cell_coordinates(local, basename, restriction):
     name = "{}_in_inside".format(basename)
     temporary_variable(name, shape=(name_dimension(),), shape_impl=("fv",))
-    apply_in_cell_transformation(name, local, restriction=Restriction.INSIDE)
+    apply_in_cell_transformation(name, local, restriction=Restriction.NEGATIVE)
     return name
 
 
@@ -179,9 +210,10 @@ def to_cell_coordinates(local, basename):
     if it == 'cell':
         return local
     if it == 'exterior_facet':
-        return name_in_cell_coordinates(local, basename, Restriction.INSIDE)
+        return name_in_cell_coordinates(local, basename, Restriction.NEGATIVE)
     if it == 'interior_facet':
-        raise NotImplementedError
+        restriction = get_global_context_value("restriction")
+        return name_in_cell_coordinates(local, basename, restriction)
 
 
 @preamble
@@ -196,6 +228,44 @@ def name_dimension():
     return "dim"
 
 
+def evaluate_unit_outer_normal(name):
+    ig = name_intersection_geometry_wrapper()
+    qp = name_quadrature_position()
+    return quadrature_preamble("{} = {}.unitOuterNormal({});".format(name, ig, qp),
+                               assignees=frozenset({name}),
+                               )
+
+
+@preamble
+def declare_normal(name, shape, shape_impl):
+    ig = name_intersection_geometry_wrapper()
+    return "auto {} = {}.centerUnitOuterNormal();".format(name, ig)
+
+
+@symbol
+def name_unit_outer_normal():
+    name = "outer_normal"
+    temporary_variable(name, shape=(name_dimension(),), decl_method=declare_normal)
+    evaluate_unit_outer_normal(name)
+    return "outer_normal"
+
+
+def evaluate_unit_inner_normal(name):
+    outer = name_unit_outer_normal()
+    return quadrature_preamble("auto {} = -1. * {};".format(name, outer),
+                               assignees=frozenset({name}),
+                               read_variables=frozenset({outer}),
+                               )
+
+
+@symbol
+def name_unit_inner_normal():
+    name = "inner_normal"
+    temporary_variable(name, shape=(name_dimension(),), decl_method=declare_normal)
+    evaluate_unit_inner_normal(name)
+    return "inner_normal"
+
+
 @symbol
 def type_jacobian_inverse_transposed():
     geo = type_element_geometry_wrapper()
diff --git a/python/dune/perftool/pymbolic/uflmapper.py b/python/dune/perftool/pymbolic/uflmapper.py
index 18b03cc1c82b95ed4d53f07d9b1a3420eb2e3d47..854c476235165ff0f617a96bf9bb3f1b7da692af 100644
--- a/python/dune/perftool/pymbolic/uflmapper.py
+++ b/python/dune/perftool/pymbolic/uflmapper.py
@@ -24,12 +24,12 @@ class UFL2PymbolicMapper(MultiFunction):
         return Product(tuple(self.call(op) for op in get_operands(o)))
 
     def multi_index(self, o):
-        return tuple(self.call(op) for op in o.ufl_operands)
+        from dune.perftool.pdelab import name_index
+        return tuple(Variable(name_index(op)) for op in o.indices())
 
     def index(self, o):
         # One might as well take the uflname as string here, but I apply this function
         from dune.perftool.pdelab import name_index
-
         return Variable(name_index(o))
 
     def fixed_index(self, o):
diff --git a/python/dune/perftool/ufl/modified_terminals.py b/python/dune/perftool/ufl/modified_terminals.py
index 6beed959b0c0cd372114be603a8eeaae2190f122..b992dc05f2fe76fb68c76b336bd46cf580c96277 100644
--- a/python/dune/perftool/ufl/modified_terminals.py
+++ b/python/dune/perftool/ufl/modified_terminals.py
@@ -18,14 +18,22 @@ class ModifiedTerminalTracker(MultiFunction):
     def positive_restricted(self, o):
         assert self.restriction == Restriction.NONE
         self.restriction = Restriction.POSITIVE
-        ret = self.call(o.ufl_operands[0])
+
+        from dune.perftool.generation import global_context
+        with global_context(restriction=Restriction.POSITIVE):
+            ret = self.call(o.ufl_operands[0])
+
         self.restriction = Restriction.NONE
         return ret
 
     def negative_restricted(self, o):
         assert self.restriction == Restriction.NONE
         self.restriction = Restriction.NEGATIVE
-        ret = self.call(o.ufl_operands[0])
+
+        from dune.perftool.generation import global_context
+        with global_context(restriction=Restriction.NEGATIVE):
+            ret = self.call(o.ufl_operands[0])
+
         self.restriction = Restriction.NONE
         return ret
 
diff --git a/python/dune/perftool/ufl/transformations/extract_accumulation_terms.py b/python/dune/perftool/ufl/transformations/extract_accumulation_terms.py
index 2b8505c56d77e790ad875bc454bd995c1423f2b8..c783d88229a995eafe741d9c1d0443c822dd08dc 100644
--- a/python/dune/perftool/ufl/transformations/extract_accumulation_terms.py
+++ b/python/dune/perftool/ufl/transformations/extract_accumulation_terms.py
@@ -19,7 +19,7 @@ class _ReplacementDict(dict):
     def __init__(self, good=[], bad=[]):
         dict.__init__(self)
         for a in bad:
-            self[a] = Zero()
+            self[a] = Zero(shape=a.ufl_shape, free_indices=a.ufl_free_indices, index_dimensions=a.ufl_index_dimensions)
         for a in good:
             self[a] = a
 
diff --git a/python/pymbolic b/python/pymbolic
new file mode 160000
index 0000000000000000000000000000000000000000..80ef7a7745829f53ae949f68ad458b88c06d66a0
--- /dev/null
+++ b/python/pymbolic
@@ -0,0 +1 @@
+Subproject commit 80ef7a7745829f53ae949f68ad458b88c06d66a0
diff --git a/test/laplace/laplace_dg.ufl b/test/laplace/laplace_dg.ufl
index f1bffa46e0cf2945d06f29cafb83b89b5cb06297..3c89fbb7648410f3117a781bc41ca12333deff57 100644
--- a/test/laplace/laplace_dg.ufl
+++ b/test/laplace/laplace_dg.ufl
@@ -4,14 +4,17 @@ V = FiniteElement("DG", cell, 1)
 u = TrialFunction(V)
 v = TestFunction(V)
 
-n = FacetNormal(cell)
+n = FacetNormal(cell)('+')
 
 gamma = 1.0
 theta = 1.0
 
 r = inner(grad(u), grad(v))*dx \
-  - inner(n, avg(grad(u)))*jump(v)*(dS+ds) \
-  + gamma*jump(u)*jump(v)*(dS+ds) \
-  - theta*jump(u)*inner(grad(v), n)*(dS+ds)
+  - inner(n, avg(grad(u)))*jump(v)*dS \
+  + gamma*jump(u)*jump(v)*dS \
+  - theta*jump(u)*inner(avg(grad(v)), n)*dS \
+  - inner(n, grad(u))*v*ds \
+  + gamma*u*v*ds \
+  - theta*u*inner(grad(v), n)*ds
 
 forms = [r]