diff --git a/dune/perftool/sumfact/invertgeometry.hh b/dune/perftool/sumfact/invertgeometry.hh
new file mode 100644
index 0000000000000000000000000000000000000000..a09f5e5227fd7f2d3e28e5c63a61984eba2706ef
--- /dev/null
+++ b/dune/perftool/sumfact/invertgeometry.hh
@@ -0,0 +1,19 @@
+#ifndef DUNE_PERFTOOL_SUMFACT_INVERTGEOMETRY_HH
+#define DUNE_PERFTOOL_SUMFACT_INVERTGEOMETRY_HH
+
+
+template<typename T>
+inline T invert_and_return_determinant(const T a00, const T a10, const T a01, const T a11, T jacobian_inverse[4]){
+  T det = a00 * a11 - a10 * a01;
+  assert (det != 0.0);
+
+  jacobian_inverse[0] = a11 / det;
+  jacobian_inverse[1] = -a10 / det;
+  jacobian_inverse[2] = -a01 / det;
+  jacobian_inverse[3] = a00 / det;
+
+  return std::abs(det);
+}
+
+
+#endif
diff --git a/python/dune/perftool/blockstructured/__init__.py b/python/dune/perftool/blockstructured/__init__.py
index 8849491e8e6c31f33f1a1c5d9a1e247122158137..5c1283b2096cf8bcfe55ef107c77d1ece2f8aa5e 100644
--- a/python/dune/perftool/blockstructured/__init__.py
+++ b/python/dune/perftool/blockstructured/__init__.py
@@ -9,7 +9,7 @@ from dune.perftool.pdelab.quadrature import pymbolic_quadrature_position
 from dune.perftool.blockstructured.spaces import lfs_inames
 from dune.perftool.blockstructured.basis import (pymbolic_reference_gradient,
                                                  pymbolic_basis)
