diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index d74091c095554195da330ad5b5a242751dc38f39..5adf4b8c0d6edce6c74f03c61b9e5c43dc78ffe6 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -1,4 +1,5 @@
-set(programs cosserat-continuum
+set(programs compute-disc-error
+             cosserat-continuum
              harmonicmaps
              mixed-cosserat-continuum
              rod-eoc
diff --git a/src/compute-disc-error.cc b/src/compute-disc-error.cc
new file mode 100644
index 0000000000000000000000000000000000000000..f08b7cb97ac6e785f07beaf981fa3db6bbc3d2e7
--- /dev/null
+++ b/src/compute-disc-error.cc
@@ -0,0 +1,260 @@
+#include <config.h>
+
+#include <dune/common/parametertree.hh>
+#include <dune/common/parametertreeparser.hh>
+
+#include <dune/grid/uggrid.hh>
+#include <dune/grid/io/file/gmshreader.hh>
+#include <dune/grid/utility/structuredgridfactory.hh>
+
+#include <dune/functions/functionspacebases/pqknodalbasis.hh>
+
+#include <dune/fufem/boundarypatch.hh>
+#include <dune/fufem/functiontools/basisinterpolator.hh>
+#include <dune/fufem/functiontools/boundarydofs.hh>
+#include <dune/fufem/functionspacebases/dunefunctionsbasis.hh>
+#include <dune/fufem/discretizationerror.hh>
+#include <dune/fufem/dunepython.hh>
+
+#include <dune/gfe/rotation.hh>
+#include <dune/gfe/unitvector.hh>
+#include <dune/gfe/realtuple.hh>
+#include <dune/gfe/embeddedglobalgfefunction.hh>
+#include <dune/gfe/cosseratvtkwriter.hh>
+
+// grid dimension
+const int dim = 2;
+const int dimworld = 2;
+
+// Image space of the geodesic fe functions
+const int targetDim = 3;
+// typedef Rotation<double,targetDim> TargetSpace;
+// typedef UnitVector<double,targetDim> TargetSpace;
+// typedef RealTuple<double,targetDim> TargetSpace;
+using TargetSpace = RigidBodyMotion<double,targetDim>;
+
+// Tangent vector of the image space
+const int blocksize = TargetSpace::TangentVector::dimension;
+
+using namespace Dune;
+
+template <class GridView, int order>
+void measureEOC(const GridView gridView,
+                const GridView referenceGridView,
+                const ParameterTree& parameterSet)
+{
+  typedef std::vector<TargetSpace> SolutionType;
+
+  //////////////////////////////////////////////////////////////////////////////////
+  //  Construct the scalar function space bases corresponding to the GFE space
+  //////////////////////////////////////////////////////////////////////////////////
+
+  typedef Dune::Functions::PQkNodalBasis<GridView, order> FEBasis;
+  FEBasis feBasis(gridView);
+  FEBasis referenceFEBasis(referenceGridView);
+
+  //////////////////////////////////////////////////////////////////////////////////
+  //  Read the data whose error is to be measured, and the reference data
+  //////////////////////////////////////////////////////////////////////////////////
+
+  // Input data
+  typedef BlockVector<TargetSpace::CoordinateType> EmbeddedVectorType;
+
+  EmbeddedVectorType embeddedX(feBasis.size());
+  std::ifstream inFile(parameterSet.get<std::string>("simulationData"), std::ios_base::binary);
+  if (not inFile)
+    DUNE_THROW(IOError, "File " << parameterSet.get<std::string>("simulationData") << " could not be opened.");
+  GenericVector::readBinary(inFile, embeddedX);
+  inFile.close();
+
+  SolutionType x(embeddedX.size());
+  for (size_t i=0; i<x.size(); i++)
+    x[i] = TargetSpace(embeddedX[i]);
+
+  // Reference configuration
+  EmbeddedVectorType embeddedReferenceX(referenceFEBasis.size());
+  inFile.open(parameterSet.get<std::string>("referenceData"), std::ios_base::binary);
+  if (not inFile)
+    DUNE_THROW(IOError, "File " << parameterSet.get<std::string>("referenceData") << " could not be opened.");
+  GenericVector::readBinary(inFile, embeddedReferenceX);
+
+  SolutionType referenceX(embeddedReferenceX.size());
+  for (size_t i=0; i<referenceX.size(); i++)
+    referenceX[i] = TargetSpace(embeddedReferenceX[i]);
+
+  //CosseratVTKWriter<typename GridView::Grid>::template write<FEBasis>(feBasis,x, "cosserat_infile_" + std::to_string(gridView.grid().maxLevel()+1));
+
+
+  /////////////////////////////////////////////////////////////////
+  //   Measure the discretization error
+  /////////////////////////////////////////////////////////////////
+#if 0
+  if (parameterSet.get<std::string>("discretizationErrorMode")=="analytical")
+  {
+    // Read reference solution and its derivative into a PythonFunction
+    typedef VirtualDifferentiableFunction<FieldVector<double, dim>, TargetSpace::CoordinateType> FBase;
+
+    Python::Module module = Python::import(parameterSet.get<std::string>("referenceSolution"));
+    auto referenceSolution = module.get("fdf").toC<std::shared_ptr<FBase>>();
+
+    // The numerical solution, as a grid function
+    GFE::EmbeddedGlobalGFEFunction<FufemFEBasis, TargetSpace> numericalSolution(feBasis, x);
+
+    // QuadratureRule for the integral of the L^2 error
+    QuadratureRuleKey quadKey(dim,6);
+
+    // Compute the embedded L^2 error
+    double l2Error = DiscretizationError<GridType::LeafGridView>::computeL2Error(&numericalSolution,
+                                                                                 referenceSolution.get(),
+                                                                                 quadKey);
+
+    // Compute the embedded H^1 error
+    double h1Error = DiscretizationError<GridType::LeafGridView>::computeH1HalfNormDifferenceSquared(grid->leafGridView(),
+                                                                                                     &numericalSolution,
+                                                                                                     referenceSolution.get(),
+                                                                                                     quadKey);
+
+    std::cout << "elements: " << grid->leafGridView().size(0)
+              << "      "
+              << "L^2 error: " << l2Error
+              << "      ";
+    std::cout << "H^1 error: " << std::sqrt(l2Error*l2Error + h1Error) << std::endl;
+  }
+#endif
+
+  if (parameterSet.get<std::string>("discretizationErrorMode")=="discrete")
+  {
+    std::cout << "FOO" << std::endl;
+    using FufemFEBasis = DuneFunctionsBasis<FEBasis>;
+    FufemFEBasis fufemReferenceFEBasis(referenceFEBasis);
+    FufemFEBasis fufemFEBasis(feBasis);
+
+    // The numerical solution, as a grid function
+    GFE::EmbeddedGlobalGFEFunction<FufemFEBasis, TargetSpace> referenceSolution(fufemReferenceFEBasis, referenceX);
+
+    // The numerical solution, as a grid function
+    GFE::EmbeddedGlobalGFEFunction<FufemFEBasis, TargetSpace> numericalSolution(fufemFEBasis, x);
+
+    double l2ErrorSquared = 0;
+    double h1ErrorSquared = 0;
+
+    HierarchicSearch<typename GridView::Grid,typename GridView::IndexSet> hierarchicSearch(gridView.grid(), gridView.indexSet());
+
+    std::cout << "l2: " << l2ErrorSquared << std::endl;
+    for (const auto& rElement : elements(referenceGridView))
+    {
+      const auto& quadRule = QuadratureRules<double, dim>::rule(rElement.type(), 6);
+
+      for (const auto& qp : quadRule)
+      {
+        auto integrationElement = rElement.geometry().integrationElement(qp.position());
+
+        auto globalPos = rElement.geometry().global(qp.position());
+
+        auto element = hierarchicSearch.findEntity(globalPos);
+        auto localPos = element.geometry().local(globalPos);
+
+        auto diff = referenceSolution(rElement, qp.position()) - numericalSolution(element, localPos);
+
+        l2ErrorSquared += integrationElement * qp.weight() * diff.two_norm2();
+
+        auto derDiff = referenceSolution.derivative(rElement, qp.position()) - numericalSolution.derivative(element, localPos);
+
+        h1ErrorSquared += integrationElement * qp.weight() * derDiff.frobenius_norm2();
+
+      }
+    }
+    std::cout << "l2: " << l2ErrorSquared << std::endl;
+
+    std::cout << "levels: " << gridView.grid().maxLevel()+1
+              << "      "
+              << "L^2 error: " << std::sqrt(l2ErrorSquared)
+              << "      "
+              << "H^1 error: " << std::sqrt(l2ErrorSquared + h1ErrorSquared)
+              << std::endl;
+  }
+}
+
+
+int main (int argc, char *argv[]) try
+{
+  // Start Python interpreter
+  Python::start();
+  Python::Reference main = Python::import("__main__");
+  Python::run("import math");
+
+  Python::runStream()
+      << std::endl << "import sys"
+      << std::endl << "sys.path.append('/home/sander/dune/dune-gfe/problems')"
+      << std::endl;
+
+  // parse data file
+  ParameterTree parameterSet;
+  if (argc < 2)
+    DUNE_THROW(Exception, "Usage: ./compute-disc-error <parameter file>");
+
+  ParameterTreeParser::readINITree(argv[1], parameterSet);
+
+  ParameterTreeParser::readOptions(argc, argv, parameterSet);
+
+  // Print all parameters, to have them in the log file
+  parameterSet.report();
+
+  /////////////////////////////////////////
+  //    Create the grids
+  /////////////////////////////////////////
+  typedef UGGrid<dim> GridType;
+
+  const int numLevels = parameterSet.get<int>("numLevels");
+
+  shared_ptr<GridType> grid, referenceGrid;
+
+  FieldVector<double,dimworld> lower(0), upper(1);
+
+  if (parameterSet.get<bool>("structuredGrid"))
+  {
+    lower = parameterSet.get<FieldVector<double,dimworld> >("lower");
+    upper = parameterSet.get<FieldVector<double,dimworld> >("upper");
+
+    array<unsigned int,dim> elements = parameterSet.get<array<unsigned int,dim> >("elements");
+    grid = StructuredGridFactory<GridType>::createCubeGrid(lower, upper, elements);
+    referenceGrid = StructuredGridFactory<GridType>::createCubeGrid(lower, upper, elements);
+  }
+  else
+  {
+    std::string path                = parameterSet.get<std::string>("path");
+    std::string gridFile            = parameterSet.get<std::string>("gridFile");
+    grid = shared_ptr<GridType>(GmshReader<GridType>::read(path + "/" + gridFile));
+    referenceGrid = shared_ptr<GridType>(GmshReader<GridType>::read(path + "/" + gridFile));
+  }
+
+  grid->globalRefine(numLevels-1);
+  referenceGrid->globalRefine(parameterSet.get<int>("numReferenceLevels")-1);
+
+  // Do the actual measurement
+  const int order = parameterSet.get<int>("order");
+  switch (order)
+  {
+    case 1:
+    measureEOC<GridType::LeafGridView,1>(grid->leafGridView(), referenceGrid->leafGridView(), parameterSet);
+    break;
+
+    case 2:
+    measureEOC<GridType::LeafGridView,2>(grid->leafGridView(), referenceGrid->leafGridView(), parameterSet);
+    break;
+
+    case 3:
+    measureEOC<GridType::LeafGridView,3>(grid->leafGridView(), referenceGrid->leafGridView(), parameterSet);
+    break;
+
+    default:
+      DUNE_THROW(NotImplemented, "Order '" << order << "' is not implemented");
+  }
+
+  return 0;
+}
+catch (Exception e)
+{
+  std::cout << e << std::endl;
+  return 1;
+}