diff --git a/applications/convection_diffusion/conv_diff_dg.ufl b/applications/convection_diffusion/conv_diff_dg.ufl
index 38e8dc7334af54b167a51955186f63660af12e4c..80e9205514aa0d7c1d813b2abb825fb654c6443f 100644
--- a/applications/convection_diffusion/conv_diff_dg.ufl
+++ b/applications/convection_diffusion/conv_diff_dg.ufl
@@ -1,3 +1,4 @@
+dim = 3
 x = SpatialCoordinate(cell)
 
 g = x[0]*x[0] + x[1]*x[1] + x[2]*x[2]
@@ -13,17 +14,22 @@ v = TestFunction(V)
 
 n = FacetNormal(cell)('+')
 
-gamma = 1.0
+alpha = 1.0
+h_ext = CellVolume(cell) / FacetArea(cell)
+gamma_ext = (alpha * degree * (degree + dim - 1)) / h_ext
+h_int = Min(CellVolume(cell)('+'), CellVolume(cell)('-')) / FacetArea(cell)
+gamma_int = (alpha * degree * (degree + dim - 1)) / h_int
+
 theta = -1.0
 
 r = (inner(A*grad(u), grad(v)) + (c*u-f)*v)*dx \
   + inner(n, A*avg(grad(u)))*jump(v)*dS \
-  + gamma*jump(u)*jump(v)*dS \
+  + gamma_int*jump(u)*jump(v)*dS \
   + theta*jump(u)*inner(A*avg(grad(v)), n)*dS \
   - inner(n, A*grad(u))*v*ds \
-  + gamma*u*v*ds \
+  + gamma_ext*u*v*ds \
   - theta*u*inner(A*grad(v), n)*ds \
   + theta*g*inner(A*grad(v), n)*ds \
-  - gamma*g*v*ds
+  - gamma_ext*g*v*ds
 
 forms = [r]
diff --git a/applications/poisson_dg/poisson_dg.ufl b/applications/poisson_dg/poisson_dg.ufl
index 536360533793fe795d9b5bd303e023f9ecb31c19..7d532811958c1abc947c71cdfacdec57e0bc3ff0 100644
--- a/applications/poisson_dg/poisson_dg.ufl
+++ b/applications/poisson_dg/poisson_dg.ufl
@@ -1,3 +1,4 @@
+dim = 3
 x = SpatialCoordinate(cell)
 f = -6.
 g = x[0]*x[0] + x[1]*x[1] + x[2]*x[2]
@@ -9,18 +10,23 @@ v = TestFunction(V)
 
 n = FacetNormal(cell)('+')
 
-gamma = 1.0
+alpha = 1.0
+h_ext = CellVolume(cell) / FacetArea(cell)
+gamma_ext = (alpha * degree * (degree + dim - 1)) / h_ext
+h_int = Min(CellVolume(cell)('+'), CellVolume(cell)('-')) / FacetArea(cell)
+gamma_int = (alpha * degree * (degree + dim - 1)) / h_int
+
 theta = 1.0
 
 r = inner(grad(u), grad(v))*dx \
   + inner(n, avg(grad(u)))*jump(v)*dS \
-  + gamma*jump(u)*jump(v)*dS \
+  + gamma_int*jump(u)*jump(v)*dS \
   + theta*jump(u)*inner(avg(grad(v)), n)*dS \
   - inner(n, grad(u))*v*ds \
-  + gamma*u*v*ds \
+  + gamma_ext*u*v*ds \
   - theta*u*inner(grad(v), n)*ds \
   - f*v*dx \
   + theta*g*inner(grad(v), n)*ds \
-  - gamma*g*v*ds
+  - gamma_ext*g*v*ds
 
 forms = [r]
diff --git a/python/dune/perftool/loopy/target.py b/python/dune/perftool/loopy/target.py
index 9427a401e8b0a51f8b43ddf52abfd2cc3b9bc753..6ef27648aa9d659ab63838d84798f19eec3a91f3 100644
--- a/python/dune/perftool/loopy/target.py
+++ b/python/dune/perftool/loopy/target.py
@@ -118,7 +118,7 @@ class DuneCExpressionToCodeMapper(CExpressionToCodeMapper):
 
         result = self.rec(children.pop(), PREC_NONE)
         while children:
-            result = "std::%s(%s, %s)" % (what,
+            result = "%s(%s, %s)" % (what,
                                           self.rec(children.pop(), PREC_NONE),
                                           result)
 
diff --git a/python/dune/perftool/pdelab/__init__.py b/python/dune/perftool/pdelab/__init__.py
index 8529eb1e55186f52c379337be47165800cf21cee..dcc17068303501fc01d96e842089454907342c3b 100644
--- a/python/dune/perftool/pdelab/__init__.py
+++ b/python/dune/perftool/pdelab/__init__.py
@@ -11,6 +11,8 @@ from dune.perftool.pdelab.basis import (pymbolic_basis,
                                         pymbolic_reference_gradient,
                                         )
 from dune.perftool.pdelab.geometry import (dimension_iname,
+                                           name_cell_volume,
+                                           name_facet_area,
                                            name_facet_jacobian_determinant,
                                            name_jacobian_determinant,
                                            name_jacobian_inverse_transposed,
@@ -112,6 +114,12 @@ class PDELabInterface(object):
     def name_unit_outer_normal(self):
         return name_unit_outer_normal()
 
+    def name_cell_volume(self, restriction):
+        return name_cell_volume(restriction)
+
+    def name_facet_area(self):
+        return name_facet_area()
+
     #
     # Quadrature related generator functions
     #
diff --git a/python/dune/perftool/pdelab/geometry.py b/python/dune/perftool/pdelab/geometry.py
index b66f58fc875370737ec9a9d267b53acedcb1efe6..ce080eba080be2cf75e5d4ee6993232dfb237079 100644
--- a/python/dune/perftool/pdelab/geometry.py
+++ b/python/dune/perftool/pdelab/geometry.py
@@ -405,3 +405,33 @@ def to_global(local):
     name = get_pymbolic_basename(local) + "_global"
     apply_to_global_transformation(name, local)
     return prim.Variable(name)
+
+
+def define_cell_volume(name, restriction):
+    geo = name_cell_geometry(restriction)
+    temporary_variable(name, shape=())
+    code = "{} = {}.volume();".format(name, geo)
+    return quadrature_preamble(code,
+                               assignees=frozenset({name}),
+                               )
+
+
+def name_cell_volume(restriction):
+    name = restricted_name("volume", restriction)
+    define_cell_volume(name, restriction)
+    return name
+
+
+def define_facet_area(name):
+    geo = name_intersection_geometry()
+    temporary_variable(name, shape=())
+    code = "{} = {}.volume();".format(name, geo)
+    return quadrature_preamble(code,
+                               assignees=frozenset({name}),
+                               )
+
+
+def name_facet_area():
+    name = "area"
+    define_facet_area(name)
+    return name
diff --git a/python/dune/perftool/ufl/preprocess.py b/python/dune/perftool/ufl/preprocess.py
index 540300bb3ee61abaa89b6b958df65e879af69e46..913bf5dad763483e56d619f9be6226b92ee9ffd8 100644
--- a/python/dune/perftool/ufl/preprocess.py
+++ b/python/dune/perftool/ufl/preprocess.py
@@ -1,22 +1,20 @@
 """ Preprocessing algorithms for UFL forms """
 
+import ufl.classes as uc
 
-def preprocess_form(form):
-    from ufl.classes import (FacetJacobianDeterminant,
-                             FacetNormal,
-                             JacobianDeterminant,
-                             JacobianInverse,
-                             )
 
+def preprocess_form(form):
     from ufl.algorithms import compute_form_data
     formdata = compute_form_data(form,
                                  do_apply_function_pullbacks=True,
                                  do_apply_geometry_lowering=True,
                                  do_apply_integral_scaling=True,
-                                 preserve_geometry_types=(FacetJacobianDeterminant,
-                                                          FacetNormal,
-                                                          JacobianDeterminant,
-                                                          JacobianInverse,
+                                 preserve_geometry_types=(uc.CellVolume,
+                                                          uc.FacetArea,
+                                                          uc.FacetJacobianDeterminant,
+                                                          uc.FacetNormal,
+                                                          uc.JacobianDeterminant,
+                                                          uc.JacobianInverse,
                                                           )
                                  )
 
diff --git a/python/dune/perftool/ufl/visitor.py b/python/dune/perftool/ufl/visitor.py
index 1ba817c856c7ba76fe36b40bf9ec4b94552a5b89..de92f3a49f23346324a280c0e5b1565563adaf3a 100644
--- a/python/dune/perftool/ufl/visitor.py
+++ b/python/dune/perftool/ufl/visitor.py
@@ -265,6 +265,12 @@ class UFL2LoopyVisitor(ModifiedTerminalTracker):
 
         raise NotImplementedError("Power function not really implemented")
 
+    def max_value(self, o):
+        return prim.Max(tuple(self.call(op) for op in o.ufl_operands))
+
+    def min_value(self, o):
+        return prim.Min(tuple(self.call(op) for op in o.ufl_operands))
+
     #
     # Handler for conditionals, use pymbolic base implementation
     #
@@ -360,6 +366,16 @@ class UFL2LoopyVisitor(ModifiedTerminalTracker):
     def facet_jacobian_determinant(self, o):
         return Variable(self.interface.name_facet_jacobian_determinant())
 
+    def cell_volume(self, o):
+        restriction = self.restriction
+        if self.measure == 'exterior_facet':
+            restriction = Restriction.NEGATIVE
+
+        return prim.Variable(self.interface.name_cell_volume(restriction))
+
+    def facet_area(self, o):
+        return prim.Variable(self.interface.name_facet_area())
+
     #
     # Equality/Hashability of the visitor
     # In order to pass this visitor into (cached) generator functions, it is beneficial
diff --git a/test/poisson/opcount_poisson_dg.ufl b/test/poisson/opcount_poisson_dg.ufl
index 3ced1b8263f75d01feeb90acae9a64ae1bcba482..ed537bc936a03fb1fa21a87419d4c62f67246d4f 100644
--- a/test/poisson/opcount_poisson_dg.ufl
+++ b/test/poisson/opcount_poisson_dg.ufl
@@ -11,20 +11,24 @@ v = TestFunction(V)
 n = FacetNormal(cell)('+')
 
 # penalty factor
-gamma = 1.0
+alpha = 1.0
+h_ext = CellVolume(cell) / FacetArea(cell)
+gamma_ext = (alpha * degree * (degree + dim - 1)) / h_ext
+h_int = Min(CellVolume(cell)('+'), CellVolume(cell)('-')) / FacetArea(cell)
+gamma_int = (alpha * degree * (degree + dim - 1)) / h_int
 
 # SIPG: -1.0, IIPG: 0.0, NIPG: 1.0
 theta = 1.0
 
 r = inner(grad(u), grad(v))*dx \
   + inner(n, avg(grad(u)))*jump(v)*dS \
-  + gamma*jump(u)*jump(v)*dS \
+  + gamma_int*jump(u)*jump(v)*dS \
   - theta*jump(u)*inner(avg(grad(v)), n)*dS \
   - inner(n, grad(u))*v*ds \
-  + gamma*u*v*ds \
+  + gamma_ext*u*v*ds \
   + theta*u*inner(grad(v), n)*ds \
   - f*v*dx \
   - theta*g*inner(grad(v), n)*ds \
-  - gamma*g*v*ds
+  - gamma_ext*g*v*ds
 
 forms = [r]
diff --git a/test/poisson/poisson_dg.ufl b/test/poisson/poisson_dg.ufl
index daf2793ee5c327dd389d05fffda0c7c8dc9dd244..b8ad04251f4fb94d483c7c01b7430fb3fc440e88 100644
--- a/test/poisson/poisson_dg.ufl
+++ b/test/poisson/poisson_dg.ufl
@@ -1,11 +1,13 @@
 cell = triangle
+degree = 1
+dim = 2
 
 x = SpatialCoordinate(cell)
 c = (0.5-x[0])**2 + (0.5-x[1])**2
 g = exp(-1.*c)
 f = 4*(1.-c)*g
 
-V = FiniteElement("DG", cell, 1)
+V = FiniteElement("DG", cell, degree)
 
 u = TrialFunction(V)
 v = TestFunction(V)
@@ -13,20 +15,24 @@ v = TestFunction(V)
 n = FacetNormal(cell)('+')
 
 # penalty factor
-gamma = 1.0
+alpha = 1.0
+h_ext = CellVolume(cell) / FacetArea(cell)
+gamma_ext = (alpha * degree * (degree + dim - 1)) / h_ext
+h_int = Min(CellVolume(cell)('+'), CellVolume(cell)('-')) / FacetArea(cell)
+gamma_int = (alpha * degree * (degree + dim - 1)) / h_int
 
 # SIPG: -1.0, IIPG: 0.0, NIPG: 1.0
 theta = 1.0
 
 r = inner(grad(u), grad(v))*dx \
   + inner(n, avg(grad(u)))*jump(v)*dS \
-  + gamma*jump(u)*jump(v)*dS \
+  + gamma_int*jump(u)*jump(v)*dS \
   - theta*jump(u)*inner(avg(grad(v)), n)*dS \
   - inner(n, grad(u))*v*ds \
-  + gamma*u*v*ds \
+  + gamma_ext*u*v*ds \
   + theta*u*inner(grad(v), n)*ds \
   - f*v*dx \
   - theta*g*inner(grad(v), n)*ds \
-  - gamma*g*v*ds
+  - gamma_ext*g*v*ds
 
 forms = [r]
diff --git a/test/poisson/poisson_dg_neumann.ufl b/test/poisson/poisson_dg_neumann.ufl
index 1dd15d4f39c18d2b07567c3d8d4afe46dbd72a18..884787e6374a742ab5276a792f6975019a65f747 100644
--- a/test/poisson/poisson_dg_neumann.ufl
+++ b/test/poisson/poisson_dg_neumann.ufl
@@ -1,3 +1,5 @@
+dim = 3
+degree = 1
 cell = triangle
 
 x = SpatialCoordinate(cell)
@@ -8,7 +10,7 @@ sgn = conditional(x[1] > 0.5, 1., -1.)
 j = -2.*sgn*(x[1]-0.5)*g
 bctype = conditional(Or(x[1]<1e-8, x[1]>1.-1e-8), 0, 1)
 
-V = FiniteElement("DG", cell, 1)
+V = FiniteElement("DG", cell, degree)
 
 u = TrialFunction(V)
 v = TestFunction(V)
@@ -18,21 +20,25 @@ n = FacetNormal(cell)('+')
 ds = ds(subdomain_data=bctype)
 
 # penalty factor
-gamma = 1.0
+alpha = 1.0
+h_ext = CellVolume(cell) / FacetArea(cell)
+gamma_ext = (alpha * degree * (degree + dim - 1)) / h_ext
+h_int = Min(CellVolume(cell)('+'), CellVolume(cell)('-')) / FacetArea(cell)
+gamma_int = (alpha * degree * (degree + dim - 1)) / h_int
 
 # SIPG: -1.0, IIPG: 0.0, NIPG: 1.0
 theta = 1.0
 
 r = inner(grad(u), grad(v))*dx \
   + inner(n, avg(grad(u)))*jump(v)*dS \
-  + gamma*jump(u)*jump(v)*dS \
+  + gamma_int*jump(u)*jump(v)*dS \
   - theta*jump(u)*inner(avg(grad(v)), n)*dS \
   - inner(n, grad(u))*v*ds(1) \
-  + gamma*u*v*ds(1) \
+  + gamma_ext*u*v*ds(1) \
   + theta*u*inner(grad(v), n)*ds(1) \
   - f*v*dx \
   - theta*g*inner(grad(v), n)*ds(1) \
-  - gamma*g*v*ds(1) \
+  - gamma_ext*g*v*ds(1) \
   - j*v*ds(0)
 
 forms = [r]
diff --git a/test/poisson/poisson_dg_tensor.ufl b/test/poisson/poisson_dg_tensor.ufl
index d84cebf6d1420b8ec3fd35086d40833937e55f60..1ae0139b3d63fe588b69ce221e17a488b0e1535a 100644
--- a/test/poisson/poisson_dg_tensor.ufl
+++ b/test/poisson/poisson_dg_tensor.ufl
@@ -1,3 +1,5 @@
+dim = 2
+degree = 1
 cell = quadrilateral
 
 x = SpatialCoordinate(cell)
@@ -8,7 +10,7 @@ g = x[0]**2 + x[1]**2
 c = 8.
 f = -4.
 
-V = FiniteElement("DG", cell, 1)
+V = FiniteElement("DG", cell, degree)
 
 u = TrialFunction(V)
 v = TestFunction(V)
@@ -16,20 +18,24 @@ v = TestFunction(V)
 n = FacetNormal(cell)('+')
 
 # penalty factor
-gamma = 1.0
+alpha = 1.0
+h_ext = CellVolume(cell) / FacetArea(cell)
+gamma_ext = (alpha * degree * (degree + dim - 1)) / h_ext
+h_int = Min(CellVolume(cell)('+'), CellVolume(cell)('-')) / FacetArea(cell)
+gamma_int = (alpha * degree * (degree + dim - 1)) / h_int
 
 # SIPG: -1.0, IIPG: 0.0, NIPG: 1.0
 theta = 1.0
 
 r = (inner(A*grad(u), grad(v)) + c*u*v)*dx \
   + inner(n, A*avg(grad(u)))*jump(v)*dS \
-  + gamma*jump(u)*jump(v)*dS \
+  + gamma_int*jump(u)*jump(v)*dS \
   - theta*jump(u)*inner(A*avg(grad(v)), n)*dS \
   - inner(n, A*grad(u))*v*ds \
-  + gamma*u*v*ds \
+  + gamma_ext*u*v*ds \
   + theta*u*inner(A*grad(v), n)*ds \
   - f*v*dx \
   - theta*g*inner(A*grad(v), n)*ds \
-  - gamma*g*v*ds
+  - gamma_ext*g*v*ds
 
 forms = [r]