-from dune.perftool.blockstructured.geometry import (pymbolic_jacobian_inverse_transposed,
+from dune.perftool.blockstructured.geometry import (pymbolic_jacobian_inverse,
                                                     pymbolic_jacobian_determinant,
                                                     pymbolic_facet_jacobian_determinant,
                                                     to_global)
@@ -55,8 +55,8 @@ class BlockStructuredInterface(PDELabInterface):
     def pymbolic_jacobian_determinant(self):
         return pymbolic_jacobian_determinant()
 
-    def pymbolic_jacobian_inverse_transposed(self, i, j, restriction):
-        return pymbolic_jacobian_inverse_transposed(i, j, restriction)
+    def pymbolic_jacobian_inverse(self, i, j, restriction):
+        return pymbolic_jacobian_inverse(i, j, restriction)
 
     def pymbolic_facet_jacobian_determinant(self):
         return pymbolic_facet_jacobian_determinant()
diff --git a/python/dune/perftool/blockstructured/geometry.py b/python/dune/perftool/blockstructured/geometry.py
index 1ffbdf0417c8261d2f0882b2384ed044af1ddd03..113f5940b0389e215c7fbaf732d812a9226dd26e 100644
--- a/python/dune/perftool/blockstructured/geometry.py
+++ b/python/dune/perftool/blockstructured/geometry.py
@@ -19,7 +19,7 @@ def pymbolic_jacobian_determinant():
 
 
 # scale Jacobian according to the order of the blockstructure
-def pymbolic_jacobian_inverse_transposed(i, j, restriction):
+def pymbolic_jacobian_inverse(i, j, restriction):
     name_jit = get_backend(interface="name_jit", selector=option_switch("constant_transformation_matrix"))(restriction)
     return prim.Product((get_form_option("number_of_blocks"),
                          prim.Subscript(prim.Variable(name_jit), (j, i))))
diff --git a/python/dune/perftool/pdelab/__init__.py b/python/dune/perftool/pdelab/__init__.py
index d3153ca0b8612b5391843a8689fa2c1c9d16bc56..f53b6ff6297efdde79344c49579e466ccd99d817 100644
--- a/python/dune/perftool/pdelab/__init__.py
+++ b/python/dune/perftool/pdelab/__init__.py
@@ -19,7 +19,7 @@ from dune.perftool.pdelab.geometry import (component_iname,
                                            pymbolic_facet_area,
                                            pymbolic_facet_jacobian_determinant,
                                            pymbolic_jacobian_determinant,
-                                           pymbolic_jacobian_inverse_transposed,
+                                           pymbolic_jacobian_inverse,
                                            pymbolic_unit_inner_normal,
                                            pymbolic_unit_outer_normal,
                                            to_global,
@@ -125,8 +125,8 @@ class PDELabInterface(object):
     def pymbolic_jacobian_determinant(self):
         return pymbolic_jacobian_determinant()
 
-    def pymbolic_jacobian_inverse_transposed(self, i, j, restriction):
-        return pymbolic_jacobian_inverse_transposed(i, j, restriction)
+    def pymbolic_jacobian_inverse(self, i, j, restriction):
+        return pymbolic_jacobian_inverse(i, j, restriction)
 
     def pymbolic_unit_inner_normal(self):
         return pymbolic_unit_inner_normal()
diff --git a/python/dune/perftool/pdelab/geometry.py b/python/dune/perftool/pdelab/geometry.py
index 39a46f211fb85e48384943ee46fd13880514b518..16f75495847532accedfd4e35a5a9c6a4bc2636c 100644
--- a/python/dune/perftool/pdelab/geometry.py
+++ b/python/dune/perftool/pdelab/geometry.py
@@ -204,14 +204,14 @@ def name_in_cell_geometry(restriction):
 # TODO is it always necessary to add quadrature inames?
 def apply_in_cell_transformation(name, local, restriction):
     geo = name_in_cell_geometry(restriction)
-    return get_backend("quadrature_preamble")("{} = {}.global({});".format(name,
-                                                                           geo,
-                                                                           str(local),
-                                                                           ),
-                                              assignees=frozenset({name}),
-                                              read_variables=frozenset({get_pymbolic_basename(local)}),
-                                              depends_on=frozenset({Writes(get_pymbolic_basename(local))}),
-                                              )
+    return quadrature_preamble("{} = {}.global({});".format(name,
+                                                            geo,
+                                                            str(local),
+                                                            ),
+                               assignees=frozenset({name}),
+                               read_variables=frozenset({get_pymbolic_basename(local)}),
+                               depends_on=frozenset({Writes(get_pymbolic_basename(local))}),
+                               )
 
 
 def pymbolic_in_cell_coordinates(local, restriction):
@@ -253,11 +253,11 @@ def local_dimension():
 def evaluate_unit_outer_normal(name):
     ig = name_intersection_geometry_wrapper()
     qp = get_backend("quad_pos")()
-    return get_backend("quadrature_preamble")("{} = {}.unitOuterNormal({});".format(name, ig, qp),
-                                              assignees=frozenset({name}),
-                                              read_variables=frozenset({get_pymbolic_basename(qp)}),
-                                              depends_on=frozenset({Writes(get_pymbolic_basename(qp))}),
-                                              )
+    return quadrature_preamble("{} = {}.unitOuterNormal({});".format(name, ig, qp),
+                               assignees=frozenset({name}),
+                               read_variables=frozenset({get_pymbolic_basename(qp)}),
+                               depends_on=frozenset({Writes(get_pymbolic_basename(qp))}),
+                               )
 
 
 @preamble
@@ -267,7 +267,7 @@ def declare_normal(name, kernel, decl_info):
 
 
 def pymbolic_unit_outer_normal():
-    name = "outer_normal"
+    name = "unit_outer_normal"
     if not get_form_option("diagonal_transformation_matrix"):
         temporary_variable(name, shape=(world_dimension(),), decl_method=declare_normal)
         evaluate_unit_outer_normal(name)
@@ -340,14 +340,14 @@ def define_jacobian_inverse_transposed(name, restriction):
     geo = name_cell_geometry(restriction)
     pos = get_backend("qp_in_cell", selector=option_switch(("blockstructured", "sumfact")))(restriction)
 
-    return get_backend("quadrature_preamble")("{} = {}.jacobianInverseTransposed({});".format(name,
-                                                                                              geo,
-                                                                                              str(pos),
-                                                                                              ),
-                                              assignees=frozenset({name}),
-                                              read_variables=frozenset({get_pymbolic_basename(pos)}),
-                                              depends_on=frozenset({Writes(get_pymbolic_basename(pos))}),
-                                              )
+    return quadrature_preamble("{} = {}.jacobianInverseTransposed({});".format(name,
+                                                                               geo,
+                                                                               str(pos),
+                                                                               ),
+                               assignees=frozenset({name}),
+                               read_variables=frozenset({get_pymbolic_basename(pos)}),
+                               depends_on=frozenset({Writes(get_pymbolic_basename(pos))}),
+                               )
 
 
 @backend(interface="name_jit", name="default")
@@ -357,10 +357,11 @@ def name_jacobian_inverse_transposed(restriction):
     return name
 
 
-def pymbolic_jacobian_inverse_transposed(i, j, restriction):
+def pymbolic_jacobian_inverse(i, j, restriction):
+    # Calculate jacobian_inverse_transposed
     name = get_backend(interface="name_jit", selector=option_switch("constant_transformation_matrix"))(restriction)
-    # Dune only has JacobianInverseTransposed as a first class citizen,
-    # so we need to switch the indices around!
+
+    # Return jacobian inverse -> (j, i) instead of (i, j)
     return prim.Subscript(prim.Variable(name), (j, i))
 
 
@@ -397,11 +398,11 @@ def define_jacobian_determinant(name):
                                                     str(pos),
                                                     )
 
-    return get_backend("quadrature_preamble")(code,
-                                              assignees=frozenset({name}),
-                                              read_variables=frozenset({get_pymbolic_basename(pos)}),
-                                              depends_on=frozenset({Writes(get_pymbolic_basename(pos))}),
-                                              )
+    return quadrature_preamble(code,
+                               assignees=frozenset({name}),
+                               read_variables=frozenset({get_pymbolic_basename(pos)}),
+                               depends_on=frozenset({Writes(get_pymbolic_basename(pos))}),
+                               )
 
 
 @backend(interface="fdetjac", name="constant_transformation_matrix")
diff --git a/python/dune/perftool/pdelab/quadrature.py b/python/dune/perftool/pdelab/quadrature.py
index 6100879930e8eca6d88054538df5084a365d76f3..031d97b019df0cab8355d4295b5229584e077b9b 100644
--- a/python/dune/perftool/pdelab/quadrature.py
+++ b/python/dune/perftool/pdelab/quadrature.py
@@ -61,7 +61,6 @@ def quadrature_inames():
     return (quadrature_iname(),)
 
 
-@backend(interface="quadrature_preamble")
 def quadrature_preamble(code, **kw):
     kw['tags'] = kw.get('tags', frozenset({})).union(frozenset({"quad"}))
     return instruction(inames=get_backend(interface="quad_inames")(), code=code, **kw)
diff --git a/python/dune/perftool/sumfact/__init__.py b/python/dune/perftool/sumfact/__init__.py
index d5eed5544f52c76be02cce4e59455d5a53770ba1..d3192b6f278bc7e0d050a500da86a09d905a4a7e 100644
--- a/python/dune/perftool/sumfact/__init__.py
+++ b/python/dune/perftool/sumfact/__init__.py
@@ -78,37 +78,25 @@ class SumFactInterface(PDELabInterface):
         return ret
 
     def pymbolic_unit_outer_normal(self):
-        from dune.perftool.generation import global_context
-        with global_context(visitor=self.visitor):
-            from dune.perftool.sumfact.geometry import pymbolic_unit_outer_normal
-            ret, indices = pymbolic_unit_outer_normal(self.visitor.indices)
-        self.visitor.indices = indices
-        return ret
+        from dune.perftool.sumfact.geometry import pymbolic_unit_outer_normal
+        return pymbolic_unit_outer_normal(self.visitor)
 
     def pymbolic_unit_inner_normal(self):
         from dune.perftool.sumfact.geometry import pymbolic_unit_inner_normal
-        ret, indices = pymbolic_unit_inner_normal(self.visitor.indices)
-        self.visitor.indices = indices
-        return ret
+        return pymbolic_unit_inner_normal(self.visitor)
 
     def pymbolic_facet_jacobian_determinant(self):
-        from dune.perftool.generation import global_context
-        with global_context(visitor=self.visitor):
-            from dune.perftool.sumfact.geometry import pymbolic_facet_jacobian_determinant
-            return pymbolic_facet_jacobian_determinant()
+        from dune.perftool.sumfact.geometry import pymbolic_facet_jacobian_determinant
+        return pymbolic_facet_jacobian_determinant(self.visitor)
 
     def pymbolic_facet_area(self):
         from dune.perftool.sumfact.geometry import pymbolic_facet_area
-        return pymbolic_facet_area()
+        return pymbolic_facet_area(self.visitor)
 
-    def pymbolic_jacobian_inverse_transposed(self, i, j, restriction):
-        from dune.perftool.pdelab.geometry import pymbolic_jacobian_inverse_transposed
-        from dune.perftool.generation import global_context
-        with global_context(visitor=self.visitor):
-            return pymbolic_jacobian_inverse_transposed(i, j, restriction)
+    def pymbolic_jacobian_inverse(self, i, j, restriction):
+        from dune.perftool.sumfact.geometry import pymbolic_jacobian_inverse
+        return pymbolic_jacobian_inverse(i, j, restriction, self.visitor)
 
     def pymbolic_jacobian_determinant(self):
-        from dune.perftool.pdelab.geometry import pymbolic_jacobian_determinant
-        from dune.perftool.generation import global_context
-        with global_context(visitor=self.visitor):
-            return pymbolic_jacobian_determinant()
+        from dune.perftool.sumfact.geometry import pymbolic_jacobian_determinant
+        return pymbolic_jacobian_determinant(self.visitor)
diff --git a/python/dune/perftool/sumfact/accumulation.py b/python/dune/perftool/sumfact/accumulation.py
index 4e7c2a6991b1c6bda49862de0aa47167c1b1ea2a..abad6788cb31f90276dbde32e2fb5aa2b6faa3af 100644
--- a/python/dune/perftool/sumfact/accumulation.py
+++ b/python/dune/perftool/sumfact/accumulation.py
@@ -24,7 +24,6 @@ from dune.perftool.options import (get_form_option,
                                    )
 from dune.perftool.loopy.flatten import flatten_index
 from dune.perftool.loopy.target import type_floatingpoint
-from dune.perftool.sumfact.quadrature import nest_quadrature_loops
 from dune.perftool.pdelab.driver import FEM_name_mangling
 from dune.perftool.pdelab.localoperator import determine_accumulation_space
 from dune.perftool.pdelab.restriction import restricted_name
diff --git a/python/dune/perftool/sumfact/geometry.py b/python/dune/perftool/sumfact/geometry.py
index f3e5b9fde10587ffb02f802b6984b3309f9b52b5..ecec31af151da1d9bbfda0e8a6ac46ac44b8cf94 100644
--- a/python/dune/perftool/sumfact/geometry.py
+++ b/python/dune/perftool/sumfact/geometry.py
@@ -6,38 +6,71 @@ from dune.perftool.generation import (backend,
                                       get_backend,
                                       get_counted_variable,
                                       iname,
+                                      include_file,
                                       instruction,
                                       kernel_cached,
                                       preamble,
+                                      silenced_warning,
                                       temporary_variable,
+                                      get_global_context_value,
                                       globalarg,
+                                      valuearg,
                                       )
+from dune.perftool.options import get_option
 from dune.perftool.pdelab.geometry import (local_dimension,
                                            world_dimension,
+                                           name_cell_geometry,
                                            name_geometry,
                                            )
-from dune.perftool.sumfact.switch import get_facedir
-from dune.perftool.sumfact.symbolic import SumfactKernelInterfaceBase
+from dune.perftool.pdelab.localoperator import (name_ansatz_gfs_constructor_param,
+                                                lop_template_ansatz_gfs,
+                                                lop_template_range_field,
+                                                )
+from dune.perftool.pdelab.restriction import restricted_name
+from dune.perftool.sumfact.basis import construct_basis_matrix_sequence
+from dune.perftool.sumfact.quadrature import (additional_inames,
+                                              default_quadrature_inames)
+from dune.perftool.sumfact.realization import (name_buffer_storage,
+                                               realize_sum_factorization_kernel,
+                                               )
+from dune.perftool.sumfact.switch import get_facedir, get_facemod
+from dune.perftool.sumfact.symbolic import SumfactKernelInterfaceBase, SumfactKernel
+from dune.perftool.sumfact.tabulation import (quadrature_points_per_direction,
+                                              BasisTabulationMatrix,
+                                              )
 from dune.perftool.sumfact.vectorization import attach_vectorization_info
+from dune.perftool.tools import get_pymbolic_basename
 from dune.perftool.options import get_form_option, option_switch
 from dune.perftool.ufl.modified_terminals import Restriction
 
 from pytools import ImmutableRecord
 
+from loopy.match import Writes
+
 import pymbolic.primitives as prim
 import numpy as np
 
 
 @iname
-def corner_iname():
-    name = get_counted_variable("corneriname")
-    domain(name, 2 ** local_dimension())
+def global_corner_iname(restriction):
+    name = get_counted_variable(restricted_name("global_corneriname", restriction))
+    domain(name, 2 ** world_dimension())
     return name
 
 
 class GeoCornersInput(SumfactKernelInterfaceBase, ImmutableRecord):
-    def __init__(self, dir):
-        ImmutableRecord.__init__(self, dir=dir)
+    def __init__(self, direction, restriction):
+        """Base class for sum-factorized evaluation of geometry mappings
+
+        At the moment we only do this for cells and not faces. For
+        intersections we do this corresponding reference elements of the
+        neigboring cells.
+
+        Each spatial component needs a seperate sum factorization kernel.  The
+        argument 'direction' specifies the component (x-component: 0,
+        y-component: 1, z-component: 2).
+        """
+        ImmutableRecord.__init__(self, direction=direction, restriction=restriction)
 
     @property
     def stage(self):
@@ -48,18 +81,22 @@ class GeoCornersInput(SumfactKernelInterfaceBase, ImmutableRecord):
 
     def realize(self, sf, insn_dep):
         # TODO: When we use vectorization this should be the offset
+        assert(get_form_option('vectorization_strategy') == 'none')
         index = 0
 
-        from dune.perftool.sumfact.realization import name_buffer_storage
+        # Note: world_dimension, since we only do evaluation of cell geometry mappings
         name = "input_{}".format(sf.buffer)
         temporary_variable(name,
-                           shape=(2 ** local_dimension(), sf.vector_width),
+                           shape=(2 ** world_dimension(), sf.vector_width),
                            custom_base_storage=name_buffer_storage(sf.buffer, 0),
                            managed=True,
                            )
+        ciname = global_corner_iname(self.restriction)
 
-        ciname = corner_iname()
-        geo = name_geometry()
+        if self.restriction == 0:
+            geo = name_geometry()
+        else:
+            geo = name_cell_geometry(self.restriction)
 
         # NB: We need to realize this as a C instruction, because the corner
         #     method does return a non-scalar, which does not fit into the current
@@ -71,7 +108,7 @@ class GeoCornersInput(SumfactKernelInterfaceBase, ImmutableRecord):
                                                           index,
                                                           geo,
                                                           ciname,
-                                                          self.dir,
+                                                          self.direction,
                                                           )
 
         insn = instruction(code=code,
@@ -85,23 +122,33 @@ class GeoCornersInput(SumfactKernelInterfaceBase, ImmutableRecord):
 
 @backend(interface="spatial_coordinate", name="default")
 def pymbolic_spatial_coordinate_multilinear(do_predicates, visitor):
+    """Calculate global coordinates of quadrature points for multilinear geometry mappings
+
+    The evalualation is done using sum factorization techniques.
+
+    On facets we use the geometry mapping of the self cell to get a global
+    evaluation of the quadrature points. Avoiding the geometry mapping of the
+    face itself greatly simplifies the generation of code for unstructured
+    grids. Instead of looking at all the possible embeddings of the reference
+    element of the face into the reference element of the cell we can make the
+    grid edge consistent and choose a suitable convention for the order of
+    directions in our sum factorization kernels.
+    """
     assert len(visitor.indices) == 1
 
-    # Construct the matrix sequence for the evaluation of the global coordinate.
-    # We need to manually construct this one, because on facets, we want to use the
-    # geometry embedding of the facet into the global space directly without going
-    # through the neighboring cell geometries. That matrix sequence will only have
-    # dim-1 matrices!
-    from dune.perftool.sumfact.tabulation import quadrature_points_per_direction, BasisTabulationMatrix
-    quadrature_size = quadrature_points_per_direction()
-    matrix_sequence = tuple(BasisTabulationMatrix(direction=i, basis_size=2) for i in range(world_dimension()) if i != get_facedir(visitor.restriction))
-    inp = GeoCornersInput(visitor.indices[0])
-
-    from dune.perftool.sumfact.symbolic import SumfactKernel
+    # Adjust restriction for boundary facets
+    restriction = visitor.restriction
+    if get_global_context_value("integral_type") == "exterior_facet":
+        restriction = 1
+
+    # Generate sum factorization kernel and add vectorization info
+    matrix_sequence = construct_basis_matrix_sequence(facedir=get_facedir(restriction),
+                                                      facemod=get_facemod(restriction),
+                                                      basis_size=(2,) * world_dimension())
+    inp = GeoCornersInput(visitor.indices[0], restriction)
     sf = SumfactKernel(matrix_sequence=matrix_sequence,
                        interface=inp,
                        )
-
     vsf = attach_vectorization_info(sf)
 
     # Add a sum factorization kernel that implements the evaluation of
@@ -109,7 +156,10 @@ def pymbolic_spatial_coordinate_multilinear(do_predicates, visitor):
     from dune.perftool.sumfact.realization import realize_sum_factorization_kernel
     var, _ = realize_sum_factorization_kernel(vsf)
 
+    # The results of this function is already the right component of the
+    # spatial coordinate and we don't need to index this in the visitor
     visitor.indices = None
+
     return prim.Subscript(var, vsf.quadrature_index(sf, visitor))
 
 
@@ -164,7 +214,6 @@ def pymbolic_spatial_coordinate_axiparallel(do_predicates, visitor):
     # Urgh: *SOMEHOW* construct a face direction
     from dune.perftool.pdelab.restriction import Restriction
     restriction = Restriction.NONE
-    from dune.perftool.generation import get_global_context_value
     if get_global_context_value("integral_type") == "interior_facet":
         restriction = Restriction.POSITIVE
     from dune.perftool.sumfact.switch import get_facedir
@@ -192,69 +241,171 @@ def pymbolic_spatial_coordinate_axiparallel(do_predicates, visitor):
     return prim.Subscript(prim.Variable(lowcorner), (index,)) + x * prim.Subscript(prim.Variable(meshwidth), (index,))
 
 
-def pymbolic_unit_outer_normal(visitor_indices):
-    index, = visitor_indices
+def define_outer_normal(name, visitor):
+    """Calculate outer normal (length not necessarily 1)
+
+    This will be used to calculate the unit outer normal and the determinant of
+    the Jacobian of the geometry mapping of the face.
+
+    The outer normal is calculated by multiplying the Jacobian inverse
+    transposed of the geometry mapping of the 'self'-cell with the unit outer
+    normal \hat{n_s} of the face corresponding to the intersetcion in the
+    reference element of the 'self'-cell:
+
+    n = (\nabla \mu_{T_s})^{-T} \hat{n_s}
+
+    Instead of setting up \hat{n_s} we just look at facedir_s and facemod_s.
+    """
+    facedir_s = get_facedir(Restriction.POSITIVE)
+    facemod_s = get_facemod(Restriction.POSITIVE)
+    temporary_variable(name, shape=(world_dimension(),))
+    for i in range(world_dimension()):
+        assignee = prim.Subscript(prim.Variable(name), i)
+        jit = pymbolic_jacobian_inverse(i, facedir_s, Restriction.POSITIVE, visitor)
+
+        # Note: 2*facemod_s-1 because of
+        # -1 if facemod_s = 0
+        # +1 if facemod_s = 1
+        expression = jit * (2 * facemod_s - 1)
+
+        inames = default_quadrature_inames(visitor) + additional_inames(visitor)
+        instruction(assignee=assignee,
+                    expression=expression,
+                    within_inames=frozenset(inames),
+                    )
+
+
+def name_outer_normal(visitor):
+    name = "outer_normal"
+    define_outer_normal(name, visitor)
+    return name
+
+
+def pymbolic_outer_normal(visitor):
+    name = name_outer_normal(visitor)
+    return prim.Variable(name)
+
+
+def define_norm_of_outer_normal(name, visitor):
+    outer_normal = pymbolic_outer_normal(visitor)
+
+    # Calculate the norm of outer_normal
+    temporary_variable(name, shape=())
+    expression = 0
+    for i in range(world_dimension()):
+        expression = prim.Sum((expression, prim.Subscript(outer_normal, i) * prim.Subscript(outer_normal, i)))
+    expression = prim.Call(prim.Variable("sqrt"), (expression,))
+    inames = default_quadrature_inames(visitor) + additional_inames(visitor)
+
+    # Apparently the call of sqrt shadows the dependency on outer normal. Add manually.
+    instruction(assignee=prim.Variable(name),
+                expression=expression,
+                depends_on=frozenset({Writes(get_pymbolic_basename(outer_normal))}),
+                within_inames=frozenset(inames),
+                )
+
+
+def name_norm_of_outer_normal(visitor):
+    name = "norm_of_outer_normal"
+    define_norm_of_outer_normal(name, visitor)
+    return name
+
+
+def pymbolic_norm_of_outer_normal(visitor):
+    name = name_norm_of_outer_normal(visitor)
+    return prim.Variable(name)
+
+
+def pymbolic_unit_outer_normal(visitor):
+    assert (len(visitor.indices) is 1)
+    index = visitor.indices[0]
     assert isinstance(index, int)
     if get_form_option("diagonal_transformation_matrix"):
+        # In this case we just return -1, 0 or 1 depending on the current
+        # facemod and facedir. We don't need to (and cannot) index these ints
+        # so we set the indices of the visitor to None.
+        visitor.indices = None
+
+        # Use facemod_s and facedir_s
         from dune.perftool.sumfact.switch import get_facedir, get_facemod
         if index == get_facedir(Restriction.POSITIVE):
             if get_facemod(Restriction.POSITIVE):
-                return 1, None
+                return 1
             else:
-                return -1, None
+                return -1
         else:
-            return 0, None
+            return 0
     else:
-        from dune.perftool.pdelab.geometry import pymbolic_unit_outer_normal as _norm
-        return _norm(), visitor_indices
+        # In pymbolic_outer_normal we need to create the
+        # jacobian_inverse_transposed which doesn't play nicely with the
+        # visitor having indices. Maybe this should be improved. For now let's
+        # just set them to None and restore them afterwards.
+        visitor.indices = None
+        outer_normal = pymbolic_outer_normal(visitor)
+        norm = pymbolic_norm_of_outer_normal(visitor)
+        visitor.indices = (index,)
+
+        # Create unit_outer_normal by scaling outer_normal to length 1
+        name = "unit_outer_normal"
+        temporary_variable(name, shape=(world_dimension(),))
+        inames = default_quadrature_inames(visitor) + additional_inames(visitor)
+        for i in range(world_dimension()):
+            instruction(assignee=prim.Subscript(prim.Variable(name), i),
+                        expression=prim.Subscript(outer_normal, i) / norm,
+                        within_inames=frozenset(inames),
+                        )
+
+        return prim.Variable(name)
 
 
 def pymbolic_unit_inner_normal(visitor_indices):
-    index, = visitor_indices
+    # Note: The implementation of this was adjusted for unstructured grids but
+    # it was not properly tested. If you need the unit inner normal just remove
+    # the assert(False) statement but make sure to verify that this does the
+    # right thing.
+    assert(False)
+
+    assert (len(visitor.indices) is 1)
+    index = visitor.indices[0]
     assert isinstance(index, int)
     if get_form_option("diagonal_transformation_matrix"):
-        from dune.perftool.sumfact.switch import get_facedir, get_facemod
+        # In this case we just return -1, 0 or 1 depending on the current
+        # facemod and facedir. We don't need to (and cannot) index these ints
+        # so we set the indices of the visitor to None.
+        visitor.indices = None
         if index == get_facedir(Restriction.POSITIVE):
             if get_facemod(Restriction.POSITIVE):
-                return -1, None
+                return -1
             else:
-                return 1, None
+                return 1
         else:
-            return 0, None
-    else:
-        from dune.perftool.pdelab.geometry import pymbolic_unit_inner_normal as _norm
-        return _norm(), visitor_indices
-
-
-def pymbolic_facet_jacobian_determinant():
-    if get_form_option("constant_transformation_matrix"):
-        return pymbolic_constant_facet_jacobian_determinant()
+            return 0
     else:
-        from dune.perftool.pdelab.geometry import pymbolic_facet_jacobian_determinant as _norm
-        return _norm()
+        # In pymbolic_outer_normal we need to create the
+        # jacobian_inverse_transposed which doesn't play nicely with the
+        # visitor having indices. Maybe this should be improved. For now let's
+        # just set them to None and restore them afterwards.
+        visitor.indices = None
+        outer_normal = pymbolic_outer_normal(visitor)
+        norm = pymbolic_norm_of_outer_normal(visitor)
+        visitor.indices = (index,)
 
+        # Create unit_outer_normal by scaling outer_normal to length 1
+        name = "unit_outer_normal"
+        temporary_variable(name, shape=(world_dimension(),))
 
-def pymbolic_constant_facet_jacobian_determinant():
-    facedir = get_facedir(Restriction.POSITIVE)
-    assert isinstance(facedir, int)
+        inames = default_quadrature_inames(visitor) + additional_inames(visitor)
+        for i in range(world_dimension()):
+            instruction(assignee=prim.Subscript(prim.Variable(name), i),
+                        expression=-1 * prim.Subscript(outer_normal, i) / norm,
+                        within_inames=frozenset(inames),
+                        )
 
-    name = "fdetjac"
-    define_constant_facet_jacobian_determinant(name)
-    globalarg(name, shape=(world_dimension(),))
-    return prim.Subscript(prim.Variable(name), (facedir,))
-
-
-@class_member(classtag="operator")
-def define_constant_facet_jacobian_determinant(name):
-    define_constant_facet_jacobian_determinant_eval(name)
-    from dune.perftool.pdelab.localoperator import lop_template_ansatz_gfs
-    gfst = lop_template_ansatz_gfs()
-    return "std::array<typename {}::Traits::GridView::template Codim<0>::Geometry::ctype, {}> {};".format(gfst, world_dimension(), name)
+        return prim.Variable(name)
 
 
 @kernel_cached(kernel="operator")
 def define_constant_facet_jacobian_determinant_eval(name):
-    from dune.perftool.pdelab.localoperator import name_ansatz_gfs_constructor_param, lop_template_range_field
     gfs = name_ansatz_gfs_constructor_param()
     rft = lop_template_range_field()
     code = ["{",
@@ -269,9 +420,196 @@ def define_constant_facet_jacobian_determinant_eval(name):
                 )
 
 
-def pymbolic_facet_area():
+@class_member(classtag="operator")
+def define_constant_facet_jacobian_determinant(name):
+    define_constant_facet_jacobian_determinant_eval(name)
+    gfst = lop_template_ansatz_gfs()
+    return "std::array<typename {}::Traits::GridView::template Codim<0>::Geometry::ctype, {}> {};".format(gfst, world_dimension(), name)
+
+
+def pymbolic_constant_facet_jacobian_determinant():
+    facedir = get_facedir(Restriction.POSITIVE)
+    assert isinstance(facedir, int)
+
+    name = "fdetjac"
+    define_constant_facet_jacobian_determinant(name)
+    globalarg(name, shape=(world_dimension(),))
+    return prim.Subscript(prim.Variable(name), (facedir,))
+
+
+def define_facet_jacobian_determinant(name, visitor):
+    """Absolute value of determinant of jacobian of facet geometry mapping
+
+    Calculate the absolute value of the determinant of the jacobian of the
+    geometry mapping from the reference cell of the intersection to the
+    intersection:
+
+    |\det(\nabla \mu_F)|
+
+    This is done using the surface metric tensor lemma from the lecture notes
+    of Jean-Luc Guermond:
+
+    |\det(\nabla \mu_F)| = \| \tilde{n} \| |\det(\nabla \mu_{T_s})|
+
+    Here \tilde{n} is the outer normal defined by:
+
+    \tilde{n} = (\nabla \mu_{T_s})^{-T} \hat{n}_s
+
+    where \hat{n}_s is the unit outer normal of the corresponding face of the
+    reference cell.
+    """
+    # Calculate norm of outer normal and determinant of jacobian of geometry
+    # mapping of the inside cell -> set restriction to 1 for boundary facets
+    if get_global_context_value("integral_type") == "exterior_facet":
+        assert visitor.restriction is 0
+        visitor.restriction = 1
+    norm_of_outer_normal = pymbolic_norm_of_outer_normal(visitor)
+    detjac = pymbolic_jacobian_determinant(visitor)
+    if get_global_context_value("integral_type") == "exterior_facet":
+        visitor.restriction = 0
+
+    # Multiply detjac and norm_of_outer_normal
+    temporary_variable(name, shape=())
+    inames = default_quadrature_inames(visitor) + additional_inames(visitor)
+    instruction(assignee=prim.Variable(name),
+                expression=detjac * norm_of_outer_normal,
+                within_inames=frozenset(inames),
+                )
+
+
+def name_facet_jacobian_determinant(visitor):
+    name = "fdetjac"
+    define_facet_jacobian_determinant(name, visitor)
+    return name
+
+
+def pymbolic_facet_jacobian_determinant(visitor):
+    if get_form_option("constant_transformation_matrix"):
+        return pymbolic_constant_facet_jacobian_determinant()
+    else:
+        name = name_facet_jacobian_determinant(visitor)
+        return prim.Variable(name)
+
+
+def pymbolic_facet_area(visitor):
+    if get_form_option("constant_transformation_matrix"):
+        return pymbolic_facet_jacobian_determinant(visitor)
+    else:
+        from dune.perftool.pdelab.geometry import pymbolic_facet_area as nonconstant_facet_area
+        return nonconstant_facet_area()
+
+
+def _name_jacobian(i, j, restriction, visitor):
+    """Return the (i, j) component of the jacobian of the geometry mapping
+
+    Evaluation of the derivative of the geometry mapping is done using sum
+    factorization.
+
+    Note: At the moment this only works for the mappings from reference cells
+    to the cell and not for the geometry mappings of intersections.
+    """
+    do_predicates = visitor.do_predicates
+
+    # Create matrix sequence with derivative in j direction
+    matrix_sequence = construct_basis_matrix_sequence(derivative=j,
+                                                      facedir=get_facedir(restriction),
+                                                      facemod=get_facemod(restriction),
+                                                      basis_size=(2,) * world_dimension())
+
+    # Sum factorization input for the i'th component of the geometry mapping
+    inp = GeoCornersInput(i, restriction)
+
+    sf = SumfactKernel(matrix_sequence=matrix_sequence,
+                       interface=inp,
+                       )
+    vsf = attach_vectorization_info(sf)
+
+    # Add a sum factorization kernel that implements the evaluation of
+    # the basis functions at quadrature points (stage 1)
+    var, _ = realize_sum_factorization_kernel(vsf)
+
+    assert(visitor.indices is None)
+    return prim.Subscript(var, vsf.quadrature_index(sf, visitor))
+
+
+def define_jacobian_inverse(name, restriction, visitor):
+    """Return jacobian inverse transposed of the geometry mapping (of a cell)
+
+    At the moment this only works for geometry mappings of cells and not for
+    intersection. We only consider this case as it greatly simplifies code
+    generation for unstructured grids by making the grid edge consistent and
+    avoiding the face-twist problem.
+    """
+    # Calculate the jacobian of the geometry mapping using sum factorization
+    dim = world_dimension()
+    names_jacobian = []
+    for j in range(dim):
+        for i in range(dim):
+            name_jacobian = restricted_name("jacobian_geometry_{}{}".format(i, j), restriction)
+            temporary_variable(name_jacobian)
+            assignee = prim.Variable(name_jacobian)
+            expression = _name_jacobian(i, j, restriction, visitor)
+            inames = default_quadrature_inames(visitor) + additional_inames(visitor)
+            instruction(assignee=assignee,
+                        expression=expression,
+                        within_inames=frozenset(inames),
+                        )
+            names_jacobian.append(name_jacobian)
+
+    # Calculate the inverse of the jacobian of the geometry mapping and the
+    # determinant by calling a c++ function
+    name_detjac = name_jacobian_determinant(visitor)
+    temporary_variable(name_detjac, shape=())
+    temporary_variable(name, shape=(dim, dim), managed=True)
+    include_file('dune/perftool/sumfact/invertgeometry.hh', filetag='operatorfile')
+    code = "{} = invert_and_return_determinant({}, {});".format(name_detjac,
+                                                                ", ".join(names_jacobian),
+                                                                name)
+    silenced_warning("read_no_write({})".format(name_detjac))
+    inames = default_quadrature_inames(visitor) + additional_inames(visitor)
+    return instruction(code=code,
+                       assignees=frozenset([name, name_detjac]),
+                       read_variables=frozenset(names_jacobian),
+                       inames=frozenset(inames),
+                       )
+
+
+def name_jacobian_inverse(restriction, visitor):
+    name = restricted_name("jacobian_inverse", restriction)
+    define_jacobian_inverse(name, restriction, visitor)
+    return name
+
+
+def pymbolic_jacobian_inverse(i, j, restriction, visitor):
+    # Switch between implementations without using the backend mechanism. In
+    # the case of constant_transformation_matrix we want to use the pdelab
+    # branch, otherwise we want to go into the sumfact implementation instead
+    # of pdelab.
     if get_form_option("constant_transformation_matrix"):
-        return pymbolic_facet_jacobian_determinant()
+        from dune.perftool.pdelab.geometry import name_constant_jacobian_inverse_transposed
+        name = name_constant_jacobian_inverse_transposed(restriction)
+        # Return jacobian inverse -> (j, i) instead of (i, j)
+        return prim.Subscript(prim.Variable(name), (j, i))
     else:
-        from dune.perftool.pdelab.geometry import pymbolic_facet_area as _norm
-        return _norm()
+        name = name_jacobian_inverse(restriction, visitor)
+        return prim.Subscript(prim.Variable(name), (i, j))
+
+
+def name_jacobian_determinant(visitor):
+    name = "detjac"
+    return name
+
+
+def pymbolic_jacobian_determinant(visitor):
+    if get_form_option("constant_transformation_matrix"):
+        from dune.perftool.pdelab.geometry import pymbolic_jacobian_determinant
+        return pymbolic_jacobian_determinant()
+    else:
+        # The calculation of the jacobian determinant happens in this function
+        if visitor.measure == 'cell':
+            restriction = 0
+        else:
+            restriction = 1
+        name_jacobian_inverse(restriction, visitor)
+
+        return prim.Variable(name_jacobian_determinant(visitor))
diff --git a/python/dune/perftool/sumfact/quadrature.py b/python/dune/perftool/sumfact/quadrature.py
index 586d9fd26a823c48ec1a7a220a840a5d928e30e1..6fe70fa441979c4ae00a5f44acc8136def9f5fb0 100644
--- a/python/dune/perftool/sumfact/quadrature.py
+++ b/python/dune/perftool/sumfact/quadrature.py
@@ -39,20 +39,6 @@ import loopy as lp
 import numpy as np
 
 
-def nest_quadrature_loops(kernel, inames):
-    insns = []
-    for insn in kernel.instructions:
-        if "quad" in insn.tags:
-            insns.append(insn.copy(within_inames=insn.within_inames.union(frozenset(inames)),
-                                   tags=insn.tags - frozenset({"quad"})
-                                   )
-                         )
-        else:
-            insns.append(insn)
-
-    return kernel.copy(instructions=insns)
-
-
 class BaseWeight(FunctionIdentifier):
     def __init__(self, accumobj):
         self.accumobj = accumobj
@@ -80,6 +66,15 @@ def pymbolic_base_weight():
     return 1.0
 
 
+def default_quadrature_inames(visitor):
+    info = visitor.current_info[1]
+    if info is None:
+        element = None
+    else:
+        element = info.element
+    return quadrature_inames(element)
+
+
 @kernel_cached
 def quadrature_inames(element):
     if element is None:
@@ -177,7 +172,8 @@ def quadrature_weight(visitor):
         element = None
     else:
         element = info.element
-    return prim.Subscript(lp.symbolic.TaggedVariable(name, "operator_precomputed"), tuple(prim.Variable(i) for i in quadrature_inames(element)))
+    return prim.Subscript(lp.symbolic.TaggedVariable(name, "operator_precomputed"),
+                          tuple(prim.Variable(i) for i in quadrature_inames(element)))
 
 
 def define_quadrature_position(name, local_index):
@@ -245,7 +241,9 @@ def pymbolic_indexed_quadrature_position(local_index, visitor):
     return prim.Subscript(lp.symbolic.TaggedVariable(name, "operator_precomputed"), tuple(prim.Variable(i) for i in quadrature_inames(element)))
 
 
-def _additional_inames(visitor):
+def additional_inames(visitor):
+    """Return inames for iterating over ansatz space in the case of jacobians
+    """
     info = visitor.current_info[1]
     if info is None:
         element = None
@@ -262,59 +260,3 @@ def _additional_inames(visitor):
         return lfs_inames
     else:
         return ()
-
-
-@backend(interface="quadrature_preamble", name="sumfact")
-def quadrature_preamble(code, **kw):
-    visitor = get_global_context_value('visitor')
-
-    info = visitor.current_info[1]
-    if info is None:
-        element = None
-    else:
-        element = info.element
-
-    inames = quadrature_inames(element)
-    inames = inames + _additional_inames(visitor)
-
-    return instruction(inames=inames, code=code, **kw)
-
-
-@preamble
-def define_quadrature_point(name):
-    local_dim = local_dimension()
-    return "Dune::FieldVector<double, {}> {};".format(local_dim, name)
-
-
-def name_quadrature_point():
-    name = "quadrature_point"
-    define_quadrature_point(name)
-    return name
-
-
-@backend(interface="quad_pos", name="sumfact")
-def pymbolic_quadrature_position():
-    visitor = get_global_context_value('visitor')
-
-    info = visitor.current_info[1]
-    if info is None:
-        element = None
-    else:
-        element = info.element
-
-    quad_point = name_quadrature_point()
-    inames = quadrature_inames(element) + _additional_inames(visitor)
-    globalarg(quad_point, shape=(local_dimension(),))
-    facedir = get_facedir(visitor.restriction)
-    for i in range(local_dimension()):
-        expression = pymbolic_indexed_quadrature_position(i, visitor)
-        instruction(assignee=prim.Subscript(prim.Variable(quad_point), i),
-                    expression=expression,
-                    within_inames=frozenset(inames))
-    return Variable(quad_point)
-
-
-@backend(interface="qp_in_cell", name="sumfact")
-def pymbolic_quadrature_position_in_cell(restriction):
-    from dune.perftool.pdelab.quadrature import pymbolic_quadrature_position_in_cell
-    return pymbolic_quadrature_position_in_cell(restriction)
diff --git a/python/dune/perftool/sumfact/symbolic.py b/python/dune/perftool/sumfact/symbolic.py
index fb283a0536318c1585a0963a33ca76105571cb84..f2fbcb76abfea8a594a1df28bebfc2142f2275aa 100644
--- a/python/dune/perftool/sumfact/symbolic.py
+++ b/python/dune/perftool/sumfact/symbolic.py
@@ -417,6 +417,23 @@ class SumfactKernel(SumfactKernelBase, ImmutableRecord, prim.Variable):
         if len(self.matrix_sequence) == local_dimension():
             return tuple(prim.Variable(i) for i in quad_inames)
 
+        # # Extremly ugly. This is the special case of being on an intersection
+        # # and generating a SF kernel for the geometry evaluation of one of the
+        # # neighboring cells. This screws the usual setup since the SF sequence
+        # # is not equal to the local dimension.
+        # #
+        # # TODO: Vectorization is probably broken for this case!
+        # count_sf_sequence_length = 0
+        # for d in range(world_dimension()):
+        #     if self.matrix_sequence[d].face is not None:
+        #         count_sf_sequence_length += 1
+        # if count_sf_sequence_length != local_dimension():
+        #     from dune.perftool.sumfact.quadrature import global_quadrature_inames
+        #     quad_inames = global_quadrature_inames(element)
+
+        #     for d in range(world_dimension()):
+        #         print(self.matrix_sequence[d].face)
+
         # Traverse all the quadrature inames and map them to their correct direction
         index = []
         i = 0
diff --git a/python/dune/perftool/ufl/visitor.py b/python/dune/perftool/ufl/visitor.py
index cbede6c30fa7d6754b58b57b662ba126a1dec6b5..9e14391c5aef7656dfcc6e0fe8276ffcf3016505 100644
--- a/python/dune/perftool/ufl/visitor.py
+++ b/python/dune/perftool/ufl/visitor.py
@@ -464,7 +464,7 @@ class UFL2LoopyVisitor(ModifiedTerminalTracker):
             if isinstance(i, int) and isinstance(j, int) and i != j:
                 return 0
 
-        return self.interface.pymbolic_jacobian_inverse_transposed(i, j, restriction)
+        return self.interface.pymbolic_jacobian_inverse(i, j, restriction)
 
     def jacobian(self, o):
         raise NotImplementedError("How did you get Jacobian into your form? We only support JacobianInverse right now. Report!")