diff --git a/dune/gfe/cosseratenergystiffness.hh b/dune/gfe/cosseratenergystiffness.hh
index 212b40b1022b740ad2aa9b13511a0f948e6f855f..197a1d1133413e4d3a62c8c04800a033d114cfcc 100644
--- a/dune/gfe/cosseratenergystiffness.hh
+++ b/dune/gfe/cosseratenergystiffness.hh
@@ -227,10 +227,11 @@ public:
 
     RT curvatureEnergy(const Tensor3<field_type,3,3,gridDim>& DR) const
     {
+        using std::pow;
 #ifdef DONT_USE_CURL
-        return mu_ * std::pow(L_c_ * L_c_ * DR.frobenius_norm2(),q_/2.0);
+        return mu_ * pow(L_c_ * L_c_ * DR.frobenius_norm2(),q_/2.0);
 #else
-        return mu_ * std::pow(L_c_ * L_c_ * curl(DR).frobenius_norm2(),q_/2.0);
+        return mu_ * pow(L_c_ * L_c_ * curl(DR).frobenius_norm2(),q_/2.0);
 #endif
     }
 
diff --git a/dune/gfe/cosseratrodenergy.hh b/dune/gfe/cosseratrodenergy.hh
new file mode 100644
index 0000000000000000000000000000000000000000..a7c1386d4a40aebe08dfec1eba33ad9b8fed999e
--- /dev/null
+++ b/dune/gfe/cosseratrodenergy.hh
@@ -0,0 +1,458 @@
+#ifndef DUNE_GFE_COSSERATRODENERGY_HH
+#define DUNE_GFE_COSSERATRODENERGY_HH
+
+#include <array>
+
+#include <dune/common/fmatrix.hh>
+#include <dune/common/version.hh>
+#if DUNE_VERSION_GTE(DUNE_COMMON, 2, 8)
+#include <dune/common/transpose.hh>
+#endif
+
+#include <dune/istl/matrix.hh>
+#include <dune/geometry/quadraturerules.hh>
+
+#include <dune/functions/functionspacebases/lagrangebasis.hh>
+
+#include <dune/fufem/boundarypatch.hh>
+
+#include <dune/gfe/localenergy.hh>
+#include <dune/gfe/rigidbodymotion.hh>
+
+namespace Dune::GFE {
+
+template<class Basis, class LocalInterpolationRule, class RT>
+class CosseratRodEnergy
+: public LocalEnergy<Basis, RigidBodyMotion<RT,3> >
+{
+    typedef RigidBodyMotion<RT,3> TargetSpace;
+
+    // grid types
+    using GridView = typename Basis::GridView;
+    typedef typename GridView::Grid::ctype DT;
+    typedef typename GridView::template Codim<0>::Entity Entity;
+
+    // some other sizes
+    enum {dim=GridView::dimension};
+
+    // Quadrature order used for the extension and shear energy
+    enum {shearQuadOrder = 2};
+
+    // Quadrature order used for the bending and torsion energy
+    enum {bendingQuadOrder = 2};
+
+public:
+
+    /** \brief The stress-free configuration
+
+      The number type cannot be RT, because RT become `adouble` when
+      using RodLocalStiffness together with an AD system.
+      The referenceConfiguration is not a variable, and we don't
+      want to use `adouble` for it.
+     */
+    std::vector<RigidBodyMotion<double,3> > referenceConfiguration_;
+
+public:
+
+    //! Each block is x, y, theta in 2d, T (R^3 \times SO(3)) in 3d
+    static constexpr auto blocksize = TargetSpace::EmbeddedTangentVector::dimension;
+
+    // /////////////////////////////////
+    //   The material parameters
+    // /////////////////////////////////
+
+    /** \brief Material constants */
+    std::array<double,3> K_;
+    std::array<double,3> A_;
+
+    GridView gridView_;
+
+    //! Constructor
+    CosseratRodEnergy(const GridView& gridView,
+                      const std::array<double,3>& K, const std::array<double,3>& A)
+        : K_(K),
+          A_(A),
+          gridView_(gridView)
+    {}
+
+    /** \brief Constructor setting shape constants and material parameters
+        \param A The rod section area
+        \param J1, J2 The geometric moments (Flächenträgheitsmomente)
+        \param E Young's modulus
+        \param nu Poisson number
+    */
+    CosseratRodEnergy(const GridView& gridView,
+                      double A, double J1, double J2, double E, double nu)
+        : gridView_(gridView)
+    {
+        // shear modulus
+        double G = E/(2+2*nu);
+
+        K_[0] = E * J1;
+        K_[1] = E * J2;
+        K_[2] = G * (J1 + J2);
+
+        A_[0] = G * A;
+        A_[1] = G * A;
+        A_[2] = E * A;
+    }
+
+    /** \brief Set the stress-free configuration
+     */
+    void setReferenceConfiguration(const std::vector<RigidBodyMotion<double,3> >& referenceConfiguration) {
+        referenceConfiguration_ = referenceConfiguration;
+    }
+
+    /** \brief Compute local element energy */
+    virtual RT energy (const typename Basis::LocalView& localView,
+                       const std::vector<RigidBodyMotion<RT,3> >& localSolution) const override;
+
+    /** \brief Get the rod strain at one point in the rod
+     *
+     * \tparam Number This is a member template because the method has to work for double and adouble
+     */
+    template<class ReboundLocalInterpolationRule>
+    auto getStrain(const ReboundLocalInterpolationRule& localSolution,
+                                           const Entity& element,
+                                           const FieldVector<double,1>& pos) const;
+
+    /** \brief Get the rod stress at one point in the rod
+     *
+     * \tparam Number This is a member template because the method has to work for double and adouble
+     */
+    template<class Number>
+    auto getStress(const std::vector<RigidBodyMotion<Number,3> >& localSolution,
+                                           const Entity& element,
+                                           const FieldVector<double,1>& pos) const;
+
+    /** \brief Get average strain for each element */
+    void getStrain(const std::vector<RigidBodyMotion<double,3> >& sol,
+                   BlockVector<FieldVector<double, blocksize> >& strain) const;
+
+    /** \brief Get average stress for each element */
+    void getStress(const std::vector<RigidBodyMotion<double,3> >& sol,
+                   BlockVector<FieldVector<double, blocksize> >& stress) const;
+
+    /** \brief Return resultant force across boundary in canonical coordinates
+
+     \note Linear run-time in the size of the grid */
+    template <class PatchGridView>
+    auto getResultantForce(const BoundaryPatch<PatchGridView>& boundary,
+                                                  const std::vector<RigidBodyMotion<double,3> >& sol) const;
+
+protected:
+
+    std::vector<RigidBodyMotion<double,3> > getLocalReferenceConfiguration(const typename Basis::LocalView& localView) const
+    {
+        unsigned int numOfBaseFct = localView.size();
+        std::vector<RigidBodyMotion<double,3> > localReferenceConfiguration(numOfBaseFct);
+
+        for (size_t i=0; i<numOfBaseFct; i++)
+            localReferenceConfiguration[i] = referenceConfiguration_[localView.index(i)];
+
+        return localReferenceConfiguration;
+    }
+
+      template <class T>
+    static FieldVector<T,3> darboux(const Rotation<T,3>& q, const FieldVector<T,4>& q_s)
+    {
+        FieldVector<T,3> u;  // The Darboux vector
+
+        u[0] = 2 * (q.B(0) * q_s);
+        u[1] = 2 * (q.B(1) * q_s);
+        u[2] = 2 * (q.B(2) * q_s);
+
+        return u;
+    }
+
+};
+
+template<class Basis, class LocalInterpolationRule, class RT>
+RT CosseratRodEnergy<Basis, LocalInterpolationRule, RT>::
+energy(const typename Basis::LocalView& localView,
+       const std::vector<RigidBodyMotion<RT,3> >& localCoefficients) const
+{
+    const auto& localFiniteElement = localView.tree().finiteElement();
+    LocalInterpolationRule localConfiguration(localFiniteElement, localCoefficients);
+
+    const auto& element = localView.element();
+
+    RT energy = 0;
+
+    std::vector<RigidBodyMotion<double,3> > localReferenceCoefficients = getLocalReferenceConfiguration(localView);
+    using InactiveLocalInterpolationRule = typename LocalInterpolationRule::template rebind<RigidBodyMotion<double,3> >::other;
+    InactiveLocalInterpolationRule localReferenceConfiguration(localFiniteElement, localReferenceCoefficients);
+
+    // ///////////////////////////////////////////////////////////////////////////////
+    //   The following two loops are a reduced integration scheme.  We integrate
+    //   the transverse shear and extensional energy with a first-order quadrature
+    //   formula, even though it should be second order.  This prevents shear-locking.
+    // ///////////////////////////////////////////////////////////////////////////////
+
+    const auto& shearingQuad = QuadratureRules<double, 1>::rule(element.type(), shearQuadOrder);
+
+    for (size_t pt=0; pt<shearingQuad.size(); pt++) {
+
+        // Local position of the quadrature point
+        const auto quadPos = shearingQuad[pt].position();
+
+        const double integrationElement = element.geometry().integrationElement(quadPos);
+
+        double weight = shearingQuad[pt].weight() * integrationElement;
+
+        auto strain = getStrain(localConfiguration, element, quadPos);
+
+        // The reference strain
+        auto referenceStrain = getStrain(localReferenceConfiguration, element, quadPos);
+
+        for (int i=0; i<3; i++)
+            energy += weight * 0.5 * A_[i] * (strain[i] - referenceStrain[i]) * (strain[i] - referenceStrain[i]);
+
+    }
+
+    // Get quadrature rule
+    const auto& bendingQuad = QuadratureRules<double, 1>::rule(element.type(), bendingQuadOrder);
+
+    for (size_t pt=0; pt<bendingQuad.size(); pt++) {
+
+        // Local position of the quadrature point
+        const FieldVector<double,1>& quadPos = bendingQuad[pt].position();
+
+        double weight = bendingQuad[pt].weight() * element.geometry().integrationElement(quadPos);
+
+        auto strain = getStrain(localConfiguration, element, quadPos);
+
+        // The reference strain
+        auto referenceStrain = getStrain(localReferenceConfiguration, element, quadPos);
+
+        // Part II: the bending and twisting energy
+        for (int i=0; i<3; i++)
+            energy += weight * 0.5 * K_[i] * (strain[i+3] - referenceStrain[i+3]) * (strain[i+3] - referenceStrain[i+3]);
+
+    }
+
+    return energy;
+}
+
+
+template<class Basis, class LocalInterpolationRule, class RT>
+template <class ReboundLocalInterpolationRule>
+auto CosseratRodEnergy<Basis, LocalInterpolationRule, RT>::
+getStrain(const ReboundLocalInterpolationRule& localInterpolation,
+          const Entity& element,
+          const FieldVector<double,1>& pos) const
+{
+    const auto jit = element.geometry().jacobianInverseTransposed(pos);
+
+    auto value = localInterpolation.evaluate(pos);
+
+    auto referenceDerivative = localInterpolation.evaluateDerivative(pos);
+#if DUNE_VERSION_GTE(DUNE_COMMON, 2, 8)
+    auto derivative = referenceDerivative * transpose(jit);
+#else
+    auto derivative = referenceDerivative;
+    derivative *= jit[0][0];
+#endif
+
+    using Number = std::decay_t<decltype(derivative[0][0])>;
+    FieldVector<Number,3> r_s = {derivative[0][0], derivative[1][0], derivative[2][0]};
+
+    // Transformation from the reference element
+    Quaternion<Number> q_s(derivative[3][0],
+                           derivative[4][0],
+                           derivative[5][0],
+                           derivative[6][0]);
+
+    // /////////////////////////////////////////////
+    //   Sum it all up
+    // /////////////////////////////////////////////
+
+    // Strain defined on each element
+    // Part I: the shearing and stretching strain
+    FieldVector<Number, 6> strain(0);
+    strain[0] = r_s * value.q.director(0);    // shear strain
+    strain[1] = r_s * value.q.director(1);    // shear strain
+    strain[2] = r_s * value.q.director(2);    // stretching strain
+
+    // Part II: the Darboux vector
+
+    FieldVector<Number,3> u = darboux<Number>(value.q, q_s);
+    strain[3] = u[0];
+    strain[4] = u[1];
+    strain[5] = u[2];
+
+    return strain;
+}
+
+template<class Basis, class LocalInterpolationRule, class RT>
+template <class Number>
+auto CosseratRodEnergy<Basis, LocalInterpolationRule, RT>::
+getStress(const std::vector<RigidBodyMotion<Number,3> >& localSolution,
+          const Entity& element,
+          const FieldVector<double, 1>& pos) const
+{
+    const auto& indexSet = gridView_.indexSet();
+    std::vector<TargetSpace> localRefConf = {referenceConfiguration_[indexSet.subIndex(element, 0, 1)],
+                                             referenceConfiguration_[indexSet.subIndex(element, 1, 1)]};
+
+    auto&& strain = getStrain(localSolution, element, pos);
+    auto&& referenceStrain = getStrain(localRefConf, element, pos);
+
+    FieldVector<RT, 6> stress;
+    for (int i=0; i < dim; i++)
+        stress[i] = (strain[i] - referenceStrain[i]) * A_[i];
+
+    for (int i=0; i < dim; i++)
+        stress[i+3] = (strain[i+3] - referenceStrain[i+3]) * K_[i];
+    return stress;
+}
+
+template<class Basis, class LocalInterpolationRule, class RT>
+void CosseratRodEnergy<Basis, LocalInterpolationRule, RT>::
+getStrain(const std::vector<RigidBodyMotion<double,3> >& sol,
+          BlockVector<FieldVector<double, blocksize> >& strain) const
+{
+    const typename GridView::Traits::IndexSet& indexSet = this->basis_.gridView().indexSet();
+
+    if (sol.size()!=this->basis_.size())
+        DUNE_THROW(Exception, "Solution vector doesn't match the grid!");
+
+    // Strain defined on each element
+    strain.resize(indexSet.size(0));
+    strain = 0;
+
+    // Loop over all elements
+    for (const auto& element : elements(this->basis_.gridView()))
+    {
+        int elementIdx = indexSet.index(element);
+
+        // Extract local solution on this element
+        P1LocalFiniteElement<double,double,1> localFiniteElement;
+        int numOfBaseFct = localFiniteElement.localCoefficients().size();
+
+        std::vector<RigidBodyMotion<double,3> > localSolution(2);
+
+        for (int i=0; i<numOfBaseFct; i++)
+            localSolution[i] = sol[indexSet.subIndex(element,i,1)];
+
+        // Get quadrature rule
+        const int polOrd = 2;
+        const auto& quad = QuadratureRules<double, 1>::rule(element.type(), polOrd);
+
+        for (std::size_t pt=0; pt<quad.size(); pt++)
+        {
+            // Local position of the quadrature point
+            const auto quadPos = quad[pt].position();
+
+            double weight = quad[pt].weight() * element.geometry().integrationElement(quadPos);
+
+            auto localStrain = getStrain(localSolution, element, quad[pt].position());
+
+            // Sum it all up
+            strain[elementIdx].axpy(weight, localStrain);
+        }
+
+        // /////////////////////////////////////////////////////////////////////////
+        //   We want the average strain per element.  Therefore we have to divide
+        //   the integral we just computed by the element volume.
+        // /////////////////////////////////////////////////////////////////////////
+        // we know the element is a line, therefore the integration element is the volume
+        FieldVector<double,1> dummyPos(0.5);
+        strain[elementIdx] /= element.geometry().integrationElement(dummyPos);
+    }
+}
+
+template<class Basis, class LocalInterpolationRule, class RT>
+void CosseratRodEnergy<Basis, LocalInterpolationRule, RT>::
+getStress(const std::vector<RigidBodyMotion<double,3> >& sol,
+          BlockVector<FieldVector<double, blocksize> >& stress) const
+{
+    // Get the strain
+    getStrain(sol,stress);
+
+    // Get reference strain
+    BlockVector<FieldVector<double, blocksize> > referenceStrain;
+    getStrain(referenceConfiguration_, referenceStrain);
+
+    // Linear diagonal constitutive law
+    for (size_t i=0; i<stress.size(); i++)
+    {
+        for (int j=0; j<3; j++)
+        {
+            stress[i][j]   = (stress[i][j]   - referenceStrain[i][j])   * A_[j];
+            stress[i][j+3] = (stress[i][j+3] - referenceStrain[i][j+3]) * K_[j];
+        }
+    }
+}
+
+template<class Basis, class LocalInterpolationRule, class RT>
+template <class PatchGridView>
+auto CosseratRodEnergy<Basis, LocalInterpolationRule, RT>::
+getResultantForce(const BoundaryPatch<PatchGridView>& boundary,
+                  const std::vector<RigidBodyMotion<double,3> >& sol) const
+{
+    const typename GridView::Traits::IndexSet& indexSet = this->basis_.gridView().indexSet();
+
+    if (sol.size()!=indexSet.size(1))
+        DUNE_THROW(Exception, "Solution vector doesn't match the grid!");
+
+    FieldVector<double,3> canonicalStress(0);
+    FieldVector<double,3> canonicalTorque(0);
+
+    // Loop over the given boundary
+    for (auto facet : boundary)
+    {
+        // //////////////////////////////////////////////
+        //   Compute force across this boundary face
+        // //////////////////////////////////////////////
+
+        double pos = facet.geometryInInside().corner(0);
+
+        std::vector<RigidBodyMotion<double,3> > localSolution(2);
+        localSolution[0] = sol[indexSet.subIndex(*facet.inside(),0,1)];
+        localSolution[1] = sol[indexSet.subIndex(*facet.inside(),1,1)];
+
+        std::vector<RigidBodyMotion<double,3> > localRefConf(2);
+        localRefConf[0] = referenceConfiguration_[indexSet.subIndex(*facet.inside(),0,1)];
+        localRefConf[1] = referenceConfiguration_[indexSet.subIndex(*facet.inside(),1,1)];
+
+        auto strain          = getStrain(localSolution, *facet.inside(), pos);
+        auto referenceStrain = getStrain(localRefConf, *facet.inside(), pos);
+
+        FieldVector<double,3> localStress;
+        for (int i=0; i<3; i++)
+            localStress[i] = (strain[i] - referenceStrain[i]) * A_[i];
+
+        FieldVector<double,3> localTorque;
+        for (int i=0; i<3; i++)
+            localTorque[i] = (strain[i+3] - referenceStrain[i+3]) * K_[i];
+
+        // Transform stress given with respect to the basis given by the three directors to
+        // the canonical basis of R^3
+
+        FieldMatrix<double,3,3> orientationMatrix;
+        sol[indexSet.subIndex(*facet.inside(),facet.indexInInside(),1)].q.matrix(orientationMatrix);
+
+        orientationMatrix.umv(localStress, canonicalStress);
+
+        orientationMatrix.umv(localTorque, canonicalTorque);
+
+        // Multiply force times boundary normal to get the transmitted force
+        canonicalStress *= facet.unitOuterNormal(FieldVector<double,0>(0))[0];
+        canonicalTorque *= facet.unitOuterNormal(FieldVector<double,0>(0))[0];
+    }
+
+    FieldVector<double,6> result;
+    for (int i=0; i<3; i++)
+    {
+        result[i] = canonicalStress[i];
+        result[i+3] = canonicalTorque[i];
+    }
+
+    return result;
+}
+
+}  // namespace Dune::GFE
+
+#endif
+
diff --git a/dune/gfe/geodesicfeassembler.hh b/dune/gfe/geodesicfeassembler.hh
index 7be9133aa8839008cef76454992ffd251fac41f4..cdd98f405361db054429f9288f69331cebbaa418 100644
--- a/dune/gfe/geodesicfeassembler.hh
+++ b/dune/gfe/geodesicfeassembler.hh
@@ -212,7 +212,7 @@ assembleGradient(const std::vector<TargetSpace>& sol,
     {
         localView.bind(element);
 
-        // A 1d grid has two vertices
+        // The number of degrees of freedom of the current element
         const auto nDofs = localView.tree().size();
 
         // Extract local solution
diff --git a/dune/gfe/geodesicfeassemblerwrapper.hh b/dune/gfe/geodesicfeassemblerwrapper.hh
index 4570b4077798ce8fbe3e14a55444e91adf4ec1bc..c42a1e3ef63b001b01d231de9fc95a7947648096 100644
--- a/dune/gfe/geodesicfeassemblerwrapper.hh
+++ b/dune/gfe/geodesicfeassemblerwrapper.hh
@@ -84,7 +84,7 @@ splitVector(const std::vector<TargetSpace>& sol) const {
     Dune::TupleVector<std::vector<MixedSpace0>,std::vector<MixedSpace1>> solutionSplit;
     solutionSplit[_0].resize(n);
     solutionSplit[_1].resize(n);
-    for (int i = 0; i < n; i++) {
+    for (std::size_t i = 0; i < n; i++) {
         solutionSplit[_0][i] = sol[i].r; // Deformation part
         solutionSplit[_1][i] = sol[i].q; // Rotational part
     }
@@ -145,7 +145,7 @@ assembleGradientAndHessian(const std::vector<TargetSpace>& sol,
     hessian = 0;
     gradient.resize(n);
     gradient = 0;
-    for (int i = 0; i < n; i++) {
+    for (std::size_t i = 0; i < n; i++) {
         for (int j = 0; j < blocksize0 + blocksize1; j++)
             gradient[i][j] = j < blocksize0 ? gradient0[i][j] : gradient1[i][j - blocksize0];
     }
diff --git a/dune/gfe/gramschmidtsolver.hh b/dune/gfe/gramschmidtsolver.hh
index 9f5bc7ce47f47c43eddda15ff0fe52acd52fbc91..202fd21be8a8cba0865b3fa82bd1fc663e72babb 100644
--- a/dune/gfe/gramschmidtsolver.hh
+++ b/dune/gfe/gramschmidtsolver.hh
@@ -27,7 +27,8 @@ class GramSchmidtSolver
   static void normalize(const Dune::SymmetricMatrix<field_type,embeddedDim>& matrix,
                         Dune::FieldVector<field_type,embeddedDim>& v)
   {
-    v /= std::sqrt(matrix.energyScalarProduct(v,v));
+    using std::sqrt;
+    v /= sqrt(matrix.energyScalarProduct(v,v));
   }
 
 
@@ -130,4 +131,4 @@ private:
 
 };
 
-#endif
\ No newline at end of file
+#endif
diff --git a/dune/gfe/localfirstordermodel.hh b/dune/gfe/localfirstordermodel.hh
index a098c5bacc3c549d4caea909e6815fb3111c0fab..ad5c1903cf122a9caecc6a5a9179dc946eef13a0 100644
--- a/dune/gfe/localfirstordermodel.hh
+++ b/dune/gfe/localfirstordermodel.hh
@@ -13,9 +13,7 @@ class LocalFirstOrderModel
 {
 public:
 
-    /** \brief Assemble the element gradient of the energy functional
-
-    The default implementation in this class uses a finite difference approximation */
+    /** \brief Assemble the element gradient of the energy functional */
     virtual void assembleGradient(const typename Basis::LocalView& localView,
                                   const std::vector<TargetSpace>& solution,
                                   std::vector<typename TargetSpace::TangentVector>& gradient) const = 0;
diff --git a/dune/gfe/localgeodesicfefunction.hh b/dune/gfe/localgeodesicfefunction.hh
index 3502f371dc54ec4756c2a7701604a6eda35d4153..e13acbd8d4934b9b0fd6010175be22eb0a519e71 100644
--- a/dune/gfe/localgeodesicfefunction.hh
+++ b/dune/gfe/localgeodesicfefunction.hh
@@ -59,6 +59,13 @@ public:
         assert(localFiniteElement_.localBasis().size() == coefficients_.size());
     }
 
+    /** \brief Rebind the FEFunction to another TargetSpace */
+    template<class U>
+    struct rebind
+    {
+      using other = LocalGeodesicFEFunction<dim,ctype,LocalFiniteElement,U>;
+    };
+
     /** \brief The number of Lagrange points */
     unsigned int size() const
     {
@@ -589,6 +596,13 @@ public:
 
     }
 
+    /** \brief Rebind the FEFunction to another TargetSpace */
+    template<class U>
+    struct rebind
+    {
+      using other = LocalGeodesicFEFunction<dim,ctype,LocalFiniteElement,U>;
+    };
+
     /** \brief The number of Lagrange points */
     unsigned int size() const
     {
diff --git a/dune/gfe/localprojectedfefunction.hh b/dune/gfe/localprojectedfefunction.hh
index 259270ccb475e1b63b84227c543bba7391ff5761..ba538c55f28df4b9f0bbe37829e023d454d4e622 100644
--- a/dune/gfe/localprojectedfefunction.hh
+++ b/dune/gfe/localprojectedfefunction.hh
@@ -70,6 +70,13 @@ Dune::FieldMatrix< K, m, p > operator* ( const Dune::FieldMatrix< K, m, n > &A,
         assert(localFiniteElement_.localBasis().size() == coefficients_.size());
       }
 
+      /** \brief Rebind the FEFunction to another TargetSpace */
+      template<class U>
+      struct rebind
+      {
+        using other = LocalProjectedFEFunction<dim,ctype,LocalFiniteElement,U>;
+      };
+
       /** \brief The number of Lagrange points */
       unsigned int size() const
       {
@@ -452,6 +459,13 @@ Dune::FieldMatrix< K, m, p > operator* ( const Dune::FieldMatrix< K, m, n > &A,
         orientationFunction_ = std::make_unique<LocalProjectedFEFunction<dim,ctype,LocalFiniteElement,Rotation<field_type,3> > > (localFiniteElement,orientationCoefficients);
       }
 
+      /** \brief Rebind the FEFunction to another TargetSpace */
+      template<class U>
+      struct rebind
+      {
+        using other = LocalProjectedFEFunction<dim,ctype,LocalFiniteElement,U>;
+      };
+
       /** \brief The number of Lagrange points */
       unsigned int size() const
       {
diff --git a/dune/gfe/parallel/globalp2mapper.hh b/dune/gfe/parallel/globalp2mapper.hh
index 437273b96e4b714dadfa1e9f3eb5258843735b74..82c0ac3401cfac2daeaf719f110af147137989e6 100644
--- a/dune/gfe/parallel/globalp2mapper.hh
+++ b/dune/gfe/parallel/globalp2mapper.hh
@@ -26,54 +26,96 @@ namespace Dune {
       p2Mapper_(gridView)
     {
 #if !HAVE_DUNE_PARMG
-      static_assert(GridView::dimension==2, "Only implemented for two-dimensional grids");
+      static_assert(GridView::dimension<=2, "Only implemented for one- and two-dimensional grids");
 
       if (gridView.size(GeometryTypes::triangle)>1)
         DUNE_THROW(NotImplemented, "GlobalP2Mapper only works for quad grids!");
 
-      GlobalIndexSet<GridView> globalVertexIndex(gridView,2);
-      GlobalIndexSet<GridView> globalEdgeIndex(gridView,1);
+      GlobalIndexSet<GridView> globalVertexIndex(gridView,GridView::dimension);
       GlobalIndexSet<GridView> globalElementIndex(gridView,0);
 
-      // total number of degrees of freedom
-      this->size_ = globalVertexIndex.size(2) + globalEdgeIndex.size(1) + globalElementIndex.size(0);
-
       auto localView = p2Mapper_.localView();
 
-      // Determine
-      for (const auto& element : elements(gridView))
+      if (GridView::dimension==1)
       {
-        localView.bind(element);
+        // total number of degrees of freedom
+        this->size_ = globalVertexIndex.size(GridView::dimension) + globalElementIndex.size(0);
 
-        // Loop over all local degrees of freedom
-        for (size_t i=0; i<localView.size(); i++)
+        // Determine
+        for (const auto& element : elements(gridView))
         {
-          int codim = localView.tree().finiteElement().localCoefficients().localKey(i).codim();
-          int entity   = localView.tree().finiteElement().localCoefficients().localKey(i).subEntity();
+          localView.bind(element);
 
-          auto localIndex  = localView.index(i);
-          int globalIndex;
-          switch (codim)
+          // Loop over all local degrees of freedom
+          for (size_t i=0; i<localView.size(); i++)
           {
-            case 2:  // vertex dofs
-              globalIndex = globalVertexIndex.index(element.template subEntity<2>(entity));
-              break;
-
-            case 1:  // edge dofs
-              globalIndex = globalEdgeIndex.index(element.template subEntity<1>(entity)) + globalVertexIndex.size(2);
-              break;
-
-            case 0:  // element dofs
-              globalIndex = globalElementIndex.index(element.template subEntity<0>(entity))
-                            + globalEdgeIndex.size(1)
-                            + globalVertexIndex.size(2);
-              break;
-
-            default:
-              DUNE_THROW(Dune::Exception, "Impossible codimension!");
+            int codim = localView.tree().finiteElement().localCoefficients().localKey(i).codim();
+            int entity   = localView.tree().finiteElement().localCoefficients().localKey(i).subEntity();
+
+            auto localIndex  = localView.index(i);
+            int globalIndex;
+            switch (codim)
+            {
+              case 1:  // vertex dofs
+                globalIndex = globalVertexIndex.index(element.template subEntity<1>(entity));
+                break;
+
+              case 0:  // element dofs
+                globalIndex = globalElementIndex.index(element.template subEntity<0>(entity))
+                              + globalVertexIndex.size(2);
+                break;
+
+              default:
+                DUNE_THROW(Dune::Exception, "Impossible codimension!");
+            }
+
+            localGlobalMap_[localIndex]  = globalIndex;
           }
+        }
+
+      }
+      else
+      {
+        GlobalIndexSet<GridView> globalEdgeIndex(gridView,1);
 
-          localGlobalMap_[localIndex]  = globalIndex;
+        // total number of degrees of freedom
+        this->size_ = globalVertexIndex.size(2) + globalEdgeIndex.size(1) + globalElementIndex.size(0);
+
+        // Determine
+        for (const auto& element : elements(gridView))
+        {
+          localView.bind(element);
+
+          // Loop over all local degrees of freedom
+          for (size_t i=0; i<localView.size(); i++)
+          {
+            int codim = localView.tree().finiteElement().localCoefficients().localKey(i).codim();
+            int entity   = localView.tree().finiteElement().localCoefficients().localKey(i).subEntity();
+
+            auto localIndex  = localView.index(i);
+            int globalIndex;
+            switch (codim)
+            {
+              case 2:  // vertex dofs
+                globalIndex = globalVertexIndex.index(element.template subEntity<GridView::dimension>(entity));
+                break;
+
+              case 1:  // edge dofs
+                globalIndex = globalEdgeIndex.index(element.template subEntity<1>(entity)) + globalVertexIndex.size(2);
+                break;
+
+              case 0:  // element dofs
+                globalIndex = globalElementIndex.index(element.template subEntity<0>(entity))
+                              + globalEdgeIndex.size(1)
+                              + globalVertexIndex.size(2);
+                break;
+
+              default:
+                DUNE_THROW(Dune::Exception, "Impossible codimension!");
+            }
+
+            localGlobalMap_[localIndex]  = globalIndex;
+          }
         }
       }
 #endif
diff --git a/dune/gfe/riemannianpnsolver.cc b/dune/gfe/riemannianpnsolver.cc
index 4937720c4adabd0abb1ce46a66eed4ab1a2605be..1976ed3c5f9b630f27614fed39a24e2a3d92c332 100644
--- a/dune/gfe/riemannianpnsolver.cc
+++ b/dune/gfe/riemannianpnsolver.cc
@@ -243,7 +243,7 @@ void RiemannianProximalNewtonSolver<Basis,TargetSpace,Assembler>::solve()
               std::cout << "Gradient norm: " << l2Norm_->operator()(gradient) << std::endl;
 
             if (this->verbosity_ == Solver::FULL and rank==0)
-              std::cout << "Oveall assembly took " << gradientTimer.elapsed() << " sec." << std::endl;
+              std::cout << "Overall assembly took " << gradientTimer.elapsed() << " sec." << std::endl;
             totalAssemblyTime += gradientTimer.elapsed();
 
             // Transfer matrix data
diff --git a/dune/gfe/riemanniantrsolver.cc b/dune/gfe/riemanniantrsolver.cc
index 88d4e7713aa48b760478a93cbd3ddeb323979acc..89a0e3246dc7a94ccfe28096bd644b9ee30775ea 100644
--- a/dune/gfe/riemanniantrsolver.cc
+++ b/dune/gfe/riemanniantrsolver.cc
@@ -424,7 +424,7 @@ void RiemannianTrustRegionSolver<Basis,TargetSpace,Assembler>::solve()
               std::cout << "Gradient norm: " << gradient.two_norm() << std::endl;
             }
             if (this->verbosity_ == Solver::FULL and rank==0)
-              std::cout << "Oveall assembly took " << gradientTimer.elapsed() << " sec." << std::endl;
+              std::cout << "Overall assembly took " << gradientTimer.elapsed() << " sec." << std::endl;
             totalAssemblyTime += gradientTimer.elapsed();
 
             // Transfer matrix data
diff --git a/dune/gfe/rodassembler.cc b/dune/gfe/rodassembler.cc
deleted file mode 100644
index 32300bd3fe334971b8bd850a69255938bb5afbfa..0000000000000000000000000000000000000000
--- a/dune/gfe/rodassembler.cc
+++ /dev/null
@@ -1,591 +0,0 @@
-#include <dune/istl/bcrsmatrix.hh>
-#include <dune/common/fmatrix.hh>
-#include <dune/istl/matrixindexset.hh>
-#include <dune/istl/matrix.hh>
-
-#include <dune/geometry/quadraturerules.hh>
-
-#include <dune/localfunctions/lagrange/p1.hh>
-
-#include <dune/gfe/rodlocalstiffness.hh>
-
-
-
-template <class Basis>
-void RodAssembler<Basis,3>::
-assembleGradient(const std::vector<RigidBodyMotion<double,3> >& sol,
-                 Dune::BlockVector<Dune::FieldVector<double, blocksize> >& grad) const
-{
-    using namespace Dune;
-
-    if (sol.size()!=this->basis_.size())
-        DUNE_THROW(Exception, "Solution vector doesn't match the grid!");
-
-    grad.resize(sol.size());
-    grad = 0;
-
-    // A view on the FE basis on a single element
-    auto localView = this->basis_.localView();
-
-    // Loop over all elements
-    for (const auto& element : Dune::elements(this->basis_.gridView()))
-    {
-        localView.bind(element);
-
-        // A 1d grid has two vertices
-        static const int nDofs = 2;
-
-        // Extract local solution
-        std::vector<RigidBodyMotion<double,3> > localSolution(nDofs);
-
-        for (int i=0; i<nDofs; i++)
-            localSolution[i] = sol[localView.index(i)];
-
-        // Assemble local gradient
-        std::vector<FieldVector<double,blocksize> > localGradient(nDofs);
-
-        this->localStiffness_->assembleGradient(localView,
-                                                localSolution,
-                                                localGradient);
-
-        // Add to global gradient
-        for (int i=0; i<nDofs; i++)
-            grad[localView.index(i)] += localGradient[i];
-
-    }
-
-}
-
-
-template <class GridView>
-void RodAssembler<GridView,3>::
-getStrain(const std::vector<RigidBodyMotion<double,3> >& sol,
-          Dune::BlockVector<Dune::FieldVector<double, blocksize> >& strain) const
-{
-    using namespace Dune;
-
-    const typename GridView::Traits::IndexSet& indexSet = this->basis_.gridView().indexSet();
-
-    if (sol.size()!=this->basis_.size())
-        DUNE_THROW(Exception, "Solution vector doesn't match the grid!");
-
-    // Strain defined on each element
-    strain.resize(indexSet.size(0));
-    strain = 0;
-
-    // Loop over all elements
-    for (const auto& element : elements(this->basis_.gridView()))
-    {
-        int elementIdx = indexSet.index(element);
-
-        // Extract local solution on this element
-        Dune::P1LocalFiniteElement<double,double,gridDim> localFiniteElement;
-        int numOfBaseFct = localFiniteElement.localCoefficients().size();
-
-        std::vector<RigidBodyMotion<double,3> > localSolution(2);
-
-        for (int i=0; i<numOfBaseFct; i++)
-            localSolution[i] = sol[indexSet.subIndex(element,i,gridDim)];
-
-        // Get quadrature rule
-        const int polOrd = 2;
-        const auto& quad = QuadratureRules<double, gridDim>::rule(element.type(), polOrd);
-
-        for (std::size_t pt=0; pt<quad.size(); pt++) {
-
-            // Local position of the quadrature point
-            const FieldVector<double,gridDim>& quadPos = quad[pt].position();
-
-            double weight = quad[pt].weight() * element.geometry().integrationElement(quadPos);
-
-            FieldVector<double,blocksize> localStrain = std::dynamic_pointer_cast<RodLocalStiffness<GridView, double> >(this->localStiffness_)->getStrain(localSolution, element, quad[pt].position());
-
-            // Sum it all up
-            strain[elementIdx].axpy(weight, localStrain);
-
-        }
-
-        // /////////////////////////////////////////////////////////////////////////
-        //   We want the average strain per element.  Therefore we have to divide
-        //   the integral we just computed by the element volume.
-        // /////////////////////////////////////////////////////////////////////////
-        // we know the element is a line, therefore the integration element is the volume
-        FieldVector<double,1> dummyPos(0.5);
-        strain[elementIdx] /= element.geometry().integrationElement(dummyPos);
-
-    }
-
-}
-
-template <class GridView>
-void RodAssembler<GridView,3>::
-getStress(const std::vector<RigidBodyMotion<double,3> >& sol,
-          Dune::BlockVector<Dune::FieldVector<double, blocksize> >& stress) const
-{
-    // Get the strain
-    getStrain(sol,stress);
-
-    // Get reference strain
-    Dune::BlockVector<Dune::FieldVector<double, blocksize> > referenceStrain;
-    getStrain(dynamic_cast<RodLocalStiffness<GridView, double>* >(this->localStiffness_)->referenceConfiguration_, referenceStrain);
-
-    // Linear diagonal constitutive law
-    for (size_t i=0; i<stress.size(); i++) {
-        for (int j=0; j<3; j++) {
-            stress[i][j]   = (stress[i][j]   - referenceStrain[i][j])   * dynamic_cast<RodLocalStiffness<GridView, double>* >(this->localStiffness_)->A_[j];
-            stress[i][j+3] = (stress[i][j+3] - referenceStrain[i][j+3]) * dynamic_cast<RodLocalStiffness<GridView, double>* >(this->localStiffness_)->K_[j];
-        }
-    }
-}
-
-template <class GridView>
-template <class PatchGridView>
-Dune::FieldVector<double,6> RodAssembler<GridView,3>::
-getResultantForce(const BoundaryPatch<PatchGridView>& boundary,
-                  const std::vector<RigidBodyMotion<double,3> >& sol) const
-{
-    using namespace Dune;
-
-    //    if (gridView_ != &boundary.gridView())
-    //        DUNE_THROW(Dune::Exception, "The boundary patch has to match the grid view of the assembler!");
-
-    const typename GridView::Traits::IndexSet& indexSet = this->basis_.gridView().indexSet();
-
-    if (sol.size()!=indexSet.size(gridDim))
-        DUNE_THROW(Exception, "Solution vector doesn't match the grid!");
-
-    FieldVector<double,3> canonicalStress(0);
-    FieldVector<double,3> canonicalTorque(0);
-
-    // Loop over the given boundary
-    typename BoundaryPatch<PatchGridView>::iterator it    = boundary.begin();
-    typename BoundaryPatch<PatchGridView>::iterator endIt = boundary.end();
-
-    for (; it!=endIt; ++it) {
-
-            // //////////////////////////////////////////////
-            //   Compute force across this boundary face
-            // //////////////////////////////////////////////
-
-            double pos = it->geometryInInside().corner(0);
-
-            std::vector<RigidBodyMotion<double,3> > localSolution(2);
-            localSolution[0] = sol[indexSet.subIndex(*it->inside(),0,1)];
-            localSolution[1] = sol[indexSet.subIndex(*it->inside(),1,1)];
-
-            std::vector<RigidBodyMotion<double,3> > localRefConf(2);
-            localRefConf[0] = dynamic_cast<RodLocalStiffness<GridView, double>* >(this->localStiffness_)->referenceConfiguration_[indexSet.subIndex(*it->inside(),0,1)];
-            localRefConf[1] = dynamic_cast<RodLocalStiffness<GridView, double>* >(this->localStiffness_)->referenceConfiguration_[indexSet.subIndex(*it->inside(),1,1)];
-
-            FieldVector<double, blocksize> strain          = dynamic_cast<RodLocalStiffness<GridView, double>* >(this->localStiffness_)->getStrain(localSolution, *it->inside(), pos);
-            FieldVector<double, blocksize> referenceStrain = dynamic_cast<RodLocalStiffness<GridView, double>* >(this->localStiffness_)->getStrain(localRefConf, *it->inside(), pos);
-
-            FieldVector<double,3> localStress;
-            for (int i=0; i<3; i++)
-                localStress[i] = (strain[i] - referenceStrain[i]) * dynamic_cast<RodLocalStiffness<GridView, double>* >(this->localStiffness_)->A_[i];
-
-            FieldVector<double,3> localTorque;
-            for (int i=0; i<3; i++)
-                localTorque[i] = (strain[i+3] - referenceStrain[i+3]) * dynamic_cast<RodLocalStiffness<GridView, double>* >(this->localStiffness_)->K_[i];
-
-            // Transform stress given with respect to the basis given by the three directors to
-            // the canonical basis of R^3
-
-            FieldMatrix<double,3,3> orientationMatrix;
-            sol[indexSet.subIndex(*it->inside(),it->indexInInside(),1)].q.matrix(orientationMatrix);
-
-            orientationMatrix.umv(localStress, canonicalStress);
-
-            orientationMatrix.umv(localTorque, canonicalTorque);
-            // Reverse transformation to make sure we did the correct thing
-//             assert( std::abs(localStress[0]-canonicalStress*sol[0].q.director(0)) < 1e-6 );
-//             assert( std::abs(localStress[1]-canonicalStress*sol[0].q.director(1)) < 1e-6 );
-//             assert( std::abs(localStress[2]-canonicalStress*sol[0].q.director(2)) < 1e-6 );
-
-            // Multiply force times boundary normal to get the transmitted force
-            canonicalStress *= it->unitOuterNormal(FieldVector<double,0>(0))[0];
-            canonicalTorque *= it->unitOuterNormal(FieldVector<double,0>(0))[0];
-
-    }
-
-    Dune::FieldVector<double,6> result;
-    for (int i=0; i<3; i++) {
-        result[i] = canonicalStress[i];
-        result[i+3] = canonicalTorque[i];
-    }
-
-    return result;
-}
-
-
-template <class GridView>
-void RodAssembler<GridView,2>::
-assembleMatrix(const std::vector<RigidBodyMotion<double,2> >& sol,
-               Dune::BCRSMatrix<MatrixBlock>& matrix)
-{
-    Dune::MatrixIndexSet neighborsPerVertex;
-    this->getNeighborsPerVertex(neighborsPerVertex);
-
-    matrix = 0;
-
-    Dune::Matrix<MatrixBlock> mat;
-
-    for (const auto& element : Dune::elements(this->basis_.gridView()))
-    {
-        const int numOfBaseFct = 2;
-
-        // Extract local solution
-        std::vector<RigidBodyMotion<double,2> > localSolution(numOfBaseFct);
-
-        for (int i=0; i<numOfBaseFct; i++)
-            localSolution[i] = sol[this->basis_.index(element,i)];
-
-        // setup matrix
-        getLocalMatrix(element, localSolution, mat);
-
-        // Add element matrix to global stiffness matrix
-        for(int i=0; i<numOfBaseFct; i++) {
-
-            int row = this->basis_.index(element,i);
-
-            for (int j=0; j<numOfBaseFct; j++ ) {
-
-                int col = this->basis_.index(element,j);
-                matrix[row][col] += mat[i][j];
-
-            }
-        }
-
-    }
-
-}
-
-
-
-
-
-
-template <class GridView>
-void RodAssembler<GridView,2>::
-getLocalMatrix( EntityType &entity,
-                const std::vector<RigidBodyMotion<double,2> >& localSolution,
-                Dune::Matrix<MatrixBlock>& localMat) const
-{
-    /* ndof is the number of vectors of the element */
-    int ndof = localSolution.size();
-
-    localMat.setSize(ndof,ndof);
-    localMat = 0;
-
-    Dune::P1LocalFiniteElement<double,double,gridDim> localFiniteElement;
-
-    // Get quadrature rule
-    const Dune::QuadratureRule<double, gridDim>& quad = Dune::QuadratureRules<double, gridDim>::rule(entity.type(), 2);
-
-    /* Loop over all integration points */
-    for (int ip=0; ip<quad.size(); ip++) {
-
-        // Local position of the quadrature point
-        const Dune::FieldVector<double,gridDim>& quadPos = quad[ip].position();
-
-        // calc Jacobian inverse before integration element is evaluated
-        const Dune::FieldMatrix<double,gridDim,gridDim>& inv = entity.geometry().jacobianInverseTransposed(quadPos);
-        const double integrationElement = entity.geometry().integrationElement(quadPos);
-
-        /* Compute the weight of the current integration point */
-        double weight = quad[ip].weight() * integrationElement;
-
-        /**********************************************/
-        /* compute gradients of the shape functions   */
-        /**********************************************/
-        std::vector<Dune::FieldMatrix<double,1,gridDim> > referenceElementGradients(ndof);
-        localFiniteElement.localBasis().evaluateJacobian(quadPos,referenceElementGradients);
-
-        std::vector<Dune::FieldVector<double,gridDim> > shapeGrad(ndof);
-
-        // multiply with jacobian inverse
-        for (int dof=0; dof<ndof; dof++)
-            inv.mv(referenceElementGradients[dof][0], shapeGrad[dof]);
-
-
-        std::vector<Dune::FieldVector<double,1> > shapeFunction;
-        localFiniteElement.localBasis().evaluateFunction(quadPos,shapeFunction);
-
-        // //////////////////////////////////
-        //   Interpolate
-        // //////////////////////////////////
-
-        double x_s     = localSolution[0].r[0]*shapeGrad[0][0] + localSolution[1].r[0]*shapeGrad[1][0];
-        double y_s     = localSolution[0].r[1]*shapeGrad[0][0] + localSolution[1].r[1]*shapeGrad[1][0];
-
-        double theta   = localSolution[0].q.angle_*shapeFunction[0] + localSolution[1].q.angle_*shapeFunction[1];
-
-        for (int i=0; i<localMat.N(); i++) {
-
-            for (int j=0; j<localMat.M(); j++) {
-
-                // \partial J^2 / \partial x_i \partial x_j
-                localMat[i][j][0][0] += weight * shapeGrad[i][0] * shapeGrad[j][0]
-                    * (A1 * cos(theta) * cos(theta) + A3 * sin(theta) * sin(theta));
-
-                // \partial J^2 / \partial x_i \partial y_j
-                localMat[i][j][0][1] += weight * shapeGrad[i][0] * shapeGrad[j][0]
-                    * (-A1 + A3) * sin(theta)* cos(theta);
-
-                // \partial J^2 / \partial x_i \partial theta_j
-                localMat[i][j][0][2] += weight * shapeGrad[i][0] * shapeFunction[j]
-                    * (-A1 * (x_s*sin(theta) + y_s*cos(theta)) * cos(theta)
-                       - A1* (x_s*cos(theta) - y_s*sin(theta)) * sin(theta)
-                       +A3 * (x_s*cos(theta) - y_s*sin(theta)) * sin(theta)
-                       +A3 * (x_s*sin(theta) + y_s*cos(theta) - 1) * cos(theta));
-
-                // \partial J^2 / \partial y_i \partial x_j
-                localMat[i][j][1][0] += weight * shapeGrad[i][0] * shapeGrad[j][0]
-                    * (-A1 * sin(theta)* cos(theta) + A3 * cos(theta) * sin(theta));
-
-                // \partial J^2 / \partial y_i \partial y_j
-                localMat[i][j][1][1] += weight * shapeGrad[i][0] * shapeGrad[j][0]
-                    * (A1 * sin(theta)*sin(theta) + A3 * cos(theta)*cos(theta));
-
-                // \partial J^2 / \partial y_i \partial theta_j
-                localMat[i][j][1][2] += weight * shapeGrad[i][0] * shapeFunction[j]
-                    * (A1  * (x_s * sin(theta) + y_s * cos(theta)) * sin(theta)
-                       -A1 * (x_s * cos(theta) - y_s * sin(theta)) * cos(theta)
-                       +A3 * (x_s * cos(theta) - y_s * sin(theta)) * cos(theta)
-                       -A3 * (x_s * sin(theta) + y_s * cos(theta) - 1) * sin(theta));
-
-                // \partial J^2 / \partial theta_i \partial x_j
-                localMat[i][j][2][0] += weight * shapeFunction[i] * shapeGrad[j][0]
-                    * (-A1 * (x_s*sin(theta) + y_s*cos(theta)) * cos(theta)
-                       - A1* (x_s*cos(theta) - y_s*sin(theta)) * sin(theta)
-                       +A3 * (x_s*cos(theta) - y_s*sin(theta)) * sin(theta)
-                       +A3 * (x_s*sin(theta) + y_s*cos(theta) - 1) * cos(theta));
-
-                // \partial J^2 / \partial theta_i \partial y_j
-                localMat[i][j][2][1] += weight * shapeFunction[i] * shapeGrad[j][0]
-                    * (A1  * (x_s * sin(theta) + y_s * cos(theta)) * sin(theta)
-                       -A1 * (x_s * cos(theta) - y_s * sin(theta)) * cos(theta)
-                       +A3 * (x_s * cos(theta) - y_s * sin(theta)) * cos(theta)
-                       -A3 * (x_s * sin(theta) + y_s * cos(theta) - 1) * sin(theta));
-
-                // \partial J^2 / \partial theta_i \partial theta_j
-                localMat[i][j][2][2] += weight * B * shapeGrad[i][0] * shapeGrad[j][0];
-                localMat[i][j][2][2] += weight * shapeFunction[i] * shapeFunction[j]
-                    * (+ A1 * (x_s*sin(theta) + y_s*cos(theta)) * (x_s*sin(theta) + y_s*cos(theta))
-                       + A1 * (x_s*cos(theta) - y_s*sin(theta)) * (-x_s*cos(theta)+ y_s*sin(theta))
-                       + A3 * (x_s*cos(theta) - y_s*sin(theta)) * (x_s*cos(theta) - y_s*sin(theta))
-                       - A3 * (x_s*sin(theta) + y_s*cos(theta) - 1) * (x_s*sin(theta) + y_s*cos(theta)));
-
-
-
-            }
-
-        }
-
-
-    }
-
-#if 0
-    static int eleme = 0;
-    printf("********* Element %d **********\n", eleme++);
-    for (int row=0; row<matSize; row++) {
-
-        for (int rcomp=0; rcomp<dim; rcomp++) {
-
-            for (int col=0; col<matSize; col++) {
-
-                for (int ccomp=0; ccomp<dim; ccomp++)
-                    std::cout << mat[row][col][rcomp][ccomp] << "  ";
-
-                std::cout << "    ";
-
-            }
-
-            std::cout << std::endl;
-
-        }
-
-        std::cout << std::endl;
-
-    }
-    exit(0);
-#endif
-
-}
-
-template <class GridView>
-void RodAssembler<GridView,2>::
-assembleGradient(const std::vector<RigidBodyMotion<double,2> >& sol,
-                 Dune::BlockVector<Dune::FieldVector<double, blocksize> >& grad) const
-{
-    if (sol.size()!=this->basis_.size())
-        DUNE_THROW(Dune::Exception, "Solution vector doesn't match the grid!");
-
-    grad.resize(sol.size());
-    grad = 0;
-
-    // Loop over all elements
-    for (const auto& element : Dune::elements(this->basis_gridView()))
-    {
-        // Extract local solution on this element
-        Dune::P1LocalFiniteElement<double,double,gridDim> localFiniteElement;
-        const int numOfBaseFct = localFiniteElement.localBasis().size();
-
-        RigidBodyMotion<double,2> localSolution[numOfBaseFct];
-
-        for (int i=0; i<numOfBaseFct; i++)
-            localSolution[i] = sol[this->basis_.index(element,i)];
-
-        // Get quadrature rule
-        const auto& quad = Dune::QuadratureRules<double, gridDim>::rule(element.type(), 2);
-
-        for (int pt=0; pt<quad.size(); pt++) {
-
-            // Local position of the quadrature point
-            const Dune::FieldVector<double,gridDim>& quadPos = quad[pt].position();
-
-            const Dune::FieldMatrix<double,1,1>& inv = element.geometry().jacobianInverseTransposed(quadPos);
-            const double integrationElement = element.geometry().integrationElement(quadPos);
-
-            double weight = quad[pt].weight() * integrationElement;
-
-            /**********************************************/
-            /* compute gradients of the shape functions   */
-            /**********************************************/
-            std::vector<Dune::FieldMatrix<double,1,gridDim> > referenceElementGradients(numOfBaseFct);
-            localFiniteElement.localBasis().evaluateJacobian(quadPos,referenceElementGradients);
-
-            std::vector<Dune::FieldVector<double,gridDim> > shapeGrad(numOfBaseFct);
-
-            // multiply with jacobian inverse
-            for (int dof=0; dof<numOfBaseFct; dof++)
-                inv.mv(referenceElementGradients[dof][0], shapeGrad[dof]);
-
-            // Get the values of the shape functions
-            std::vector<Dune::FieldVector<double,1> > shapeFunction;
-            localFiniteElement.localBasis().evaluateFunction(quadPos,shapeFunction);
-
-            // //////////////////////////////////
-            //   Interpolate
-            // //////////////////////////////////
-
-            double x_s     = localSolution[0].r[0]*shapeGrad[0][0] + localSolution[1].r[0]*shapeGrad[1][0];
-            double y_s     = localSolution[0].r[1]*shapeGrad[0][0] + localSolution[1].r[1]*shapeGrad[1][0];
-            double theta_s = localSolution[0].q.angle_*shapeGrad[0][0] + localSolution[1].q.angle_*shapeGrad[1][0];
-
-            double theta   = localSolution[0].q.angle_*shapeFunction[0] + localSolution[1].q.angle_*shapeFunction[1];
-
-            // /////////////////////////////////////////////
-            //   Sum it all up
-            // /////////////////////////////////////////////
-
-            double partA1 = A1 * (x_s * cos(theta) - y_s * sin(theta));
-            double partA3 = A3 * (x_s * sin(theta) + y_s * cos(theta) - 1);
-
-            for (int dof=0; dof<numOfBaseFct; dof++) {
-
-                int globalDof = this->basis_.index(element,dof);
-
-                //printf("globalDof: %d   partA1: %g   partA3: %g\n", globalDof, partA1, partA3);
-
-                // \partial J / \partial x^i
-                grad[globalDof][0] += weight * (partA1 * cos(theta) + partA3 * sin(theta)) * shapeGrad[dof][0];
-
-                // \partial J / \partial y^i
-                grad[globalDof][1] += weight * (-partA1 * sin(theta) + partA3 * cos(theta)) * shapeGrad[dof][0];
-
-                // \partial J / \partial \theta^i
-                grad[globalDof][2] += weight * (B * theta_s * shapeGrad[dof][0]
-                                               + partA1 * (-x_s * sin(theta) - y_s * cos(theta)) * shapeFunction[dof]
-                                               + partA3 * ( x_s * cos(theta) - y_s * sin(theta)) * shapeFunction[dof]);
-
-            }
-
-
-        }
-
-    }
-
-}
-
-
-template <class GridView>
-double RodAssembler<GridView,2>::
-computeEnergy(const std::vector<RigidBodyMotion<double,2> >& sol) const
-{
-    double energy = 0;
-
-    if (sol.size()!=this->basis_.size())
-        DUNE_THROW(Dune::Exception, "Solution vector doesn't match the grid!");
-
-    // Loop over all elements
-    for (const auto& element : Dune::elements(this->basis_gridView()))
-    {
-        // Extract local solution on this element
-        Dune::P1LocalFiniteElement<double,double,gridDim> localFiniteElement;
-
-        int numOfBaseFct = localFiniteElement.localBasis().size();
-
-        std::vector<RigidBodyMotion<double,2> > localSolution(numOfBaseFct);
-
-        for (int i=0; i<numOfBaseFct; i++)
-            localSolution[i] = sol[this->basis_.index(element,i)];
-
-        // Get quadrature rule
-        const auto& quad = Dune::QuadratureRules<double, gridDim>::rule(element.type(), 2);
-
-        for (int pt=0; pt<quad.size(); pt++) {
-
-            // Local position of the quadrature point
-            const Dune::FieldVector<double,gridDim>& quadPos = quad[pt].position();
-
-            const Dune::FieldMatrix<double,1,1>& inv = element.geometry().jacobianInverseTransposed(quadPos);
-            const double integrationElement = element.geometry().integrationElement(quadPos);
-
-            double weight = quad[pt].weight() * integrationElement;
-
-            /**********************************************/
-            /* compute gradients of the shape functions   */
-            /**********************************************/
-            std::vector<Dune::FieldMatrix<double,1,gridDim> > referenceElementGradients(numOfBaseFct);
-            localFiniteElement.localBasis().evaluateJacobian(quadPos,referenceElementGradients);
-
-            std::vector<Dune::FieldVector<double,gridDim> > shapeGrad(numOfBaseFct);
-
-            // multiply with jacobian inverse
-            for (int dof=0; dof<numOfBaseFct; dof++)
-                inv.mv(referenceElementGradients[dof][0], shapeGrad[dof]);
-
-            // Get the value of the shape functions
-            std::vector<Dune::FieldVector<double,1> > shapeFunction;
-            localFiniteElement.localBasis().evaluateFunction(quadPos,shapeFunction);
-
-            // //////////////////////////////////
-            //   Interpolate
-            // //////////////////////////////////
-
-            double x_s     = localSolution[0].r[0]*shapeGrad[0][0] + localSolution[1].r[0]*shapeGrad[1][0];
-            double y_s     = localSolution[0].r[1]*shapeGrad[0][0] + localSolution[1].r[1]*shapeGrad[1][0];
-            double theta_s = localSolution[0].q.angle_*shapeGrad[0][0] + localSolution[1].q.angle_*shapeGrad[1][0];
-
-            double theta   = localSolution[0].q.angle_*shapeFunction[0] + localSolution[1].q.angle_*shapeFunction[1];
-
-            // /////////////////////////////////////////////
-            //   Sum it all up
-            // /////////////////////////////////////////////
-
-            double partA1 = x_s * cos(theta) - y_s * sin(theta);
-            double partA3 = x_s * sin(theta) + y_s * cos(theta) - 1;
-
-
-            energy += 0.5 * weight * (B * theta_s * theta_s
-                                      + A1 * partA1 * partA1
-                                      + A3 * partA3 * partA3);
-
-        }
-
-    }
-
-    return energy;
-
-}
diff --git a/dune/gfe/rodassembler.hh b/dune/gfe/rodassembler.hh
deleted file mode 100644
index 64c1327ecae83ff146d6675be04243003a8158ae..0000000000000000000000000000000000000000
--- a/dune/gfe/rodassembler.hh
+++ /dev/null
@@ -1,160 +0,0 @@
-#ifndef DUNE_EXTENSIBLE_ROD_ASSEMBLER_HH
-#define DUNE_EXTENSIBLE_ROD_ASSEMBLER_HH
-
-#include <dune/istl/bcrsmatrix.hh>
-#include <dune/common/fmatrix.hh>
-#include <dune/istl/matrixindexset.hh>
-#include <dune/istl/matrix.hh>
-
-#include <dune/fufem/boundarypatch.hh>
-
-#include <dune/gfe/localgeodesicfefdstiffness.hh>
-#include "rigidbodymotion.hh"
-#include "rodlocalstiffness.hh"
-#include "geodesicfeassembler.hh"
-
-/** \brief The FEM operator for an extensible, shearable rod in 3d
- */
-template <class Basis, int spaceDim>
-class RodAssembler
-{
-    static_assert(spaceDim==2 || spaceDim==3,
-                       "You can only instantiate the class RodAssembler for 2d and 3d spaces");
-};
-
-/** \brief The FEM operator for an extensible, shearable rod in 3d
- */
-template <class Basis>
-class RodAssembler<Basis,3> : public GeodesicFEAssembler<Basis, RigidBodyMotion<double,3> >
-{
-  typedef typename Basis::GridView GridView;
-
-  //! Dimension of the grid.
-  enum { gridDim = GridView::dimension };
-  static_assert(gridDim==1, "RodAssembler can only be used with one-dimensional grids!");
-
-        enum { elementOrder = 1};
-
-        //! Each block is x, y, theta in 2d, T (R^3 \times SO(3)) in 3d
-        enum { blocksize = 6 };
-
-public:
-        //! ???
-    RodAssembler(const Basis& basis,
-                 LocalGeodesicFEStiffness<Basis, RigidBodyMotion<double,3> >& localStiffness)
-    : GeodesicFEAssembler<Basis, RigidBodyMotion<double,3> >(basis,localStiffness)
-        {
-            std::vector<RigidBodyMotion<double,3> > referenceConfiguration(basis.size());
-
-    for (const auto vertex : Dune::vertices(basis.gridView()))
-    {
-      auto idx = basis.gridView().indexSet().index(vertex);
-
-                referenceConfiguration[idx].r[0] = 0;
-                referenceConfiguration[idx].r[1] = 0;
-      referenceConfiguration[idx].r[2] = vertex.geometry().corner(0)[0];
-                referenceConfiguration[idx].q = Rotation<double,3>::identity();
-            }
-
-    rodEnergy()->setReferenceConfiguration(referenceConfiguration);
-        }
-
-    auto rodEnergy()
-    {
-      // TODO: Does not work for other stiffness implementations
-      auto localFDStiffness = std::dynamic_pointer_cast<LocalGeodesicFEFDStiffness<Basis, RigidBodyMotion<double,3> > >(this->localStiffness_);
-      return const_cast<RodLocalStiffness<GridView,double>*>(dynamic_cast<const RodLocalStiffness<GridView,double>*>(localFDStiffness->localEnergy_));
-    }
-
-        std::vector<RigidBodyMotion<double,3> > getRefConfig()
-    {
-      return rodEnergy()->referenceConfiguration_;
-        }
-
-  virtual void assembleGradient(const std::vector<RigidBodyMotion<double,3> >& sol,
-                                Dune::BlockVector<Dune::FieldVector<double, blocksize> >& grad) const override;
-
-        void getStrain(const std::vector<RigidBodyMotion<double,3> >& sol,
-                       Dune::BlockVector<Dune::FieldVector<double, blocksize> >& strain) const;
-
-        void getStress(const std::vector<RigidBodyMotion<double,3> >& sol,
-                       Dune::BlockVector<Dune::FieldVector<double, blocksize> >& stress) const;
-
-        /** \brief Return resultant force across boundary in canonical coordinates
-
-        \note Linear run-time in the size of the grid */
-        template <class PatchGridView>
-        Dune::FieldVector<double,6> getResultantForce(const BoundaryPatch<PatchGridView>& boundary,
-                                                      const std::vector<RigidBodyMotion<double,3> >& sol) const;
-    }; // end class
-
-
-/** \brief The FEM operator for a 2D extensible, shearable rod
- */
-template <class Basis>
-class RodAssembler<Basis,2> : public GeodesicFEAssembler<Basis, RigidBodyMotion<double,2> >
-{
-
-    typedef typename Basis::GridView GridView;
-    typedef typename GridView::template Codim<0>::Entity EntityType;
-
-  //! Dimension of the grid.
-  enum { gridDim = GridView::dimension };
-  static_assert(gridDim==1, "RodAssembler can only be used with one-dimensional grids!");
-
-    enum { elementOrder = 1};
-
-    //! Each block is x, y, theta
-    enum { blocksize = 3 };
-
-    //!
-    typedef Dune::FieldMatrix<double, blocksize, blocksize> MatrixBlock;
-
-    /** \brief Material constants */
-    double B;
-    double A1;
-    double A3;
-
-public:
-
-    //! ???
-    RodAssembler(const GridView &gridView)
-        : GeodesicFEAssembler<Basis, RigidBodyMotion<double,2> >(gridView,nullptr)
-    {
-        B = 1;
-        A1 = 1;
-        A3 = 1;
-    }
-
-    ~RodAssembler() {}
-
-    void setParameters(double b, double a1, double a3) {
-        B  = b;
-        A1 = a1;
-        A3 = a3;
-    }
-
-    /** \brief Assemble the tangent stiffness matrix and the right hand side
-     */
-    void assembleMatrix(const std::vector<RigidBodyMotion<double,2> >& sol,
-                        Dune::BCRSMatrix<MatrixBlock>& matrix);
-
-    virtual void assembleGradient(const std::vector<RigidBodyMotion<double,2> >& sol,
-                          Dune::BlockVector<Dune::FieldVector<double, blocksize> >& grad) const override;
-
-    /** \brief Compute the energy of a deformation state */
-    virtual double computeEnergy(const std::vector<RigidBodyMotion<double,2> >& sol) const override;
-
-protected:
-
-    /** \brief Compute the element tangent stiffness matrix  */
-    void getLocalMatrix( EntityType &entity,
-                         const std::vector<RigidBodyMotion<double,2> >& localSolution,
-                         Dune::Matrix<MatrixBlock>& mat) const;
-
-}; // end class
-
-#include "rodassembler.cc"
-
-#endif
-
diff --git a/dune/gfe/rodlocalstiffness.hh b/dune/gfe/rodlocalstiffness.hh
deleted file mode 100644
index 5157a30e3f7a4e4d67f292c938a13ccc505b8f2d..0000000000000000000000000000000000000000
--- a/dune/gfe/rodlocalstiffness.hh
+++ /dev/null
@@ -1,720 +0,0 @@
-#ifndef ROD_LOCAL_STIFFNESS_HH
-#define ROD_LOCAL_STIFFNESS_HH
-
-#include <array>
-
-#include <dune/common/fmatrix.hh>
-#include <dune/istl/matrix.hh>
-#include <dune/geometry/quadraturerules.hh>
-
-#include <dune/functions/functionspacebases/lagrangebasis.hh>
-
-#include <dune/gfe/localfirstordermodel.hh>
-#include "rigidbodymotion.hh"
-
-template<class GridView, class RT>
-class RodLocalStiffness
-: public Dune::GFE::LocalFirstOrderModel<Dune::Functions::LagrangeBasis<GridView,1>, RigidBodyMotion<RT,3> >
-{
-    typedef RigidBodyMotion<RT,3> TargetSpace;
-    typedef Dune::Functions::LagrangeBasis<GridView,1> Basis;
-
-    // grid types
-    typedef typename GridView::Grid::ctype DT;
-    typedef typename GridView::template Codim<0>::Entity Entity;
-
-    // some other sizes
-    enum {dim=GridView::dimension};
-
-    // Quadrature order used for the extension and shear energy
-    enum {shearQuadOrder = 2};
-
-    // Quadrature order used for the bending and torsion energy
-    enum {bendingQuadOrder = 2};
-
-public:
-
-    /** \brief The stress-free configuration */
-    std::vector<RigidBodyMotion<RT,3> > referenceConfiguration_;
-
-public:
-
-    //! Each block is x, y, theta in 2d, T (R^3 \times SO(3)) in 3d
-    enum { blocksize = 6 };
-
-    // define the number of components of your system, this is used outside
-    // to allocate the correct size of (dense) blocks with a FieldMatrix
-    enum {m=blocksize};
-
-    // types for matrics, vectors and boundary conditions
-    typedef Dune::FieldMatrix<RT,m,m> MBlockType; // one entry in the stiffness matrix
-    typedef Dune::FieldVector<RT,m> VBlockType;   // one entry in the global vectors
-
-    // /////////////////////////////////
-    //   The material parameters
-    // /////////////////////////////////
-
-    /** \brief Material constants */
-    std::array<double,3> K_;
-    std::array<double,3> A_;
-
-    GridView gridView_;
-
-    //! Constructor
-    RodLocalStiffness (const GridView& gridView,
-                       const std::array<double,3>& K, const std::array<double,3>& A)
-        : K_(K),
-          A_(A),
-          gridView_(gridView)
-    {}
-
-    /** \brief Constructor setting shape constants and material parameters
-        \param A The rod section area
-        \param J1, J2 The geometric moments (Flächenträgheitsmomente)
-        \param E Young's modulus
-        \param nu Poisson number
-    */
-    RodLocalStiffness (const GridView& gridView,
-                       double A, double J1, double J2, double E, double nu)
-        : gridView_(gridView)
-    {
-        // shear modulus
-        double G = E/(2+2*nu);
-
-        K_[0] = E * J1;
-        K_[1] = E * J2;
-        K_[2] = G * (J1 + J2);
-
-        A_[0] = G * A;
-        A_[1] = G * A;
-        A_[2] = E * A;
-    }
-
-
-
-    void setReferenceConfiguration(const std::vector<RigidBodyMotion<RT,3> >& referenceConfiguration) {
-        referenceConfiguration_ = referenceConfiguration;
-    }
-
-    /** \brief Compute local element energy */
-    virtual RT energy (const typename Basis::LocalView& localView,
-                       const std::vector<RigidBodyMotion<RT,3> >& localSolution) const override;
-
-    /** \brief Assemble the element gradient of the energy functional */
-    void assembleGradient(const typename Basis::LocalView& localView,
-                          const std::vector<RigidBodyMotion<RT,3> >& solution,
-                          std::vector<Dune::FieldVector<double,6> >& gradient) const override;
-
-    Dune::FieldVector<double, 6> getStrain(const std::vector<RigidBodyMotion<RT,3> >& localSolution,
-                                           const Entity& element,
-                                           const Dune::FieldVector<double,1>& pos) const;
-
-    Dune::FieldVector<RT, 6> getStress(const std::vector<RigidBodyMotion<RT,3> >& localSolution,
-                                           const Entity& element,
-                                           const Dune::FieldVector<double,1>& pos) const;
-
-protected:
-
-    void getLocalReferenceConfiguration(const Entity& element,
-                                        std::vector<RigidBodyMotion<RT,3> >& localReferenceConfiguration) const {
-
-        unsigned int numOfBaseFct = element.subEntities(dim);
-        localReferenceConfiguration.resize(numOfBaseFct);
-
-        for (size_t i=0; i<numOfBaseFct; i++)
-            localReferenceConfiguration[i] = referenceConfiguration_[gridView_.indexSet().subIndex(element,i,dim)];
-    }
-
-public:
-    static void interpolationDerivative(const Rotation<RT,3>& q0, const Rotation<RT,3>& q1, double s,
-                                        std::array<Quaternion<double>,6>& grad);
-
-    static void interpolationVelocityDerivative(const Rotation<RT,3>& q0, const Rotation<RT,3>& q1, double s,
-                                                double intervalLength, std::array<Quaternion<double>,6>& grad);
-
-protected:
-    template <class T>
-    static Dune::FieldVector<T,3> darboux(const Rotation<T,3>& q, const Dune::FieldVector<T,4>& q_s)
-    {
-        Dune::FieldVector<double,3> u;  // The Darboux vector
-
-        u[0] = 2 * (q.B(0) * q_s);
-        u[1] = 2 * (q.B(1) * q_s);
-        u[2] = 2 * (q.B(2) * q_s);
-
-        return u;
-    }
-
-};
-
-template <class GridType, class RT>
-RT RodLocalStiffness<GridType, RT>::
-energy(const typename Basis::LocalView& localView,
-       const std::vector<RigidBodyMotion<RT,3> >& localSolution) const
-{
-    assert(localSolution.size()==2);
-    const auto& element = localView.element();
-
-    RT energy = 0;
-
-    std::vector<RigidBodyMotion<RT,3> > localReferenceConfiguration;
-    getLocalReferenceConfiguration(element, localReferenceConfiguration);
-
-    // ///////////////////////////////////////////////////////////////////////////////
-    //   The following two loops are a reduced integration scheme.  We integrate
-    //   the transverse shear and extensional energy with a first-order quadrature
-    //   formula, even though it should be second order.  This prevents shear-locking.
-    // ///////////////////////////////////////////////////////////////////////////////
-
-    const Dune::QuadratureRule<double, 1>& shearingQuad
-        = Dune::QuadratureRules<double, 1>::rule(element.type(), shearQuadOrder);
-
-    // hack: convert from std::array to std::vector
-    std::vector<RigidBodyMotion<RT,3> > localSolutionVector(localSolution.begin(), localSolution.end());
-
-    for (size_t pt=0; pt<shearingQuad.size(); pt++) {
-
-        // Local position of the quadrature point
-        const Dune::FieldVector<double,1>& quadPos = shearingQuad[pt].position();
-
-        const double integrationElement = element.geometry().integrationElement(quadPos);
-
-        double weight = shearingQuad[pt].weight() * integrationElement;
-
-        Dune::FieldVector<double,6> strain = getStrain(localSolutionVector, element, quadPos);
-
-        // The reference strain
-        Dune::FieldVector<double,6> referenceStrain = getStrain(localReferenceConfiguration, element, quadPos);
-
-        for (int i=0; i<3; i++)
-            energy += weight * 0.5 * A_[i] * (strain[i] - referenceStrain[i]) * (strain[i] - referenceStrain[i]);
-
-    }
-
-    // Get quadrature rule
-    const Dune::QuadratureRule<double, 1>& bendingQuad
-        = Dune::QuadratureRules<double, 1>::rule(element.type(), bendingQuadOrder);
-
-    for (size_t pt=0; pt<bendingQuad.size(); pt++) {
-
-        // Local position of the quadrature point
-        const Dune::FieldVector<double,1>& quadPos = bendingQuad[pt].position();
-
-        double weight = bendingQuad[pt].weight() * element.geometry().integrationElement(quadPos);
-
-        Dune::FieldVector<double,6> strain = getStrain(localSolutionVector, element, quadPos);
-
-        // The reference strain
-        Dune::FieldVector<double,6> referenceStrain = getStrain(localReferenceConfiguration, element, quadPos);
-
-        // Part II: the bending and twisting energy
-        for (int i=0; i<3; i++)
-            energy += weight * 0.5 * K_[i] * (strain[i+3] - referenceStrain[i+3]) * (strain[i+3] - referenceStrain[i+3]);
-
-    }
-
-    return energy;
-}
-
-
-template <class GridType, class RT>
-void RodLocalStiffness<GridType, RT>::
-interpolationDerivative(const Rotation<RT,3>& q0, const Rotation<RT,3>& q1, double s,
-                        std::array<Quaternion<double>,6>& grad)
-{
-    // Clear output array
-    for (int i=0; i<6; i++)
-        grad[i] = 0;
-
-    // The derivatives with respect to w^0
-
-    // Compute q_1^{-1}q_0
-    Rotation<RT,3> q1InvQ0 = q1;
-    q1InvQ0.invert();
-    q1InvQ0 = q1InvQ0.mult(q0);
-
-    {
-    // Compute v = (1-s) \exp^{-1} ( q_1^{-1} q_0)
-        Dune::FieldVector<RT,3> v = Rotation<RT,3>::expInv(q1InvQ0);
-    v *= (1-s);
-
-    Dune::FieldMatrix<RT,4,3> dExp_v = Rotation<RT,3>::Dexp(SkewMatrix<RT,3>(v));
-
-    Dune::FieldMatrix<RT,3,4> dExpInv = Rotation<RT,3>::DexpInv(q1InvQ0);
-
-    Dune::FieldMatrix<RT,4,4> mat(0);
-    for (int i=0; i<4; i++)
-        for (int j=0; j<4; j++)
-            for (int k=0; k<3; k++)
-                mat[i][j] += (1-s) * dExp_v[i][k] * dExpInv[k][j];
-
-    for (int i=0; i<3; i++) {
-
-        Quaternion<RT> dw;
-        for (int j=0; j<4; j++)
-            dw[j] = 0.5 * (i==j);  // dExp[j][i] at v=0
-
-        dw = q1InvQ0.Quaternion<double>::mult(dw);
-
-        mat.umv(dw,grad[i]);
-        grad[i] = q1.Quaternion<double>::mult(grad[i]);
-
-    }
-    }
-
-
-    // The derivatives with respect to w^1
-
-    // Compute q_0^{-1}
-    Rotation<RT,3> q0InvQ1 = q0;
-    q0InvQ1.invert();
-    q0InvQ1 = q0InvQ1.mult(q1);
-
-    {
-    // Compute v = s \exp^{-1} ( q_0^{-1} q_1)
-        Dune::FieldVector<RT,3> v = Rotation<RT,3>::expInv(q0InvQ1);
-    v *= s;
-
-    Dune::FieldMatrix<RT,4,3> dExp_v = Rotation<RT,3>::Dexp(SkewMatrix<RT,3>(v));
-
-    Dune::FieldMatrix<RT,3,4> dExpInv = Rotation<RT,3>::DexpInv(q0InvQ1);
-
-    Dune::FieldMatrix<RT,4,4> mat(0);
-    for (int i=0; i<4; i++)
-        for (int j=0; j<4; j++)
-            for (int k=0; k<3; k++)
-                mat[i][j] += s * dExp_v[i][k] * dExpInv[k][j];
-
-    for (int i=3; i<6; i++) {
-
-        Quaternion<RT> dw;
-        for (int j=0; j<4; j++)
-            dw[j] = 0.5 * ((i-3)==j);  // dExp[j][i-3] at v=0
-
-        dw = q0InvQ1.Quaternion<double>::mult(dw);
-
-        mat.umv(dw,grad[i]);
-        grad[i] = q0.Quaternion<double>::mult(grad[i]);
-
-    }
-    }
-}
-
-
-
-template <class GridType, class RT>
-void RodLocalStiffness<GridType, RT>::
-interpolationVelocityDerivative(const Rotation<RT,3>& q0, const Rotation<RT,3>& q1, double s,
-                                double intervalLength, std::array<Quaternion<double>,6>& grad)
-{
-    // Clear output array
-    for (int i=0; i<6; i++)
-        grad[i] = 0;
-
-    // Compute q_0^{-1}
-    Rotation<RT,3> q0Inv = q0;
-    q0Inv.invert();
-
-
-    // Compute v = s \exp^{-1} ( q_0^{-1} q_1)
-    Dune::FieldVector<RT,3> v = Rotation<RT,3>::expInv(q0Inv.mult(q1));
-    v *= s/intervalLength;
-
-    Dune::FieldMatrix<RT,4,3> dExp_v = Rotation<RT,3>::Dexp(SkewMatrix<RT,3>(v));
-
-    std::array<Dune::FieldMatrix<RT,3,3>, 4> ddExp;
-    Rotation<RT,3>::DDexp(v, ddExp);
-
-    Dune::FieldMatrix<RT,3,4> dExpInv = Rotation<RT,3>::DexpInv(q0Inv.mult(q1));
-
-    Dune::FieldMatrix<RT,4,4> mat(0);
-    for (int i=0; i<4; i++)
-        for (int j=0; j<4; j++)
-            for (int k=0; k<3; k++)
-                mat[i][j] += 1/intervalLength * dExp_v[i][k] * dExpInv[k][j];
-
-
-    // /////////////////////////////////////////////////
-    // The derivatives with respect to w^0
-    // /////////////////////////////////////////////////
-    for (int i=0; i<3; i++) {
-
-        // \partial exp \partial w^1_j at 0
-        Quaternion<RT> dw;
-        for (int j=0; j<4; j++)
-            dw[j] = 0.5*(i==j);  // dExp_v_0[j][i];
-
-        // \xi = \exp^{-1} q_0^{-1} q_1
-        Dune::FieldVector<RT,3> xi = Rotation<RT,3>::expInv(q0Inv.mult(q1));
-
-        Quaternion<RT> addend0;
-        addend0 = 0;
-        dExp_v.umv(xi,addend0);
-        addend0 = dw.mult(addend0);
-        addend0 /= intervalLength;
-
-        //  \parder{\xi}{w^1_j} = ...
-        Quaternion<RT> dwConj = dw;
-        dwConj.conjugate();
-        //dwConj[3] -= 2 * dExp_v_0[3][i];   the last row of dExp_v_0 is zero
-        dwConj = dwConj.mult(q0Inv.mult(q1));
-
-        Dune::FieldVector<RT,3> dxi(0);
-        Rotation<RT,3>::DexpInv(q0Inv.mult(q1)).umv(dwConj, dxi);
-
-        Quaternion<RT> vHv;
-        for (int j=0; j<4; j++) {
-            vHv[j] = 0;
-            // vHv[j] = dxi * DDexp * xi
-            for (int k=0; k<3; k++)
-                for (int l=0; l<3; l++)
-                    vHv[j] += ddExp[j][k][l]*dxi[k]*xi[l];
-        }
-
-        vHv *= s/intervalLength/intervalLength;
-
-        // Third addend
-        mat.umv(dwConj,grad[i]);
-
-        // add up
-        grad[i] += addend0;
-        grad[i] += vHv;
-
-        grad[i] = q0.Quaternion<double>::mult(grad[i]);
-    }
-
-
-    // /////////////////////////////////////////////////
-    // The derivatives with respect to w^1
-    // /////////////////////////////////////////////////
-    for (int i=3; i<6; i++) {
-
-        // \partial exp \partial w^1_j at 0
-        Quaternion<RT> dw;
-        for (int j=0; j<4; j++)
-            dw[j] = 0.5 * ((i-3)==j);  // dw[j] = dExp_v_0[j][i-3];
-
-        // \xi = \exp^{-1} q_0^{-1} q_1
-        Dune::FieldVector<RT,3> xi = Rotation<RT,3>::expInv(q0Inv.mult(q1));
-
-        //  \parder{\xi}{w^1_j} = ...
-        Dune::FieldVector<RT,3> dxi(0);
-        dExpInv.umv(q0Inv.Quaternion<double>::mult(q1.Quaternion<double>::mult(dw)), dxi);
-
-        Quaternion<RT> vHv;
-        for (int j=0; j<4; j++) {
-            // vHv[j] = dxi * DDexp * xi
-            vHv[j] = 0;
-            for (int k=0; k<3; k++)
-                for (int l=0; l<3; l++)
-                    vHv[j] += ddExp[j][k][l]*dxi[k]*xi[l];
-        }
-
-        vHv *= s/intervalLength/intervalLength;
-
-        // ///////////////////////////////////
-        //   second addend
-        // ///////////////////////////////////
-
-
-        dw = q0Inv.Quaternion<double>::mult(q1.Quaternion<double>::mult(dw));
-
-        mat.umv(dw,grad[i]);
-        grad[i] += vHv;
-
-        grad[i] = q0.Quaternion<double>::mult(grad[i]);
-
-    }
-
-}
-
-template <class GridType, class RT>
-Dune::FieldVector<double, 6> RodLocalStiffness<GridType, RT>::
-getStrain(const std::vector<RigidBodyMotion<RT,3> >& localSolution,
-          const Entity& element,
-          const Dune::FieldVector<double,1>& pos) const
-{
-    if (!element.isLeaf())
-        DUNE_THROW(Dune::NotImplemented, "Only for leaf elements");
-
-    assert(localSolution.size() == 2);
-
-    // Strain defined on each element
-    Dune::FieldVector<double, 6> strain(0);
-
-    // Extract local solution on this element
-    Dune::P1LocalFiniteElement<double,double,1> localFiniteElement;
-    int numOfBaseFct = localFiniteElement.localCoefficients().size();
-
-    const Dune::FieldMatrix<double,1,1>& inv = element.geometry().jacobianInverseTransposed(pos);
-
-    // ///////////////////////////////////////
-    //   Compute deformation gradient
-    // ///////////////////////////////////////
-    std::vector<Dune::FieldMatrix<double,1,1> > shapeGrad;
-
-    localFiniteElement.localBasis().evaluateJacobian(pos, shapeGrad);
-
-    for (int dof=0; dof<numOfBaseFct; dof++) {
-
-        // multiply with jacobian inverse
-        Dune::FieldVector<double,1> tmp(0);
-        inv.umv(shapeGrad[dof][0], tmp);
-        shapeGrad[dof][0] = tmp;
-
-    }
-
-    // //////////////////////////////////
-    //   Interpolate
-    // //////////////////////////////////
-
-    Dune::FieldVector<double,3> r_s;
-    for (int i=0; i<3; i++)
-        r_s[i] = localSolution[0].r[i]*shapeGrad[0][0] + localSolution[1].r[i]*shapeGrad[1][0];
-
-    // Interpolate the rotation at the quadrature point
-    Rotation<RT,3> q = Rotation<RT,3>::interpolate(localSolution[0].q, localSolution[1].q, pos);
-
-    // Get the derivative of the rotation at the quadrature point by interpolating in $H$
-    Quaternion<double> q_s = Rotation<RT,3>::interpolateDerivative(localSolution[0].q, localSolution[1].q,
-                                                                       pos);
-    // Transformation from the reference element
-    q_s *= inv[0][0];
-
-    // /////////////////////////////////////////////
-    //   Sum it all up
-    // /////////////////////////////////////////////
-
-    // Part I: the shearing and stretching strain
-    strain[0] = r_s * q.director(0);    // shear strain
-    strain[1] = r_s * q.director(1);    // shear strain
-    strain[2] = r_s * q.director(2);    // stretching strain
-
-    // Part II: the Darboux vector
-
-    Dune::FieldVector<double,3> u = darboux(q, q_s);
-
-    strain[3] = u[0];
-    strain[4] = u[1];
-    strain[5] = u[2];
-
-    return strain;
-}
-template <class GridType, class RT>
-Dune::FieldVector<RT, 6> RodLocalStiffness<GridType, RT>::
-getStress(const std::vector<RigidBodyMotion<RT,3> >& localSolution,
-              const Entity& element,
-                        const Dune::FieldVector<double, 1>& pos) const
-{
-    const auto& indexSet = gridView_.indexSet();
-    std::vector<TargetSpace> localRefConf = {referenceConfiguration_[indexSet.subIndex(element, 0, 1)],
-                                             referenceConfiguration_[indexSet.subIndex(element, 1, 1)]};
-
-    auto&& strain = getStrain(localSolution, element, pos);
-    auto&& referenceStrain = getStrain(localRefConf, element, pos);
-
-    Dune::FieldVector<RT, 6> stress;
-    for (int i=0; i < dim; i++)
-        stress[i] = (strain[i] - referenceStrain[i]) * A_[i];
-
-    for (int i=0; i < dim; i++)
-        stress[i+3] = (strain[i+3] - referenceStrain[i+3]) * K_[i];
-    return stress;
-}
-
-
-template <class GridType, class RT>
-void RodLocalStiffness<GridType, RT>::
-assembleGradient(const typename Basis::LocalView& localView,
-                 const std::vector<RigidBodyMotion<RT,3> >& solution,
-                 std::vector<Dune::FieldVector<double,6> >& gradient) const
-{
-    using namespace Dune;
-    const auto& element = localView.element();
-
-    std::vector<RigidBodyMotion<RT,3> > localReferenceConfiguration;
-    getLocalReferenceConfiguration(element, localReferenceConfiguration);
-
-    // Extract local solution on this element
-    Dune::P1LocalFiniteElement<double,double,1> localFiniteElement;
-    int numOfBaseFct = localFiniteElement.localCoefficients().size();
-
-    // init
-    gradient.resize(numOfBaseFct);
-    for (size_t i=0; i<gradient.size(); i++)
-        gradient[i] = 0;
-
-    double intervalLength = element.geometry().corner(1)[0] - element.geometry().corner(0)[0];
-
-    // ///////////////////////////////////////////////////////////////////////////////////
-    //   Reduced integration to avoid locking:  assembly is split into a shear part
-    //   and a bending part.  Different quadrature rules are used for the two parts.
-    //   This avoids locking.
-    // ///////////////////////////////////////////////////////////////////////////////////
-
-    // Get quadrature rule
-    const QuadratureRule<double, 1>& shearingQuad = QuadratureRules<double, 1>::rule(element.type(), shearQuadOrder);
-
-    for (size_t pt=0; pt<shearingQuad.size(); pt++) {
-
-        // Local position of the quadrature point
-        const FieldVector<double,1>& quadPos = shearingQuad[pt].position();
-
-        const FieldMatrix<double,1,1>& inv = element.geometry().jacobianInverseTransposed(quadPos);
-        const double integrationElement = element.geometry().integrationElement(quadPos);
-
-        double weight = shearingQuad[pt].weight() * integrationElement;
-
-        // ///////////////////////////////////////
-        //   Compute deformation gradient
-        // ///////////////////////////////////////
-        std::vector<Dune::FieldMatrix<double,1,1> > shapeGrad;
-        localFiniteElement.localBasis().evaluateJacobian(quadPos, shapeGrad);
-
-        for (int dof=0; dof<numOfBaseFct; dof++) {
-
-            // multiply with jacobian inverse
-            FieldVector<double,1> tmp(0);
-            inv.umv(shapeGrad[dof][0], tmp);
-            shapeGrad[dof][0] = tmp;
-
-        }
-
-        // //////////////////////////////////
-        //   Interpolate
-        // //////////////////////////////////
-
-        FieldVector<double,3> r_s;
-        for (int i=0; i<3; i++)
-            r_s[i] = solution[0].r[i]*shapeGrad[0] + solution[1].r[i]*shapeGrad[1];
-
-        // Interpolate current rotation at this quadrature point
-        Rotation<RT,3> q = Rotation<RT,3>::interpolate(solution[0].q, solution[1].q,quadPos[0]);
-
-        // The current strain
-        FieldVector<double,blocksize> strain = getStrain(solution, element, quadPos);
-
-        // The reference strain
-        FieldVector<double,blocksize> referenceStrain = getStrain(localReferenceConfiguration, element, quadPos);
-
-
-        // dd_dvij[m][i][j] = \parder {(d_k)_i} {q}
-        Tensor3<double,3 ,3, 4> dd_dq;
-        q.getFirstDerivativesOfDirectors(dd_dq);
-
-        // First derivatives of the position
-        std::array<Quaternion<double>,6> dq_dwij;
-        interpolationDerivative(solution[0].q, solution[1].q, quadPos, dq_dwij);
-
-        // /////////////////////////////////////////////
-        //   Sum it all up
-        // /////////////////////////////////////////////
-
-        for (int i=0; i<numOfBaseFct; i++) {
-
-            // /////////////////////////////////////////////
-            //   The translational part
-            // /////////////////////////////////////////////
-
-            // \partial \bar{W} / \partial r^i_j
-            for (int j=0; j<3; j++) {
-
-                for (int m=0; m<3; m++)
-                    gradient[i][j] += weight
-                        * (  A_[m] * (strain[m] - referenceStrain[m]) * shapeGrad[i] * q.director(m)[j]);
-
-            }
-
-            // \partial \bar{W}_v / \partial v^i_j
-            for (int j=0; j<3; j++) {
-
-                for (int m=0; m<3; m++) {
-                    FieldVector<double,3> tmp(0);
-                    dd_dq[m].umv(dq_dwij[3*i+j], tmp);
-                    gradient[i][3+j] += weight
-                        * A_[m] * (strain[m] - referenceStrain[m]) * (r_s*tmp);
-                }
-            }
-
-        }
-
-    }
-
-    // /////////////////////////////////////////////////////
-    //   Now: the bending/torsion part
-    // /////////////////////////////////////////////////////
-
-    // Get quadrature rule
-    const QuadratureRule<double, 1>& bendingQuad = QuadratureRules<double, 1>::rule(element.type(), bendingQuadOrder);
-
-    for (std::size_t pt=0; pt<bendingQuad.size(); pt++) {
-
-        // Local position of the quadrature point
-        const FieldVector<double,1>& quadPos = bendingQuad[pt].position();
-
-        const FieldMatrix<double,1,1>& inv = element.geometry().jacobianInverseTransposed(quadPos);
-        const double integrationElement = element.geometry().integrationElement(quadPos);
-
-        double weight = bendingQuad[pt].weight() * integrationElement;
-
-        // Interpolate current rotation at this quadrature point
-        Rotation<RT,3> q = Rotation<RT,3>::interpolate(solution[0].q, solution[1].q,quadPos[0]);
-
-        // Get the derivative of the rotation at the quadrature point by interpolating in $H$
-        Quaternion<double> q_s = Rotation<RT,3>::interpolateDerivative(solution[0].q, solution[1].q,
-                                                                           quadPos);
-        // Transformation from the reference element
-        q_s *= inv[0][0];
-
-
-        // The current strain
-        FieldVector<double,blocksize> strain = getStrain(solution, element, quadPos);
-
-        // The reference strain
-        FieldVector<double,blocksize> referenceStrain = getStrain(localReferenceConfiguration, element, quadPos);
-
-        // First derivatives of the position
-        std::array<Quaternion<double>,6> dq_dwij;
-        interpolationDerivative(solution[0].q, solution[1].q, quadPos, dq_dwij);
-
-        std::array<Quaternion<double>,6> dq_ds_dwij;
-        interpolationVelocityDerivative(solution[0].q, solution[1].q, quadPos[0]*intervalLength, intervalLength,
-                                        dq_ds_dwij);
-
-        // /////////////////////////////////////////////
-        //   Sum it all up
-        // /////////////////////////////////////////////
-
-        for (int i=0; i<numOfBaseFct; i++) {
-
-            // /////////////////////////////////////////////
-            //   The rotational part
-            // /////////////////////////////////////////////
-
-            // \partial \bar{W}_v / \partial v^i_j
-            for (int j=0; j<3; j++) {
-
-                for (int m=0; m<3; m++) {
-
-                    // Compute derivative of the strain
-                    /** \todo Is this formula correct?  It seems strange to call
-                        B(m) for a _derivative_ of a rotation */
-                    double du_dvij_m = 2 * (dq_dwij[i*3+j].B(m) * q_s)
-                        + 2* ( q.B(m) * dq_ds_dwij[i*3+j]);
-
-                    // Sum it up
-                    gradient[i][3+j] += weight * K_[m]
-                        * (strain[m+3]-referenceStrain[m+3]) * du_dvij_m;
-
-                }
-
-            }
-
-        }
-
-    }
-}
-
-
-#endif
-
diff --git a/dune/gfe/rotation.hh b/dune/gfe/rotation.hh
index 2ca609ed8c98312c084c5a0345824db4b9323134..96ea13db09cfbd34112410fdb530091c8ede82f0 100644
--- a/dune/gfe/rotation.hh
+++ b/dune/gfe/rotation.hh
@@ -145,7 +145,8 @@ class Rotation<T,3> : public Quaternion<T>
 
     /** \brief Computes sin(x/2) / x without getting unstable for small x */
     static T sincHalf(const T& x) {
-        return (x < 1e-4) ? 0.5 - (x*x/48)  + (x*x*x*x)/3840 : std::sin(x/2)/x;
+        using std::sin;
+        return (x < 1e-4) ? 0.5 - (x*x/48)  + (x*x*x*x)/3840 : sin(x/2)/x;
     }
 
     /** \brief Computes sin(sqrt(x)/2) / sqrt(x) without getting unstable for small x
@@ -154,7 +155,9 @@ class Rotation<T,3> : public Quaternion<T>
      * which ADOL-C doesn't like.
      */
     static T sincHalfOfSquare(const T& x) {
-        return (x < 1e-15) ? 0.5 - (x/48)  + (x*x)/(120*32) : std::sin(std::sqrt(x)/2)/std::sqrt(x);
+        using std::sin;
+        using std::sqrt;
+        return (x < 1e-15) ? 0.5 - (x/48)  + (x*x)/(120*32) : sin(sqrt(x)/2)/sqrt(x);
     }
 
     /** \brief Computes sin(sqrt(x)) / sqrt(x) without getting unstable for small x
@@ -163,7 +166,9 @@ class Rotation<T,3> : public Quaternion<T>
      * which ADOL-C doesn't like.
      */
     static T sincOfSquare(const T& x) {
-        return (x < 1e-15) ? 1 - (x/6)  + (x*x)/120 : std::sin(std::sqrt(x))/std::sqrt(x);
+        using std::sin;
+        using std::sqrt;
+        return (x < 1e-15) ? 1 - (x/6)  + (x*x)/120 : sin(sqrt(x))/sqrt(x);
     }
 
 public:
@@ -262,6 +267,9 @@ public:
     /** \brief The exponential map from \f$ \mathfrak{so}(3) \f$ to \f$ SO(3) \f$
      */
     static Rotation<T,3> exp(const SkewMatrix<T,3>& v) {
+        using std::cos;
+        using std::sqrt;
+
         Rotation<T,3> q;
 
         Dune::FieldVector<T,3> vAxial = v.axial();
@@ -282,7 +290,7 @@ public:
         // 1 - x*x/8 + x*x*x*x/384 - ...
         q[3] = (normV2 < 1e-4)
           ? 1 - normV2/8 + normV2*normV2 / 384
-          : std::cos(std::sqrt(normV2)/2);
+          : cos(sqrt(normV2)/2);
 
         return q;
     }
@@ -302,7 +310,10 @@ public:
      */
     static Rotation<T,3> exp(const Rotation<T,3>& p, const Dune::FieldVector<T,4>& v) {
 
-        assert( std::abs(p*v) < 1e-8 );
+        using std::abs;
+        using std::cos;
+        using std::sqrt;
+        assert( abs(p*v) < 1e-8 );
 
         const T norm2 = v.two_norm2();
 
@@ -310,10 +321,10 @@ public:
 
         // The series expansion of cos(x) at x=0 is
         // 1 - x*x/2 + x*x*x*x/24 - ...
-        T cos = (norm2 < 1e-4)
+        T cosValue = (norm2 < 1e-4)
           ? 1 - norm2/2 + norm2*norm2 / 24
-          : std::cos(std::sqrt(norm2));
-        result *= cos;
+          : cos(sqrt(norm2));
+        result *= cosValue;
 
         result.axpy(sincOfSquare(norm2), v);
         return result;
@@ -385,6 +396,8 @@ public:
 
     static Dune::FieldMatrix<T,4,3> Dexp(const SkewMatrix<T,3>& v) {
 
+        using std::cos;
+
         Dune::FieldMatrix<T,4,3> result(0);
         Dune::FieldVector<T,3> vAxial = v.axial();
         T norm = vAxial.two_norm();
@@ -395,8 +408,8 @@ public:
 
                 result[m][i] = (norm<1e-10)
                     /** \todo Isn't there a better way to implement this stably? */
-                    ? 0.5 * (i==m)
-                    : 0.5 * std::cos(norm/2) * vAxial[i] * vAxial[m] / (norm*norm) + sincHalf(norm) * ( (i==m) - vAxial[i]*vAxial[m]/(norm*norm));
+                    ? T(0.5) * (i==m)
+                    : 0.5 * cos(norm/2) * vAxial[i] * vAxial[m] / (norm*norm) + sincHalf(norm) * ( (i==m) - vAxial[i]*vAxial[m]/(norm*norm));
 
             }
 
@@ -409,6 +422,9 @@ public:
     static void DDexp(const Dune::FieldVector<T,3>& v,
                       std::array<Dune::FieldMatrix<T,3,3>, 4>& result) {
 
+        using std::cos;
+        using std::sin;
+
         T norm = v.two_norm();
         if (norm<=1e-10) {
 
@@ -427,15 +443,15 @@ public:
 
                     for (int m=0; m<3; m++) {
 
-                        result[m][i][j] = -0.25*std::sin(norm/2)*v[i]*v[j]*v[m]/(norm*norm*norm)
+                        result[m][i][j] = -0.25*sin(norm/2)*v[i]*v[j]*v[m]/(norm*norm*norm)
                             + ((i==j)*v[m] + (j==m)*v[i] + (i==m)*v[j] - 3*v[i]*v[j]*v[m]/(norm*norm))
-                            * (0.5*std::cos(norm/2) - sincHalf(norm)) / (norm*norm);
+                            * (0.5*cos(norm/2) - sincHalf(norm)) / (norm*norm);
 
 
                     }
 
                     result[3][i][j] = -0.5/(norm*norm)
-                        * ( 0.5*std::cos(norm/2)*v[i]*v[j] + std::sin(norm/2) * ((i==j)*norm - v[i]*v[j]/norm));
+                        * ( 0.5*cos(norm/2)*v[i]*v[j] + sin(norm/2) * ((i==j)*norm - v[i]*v[j]/norm));
 
                 }
 
@@ -457,7 +473,8 @@ public:
 
         } else {
 
-            T invSinc = 1/sincHalf(2*std::acos(q[3]));
+            using std::acos;
+            T invSinc = 1/sincHalf(2*acos(q[3]));
 
             v[0] = q[0] * invSinc;
             v[1] = q[1] * invSinc;
@@ -575,7 +592,9 @@ public:
         T sp = a.globalCoordinates() * b.globalCoordinates();
 
         // Scalar product may be larger than 1.0, due to numerical dirt
-        T dist = 2*std::acos( std::min(sp,T(1.0)) );
+        using std::acos;
+        using std::min;
+        T dist = 2*acos( min(sp,T(1.0)) );
 
         // Make sure we do the right thing if a and b are not in the same sheet
         // of the double covering of the unit quaternions over SO(3)
@@ -601,7 +620,11 @@ public:
 
         } else {
 
-            T dist = 2*std::acos( diff[3] );
+            // TODO: ADOL-C does not like this part of the code,
+            // because arccos is not differentiable at -1 and 1.
+            // (Even though the overall 'difference' function is differentiable.)
+            using std::acos;
+            T dist = 2*acos( diff[3] );
 
             // Make sure we do the right thing if a and b are not in the same sheet
             // of the double covering of the unit quaternions over SO(3)
@@ -725,7 +748,8 @@ public:
         result.axpy(-1*(q*p), q);
 
         // The ternary operator comes from the derivative of the absolute value function
-        result *= 4 * UnitVector<T,4>::derivativeOfArcCosSquared(std::abs(sp)) * ( (sp<0) ? -1 : 1 );
+        using std::abs;
+        result *= 4 * UnitVector<T,4>::derivativeOfArcCosSquared(abs(sp)) * ( (sp<0) ? -1 : 1 );
 
         return result;
     }
@@ -742,7 +766,8 @@ public:
             for (int j=0; j<=i; j++)
                 A(i,j) = pProjected[i]*pProjected[j];
 
-        A *= 4*UnitVector<T,4>::secondDerivativeOfArcCosSquared(std::abs(sp));
+        using std::abs;
+        A *= 4*UnitVector<T,4>::secondDerivativeOfArcCosSquared(abs(sp));
 
         // Compute matrix B (see notes)
         Dune::SymmetricMatrix<T,4> Pq;
@@ -751,7 +776,7 @@ public:
                 Pq(i,j) = (i==j) - q.globalCoordinates()[i]*q.globalCoordinates()[j];
 
         // Bring it all together
-        A.axpy(-4* ((sp<0) ? -1 : 1) * UnitVector<T,4>::derivativeOfArcCosSquared(std::abs(sp))*sp, Pq);
+        A.axpy(-4* ((sp<0) ? -1 : 1) * UnitVector<T,4>::derivativeOfArcCosSquared(abs(sp))*sp, Pq);
 
         return A;
     }
@@ -773,7 +798,8 @@ public:
         Dune::FieldMatrix<T,4,4> A;
         // A = row * column
         Dune::FMatrixHelp::multMatrix(column,row,A);
-        A *= 4 * UnitVector<T,4>::secondDerivativeOfArcCosSquared(std::abs(sp));
+        using std::abs;
+        A *= 4 * UnitVector<T,4>::secondDerivativeOfArcCosSquared(abs(sp));
 
         // Compute matrix B (see notes)
         Dune::FieldMatrix<T,4,4> Pp, Pq;
@@ -787,7 +813,7 @@ public:
         Dune::FMatrixHelp::multMatrix(Pp,Pq,B);
 
         // Bring it all together
-        A.axpy(4 * ( (sp<0) ? -1 : 1) * UnitVector<T,4>::derivativeOfArcCosSquared(std::abs(sp)), B);
+        A.axpy(4 * ( (sp<0) ? -1 : 1) * UnitVector<T,4>::derivativeOfArcCosSquared(abs(sp)), B);
 
         return A;
     }
@@ -812,16 +838,17 @@ public:
 
         double plusMinus = (sp < 0) ? -1 : 1;
 
+        using std::abs;
         for (int i=0; i<4; i++)
             for (int j=0; j<4; j++)
                 for (int k=0; k<4; k++) {
 
-                    result[i][j][k] = plusMinus * UnitVector<T,4>::thirdDerivativeOfArcCosSquared(std::abs(sp)) * pProjected[i] * pProjected[j] * pProjected[k]
-                                    - UnitVector<T,4>::secondDerivativeOfArcCosSquared(std::abs(sp)) * ((i==j)*sp + p.globalCoordinates()[i]*q.globalCoordinates()[j])*pProjected[k]
-                                    - UnitVector<T,4>::secondDerivativeOfArcCosSquared(std::abs(sp)) * ((i==k)*sp + p.globalCoordinates()[i]*q.globalCoordinates()[k])*pProjected[j]
-                                    - UnitVector<T,4>::secondDerivativeOfArcCosSquared(std::abs(sp)) * pProjected[i] * Pq[j][k] * sp
-                                    + plusMinus * UnitVector<T,4>::derivativeOfArcCosSquared(std::abs(sp)) * ((i==j)*q.globalCoordinates()[k] + (i==k)*q.globalCoordinates()[j]) * sp
-                                    - plusMinus * UnitVector<T,4>::derivativeOfArcCosSquared(std::abs(sp)) * p.globalCoordinates()[i] * Pq[j][k];
+                    result[i][j][k] = plusMinus * UnitVector<T,4>::thirdDerivativeOfArcCosSquared(abs(sp)) * pProjected[i] * pProjected[j] * pProjected[k]
+                                    - UnitVector<T,4>::secondDerivativeOfArcCosSquared(abs(sp)) * ((i==j)*sp + p.globalCoordinates()[i]*q.globalCoordinates()[j])*pProjected[k]
+                                    - UnitVector<T,4>::secondDerivativeOfArcCosSquared(abs(sp)) * ((i==k)*sp + p.globalCoordinates()[i]*q.globalCoordinates()[k])*pProjected[j]
+                                    - UnitVector<T,4>::secondDerivativeOfArcCosSquared(abs(sp)) * pProjected[i] * Pq[j][k] * sp
+                                    + plusMinus * UnitVector<T,4>::derivativeOfArcCosSquared(abs(sp)) * ((i==j)*q.globalCoordinates()[k] + (i==k)*q.globalCoordinates()[j]) * sp
+                                    - plusMinus * UnitVector<T,4>::derivativeOfArcCosSquared(abs(sp)) * p.globalCoordinates()[i] * Pq[j][k];
                 }
 
         Pq *= 4;
@@ -862,10 +889,11 @@ public:
 
         double plusMinus = (sp < 0) ? -1 : 1;
 
-        result = plusMinus * UnitVector<T,4>::thirdDerivativeOfArcCosSquared(std::abs(sp))         * Tensor3<T,4,4,4>::product(qProjected,pProjected,pProjected)
-                 + UnitVector<T,4>::secondDerivativeOfArcCosSquared(std::abs(sp))      * derivativeOfPqOTimesPq
-                 - UnitVector<T,4>::secondDerivativeOfArcCosSquared(std::abs(sp)) * sp * Tensor3<T,4,4,4>::product(qProjected,Pq)
-                 - plusMinus * UnitVector<T,4>::derivativeOfArcCosSquared(std::abs(sp))            * Tensor3<T,4,4,4>::product(qProjected,Pq);
+        using std::abs;
+        result = plusMinus * UnitVector<T,4>::thirdDerivativeOfArcCosSquared(abs(sp))         * Tensor3<T,4,4,4>::product(qProjected,pProjected,pProjected)
+                 + UnitVector<T,4>::secondDerivativeOfArcCosSquared(abs(sp))      * derivativeOfPqOTimesPq
+                 - UnitVector<T,4>::secondDerivativeOfArcCosSquared(abs(sp)) * sp * Tensor3<T,4,4,4>::product(qProjected,Pq)
+                 - plusMinus * UnitVector<T,4>::derivativeOfArcCosSquared(abs(sp))            * Tensor3<T,4,4,4>::product(qProjected,Pq);
 
         result *= 4;
 
@@ -955,6 +983,8 @@ public:
     We tacitly assume that the matrix really is orthogonal */
     void set(const Dune::FieldMatrix<T,3,3>& m) {
 
+        using std::sqrt;
+
         // Easier writing
         Dune::FieldVector<T,4>& p = (*this);
         // The following equations for the derivation of a unit quaternion from a rotation
@@ -969,7 +999,7 @@ public:
         // avoid rounding problems
         if (p[0] >= p[1] && p[0] >= p[2] && p[0] >= p[3]) {
 
-            p[0] = std::sqrt(p[0]);
+            p[0] = sqrt(p[0]);
 
             // r_x r_y = (R_12 + R_21) / 4
             p[1] = (m[0][1] + m[1][0]) / 4 / p[0];
@@ -982,7 +1012,7 @@ public:
 
         } else if (p[1] >= p[0] && p[1] >= p[2] && p[1] >= p[3]) {
 
-            p[1] = std::sqrt(p[1]);
+            p[1] = sqrt(p[1]);
 
             // r_x r_y = (R_12 + R_21) / 4
             p[0] = (m[0][1] + m[1][0]) / 4 / p[1];
@@ -995,7 +1025,7 @@ public:
 
         } else if (p[2] >= p[0] && p[2] >= p[1] && p[2] >= p[3]) {
 
-            p[2] = std::sqrt(p[2]);
+            p[2] = sqrt(p[2]);
 
             // r_x r_z = (R_13 + R_31) / 4
             p[0] = (m[0][2] + m[2][0]) / 4 / p[2];
@@ -1008,7 +1038,7 @@ public:
 
         } else {
 
-            p[3] = std::sqrt(p[3]);
+            p[3] = sqrt(p[3]);
 
             // r_0 r_x = (R_32 - R_23) / 4
             p[0] = (m[2][1] - m[1][2]) / 4 / p[3];
@@ -1028,6 +1058,9 @@ public:
     We tacitly assume that the matrix really is orthogonal */
     static Tensor3<T,4,3,3> derivativeOfMatrixToQuaternion(const Dune::FieldMatrix<T,3,3>& m)
     {
+      using std::pow;
+      using std::sqrt;
+
       Tensor3<T,4,3,3> result;
 
       Dune::FieldVector<T,4> p;
@@ -1045,10 +1078,10 @@ public:
         if (p[0] >= p[1] && p[0] >= p[2] && p[0] >= p[3])
         {
           result[0] = {{1,0,0},{0,-1,0},{0,0,-1}};
-          result[0] *= 1.0/(8.0*std::sqrt(p[0]));
+          result[0] *= 1.0/(8.0*sqrt(p[0]));
 
-          T denom = 32 * std::pow(p[0],1.5);
-          T offDiag = 1.0/(4*std::sqrt(p[0]));
+          T denom = 32 * pow(p[0],1.5);
+          T offDiag = 1.0/(4*sqrt(p[0]));
 
           result[1] = { {-(m[0][1]+m[1][0]) / denom, offDiag,              0},
                         {offDiag,                    (m[0][1]+m[1][0]) / denom, 0},
@@ -1065,10 +1098,10 @@ public:
         else if (p[1] >= p[0] && p[1] >= p[2] && p[1] >= p[3])
         {
           result[1] = {{-1,0,0},{0,1,0},{0,0,-1}};
-          result[1] *= 1.0/(8.0*std::sqrt(p[1]));
+          result[1] *= 1.0/(8.0*sqrt(p[1]));
 
-          T denom = 32 * std::pow(p[1],1.5);
-          T offDiag = 1.0/(4*std::sqrt(p[1]));
+          T denom = 32 * pow(p[1],1.5);
+          T offDiag = 1.0/(4*sqrt(p[1]));
 
           result[0] = { {(m[0][1]+m[1][0]) / denom, offDiag,                    0},
                         {offDiag,                  -(m[0][1]+m[1][0]) / denom, 0},
@@ -1085,10 +1118,10 @@ public:
         else if (p[2] >= p[0] && p[2] >= p[1] && p[2] >= p[3])
         {
           result[2] = {{-1,0,0},{0,-1,0},{0,0,1}};
-          result[2] *= 1.0/(8.0*std::sqrt(p[2]));
+          result[2] *= 1.0/(8.0*sqrt(p[2]));
 
-          T denom = 32 * std::pow(p[2],1.5);
-          T offDiag = 1.0/(4*std::sqrt(p[2]));
+          T denom = 32 * pow(p[2],1.5);
+          T offDiag = 1.0/(4*sqrt(p[2]));
 
           result[0] = { {(m[0][2]+m[2][0]) / denom, 0,                         offDiag},
                         {0,                        (m[0][2]+m[2][0]) / denom, 0},
@@ -1105,10 +1138,10 @@ public:
         else
         {
           result[3] = {{1,0,0},{0,1,0},{0,0,1}};
-          result[3] *= 1.0/(8.0*std::sqrt(p[3]));
+          result[3] *= 1.0/(8.0*sqrt(p[3]));
 
-          T denom = 32 * std::pow(p[3],1.5);
-          T offDiag = 1.0/(4*std::sqrt(p[3]));
+          T denom = 32 * pow(p[3],1.5);
+          T offDiag = 1.0/(4*sqrt(p[3]));
 
           result[0] = { {-(m[2][1]-m[1][2]) / denom, 0,                         0},
                         {0,                         -(m[2][1]-m[1][2]) / denom, -offDiag},
diff --git a/dune/gfe/unitvector.hh b/dune/gfe/unitvector.hh
index 734188488d5accf9b290a535ec518148507d1350..83f1813c53e1911611795c7358339102d175a167 100644
--- a/dune/gfe/unitvector.hh
+++ b/dune/gfe/unitvector.hh
@@ -3,7 +3,12 @@
 
 #include <dune/common/fvector.hh>
 #include <dune/common/fmatrix.hh>
+#include <dune/common/version.hh>
+#if DUNE_VERSION_GTE(DUNE_COMMON, 2, 7)
+#include <dune/common/math.hh>
+#else
 #include <dune/common/power.hh>
+#endif
 
 #include <dune/gfe/tensor3.hh>
 #include <dune/gfe/symmetricmatrix.hh>
@@ -24,42 +29,54 @@ class UnitVector
 
     /** \brief Computes sin(x) / x without getting unstable for small x */
     static T sinc(const T& x) {
-        return (x < 1e-4) ? 1 - (x*x/6) : std::sin(x)/x;
+        using std::sin;
+        return (x < 1e-4) ? 1 - (x*x/6) : sin(x)/x;
     }
 
     /** \brief Compute arccos^2 without using the (at 1) nondifferentiable function acos x close to 1 */
     static T arcCosSquared(const T& x) {
+        using std::acos;
         const T eps = 1e-4;
         if (x > 1-eps) {  // acos is not differentiable, use the series expansion instead
             return -2 * (x-1) + 1.0/3 * (x-1)*(x-1) - 4.0/45 * (x-1)*(x-1)*(x-1);
         } else
-            return Dune::Power<2>::eval(std::acos(x));
+#if DUNE_VERSION_GTE(DUNE_COMMON, 2, 7)
+            return Dune::power(acos(x),2);
+#else
+            return Dune::Power<2>::eval(acos(x));
+#endif
     }
 
     /** \brief Compute the derivative of arccos^2 without getting unstable for x close to 1 */
     static T derivativeOfArcCosSquared(const T& x) {
+        using std::acos;
+        using std::sqrt;
         const T eps = 1e-4;
         if (x > 1-eps) {  // regular expression is unstable, use the series expansion instead
             return -2 + 2*(x-1)/3 - 4/15*(x-1)*(x-1);
         } else if (x < -1+eps) {  // The function is not differentiable
             DUNE_THROW(Dune::Exception, "arccos^2 is not differentiable at x==-1!");
         } else
-            return -2*std::acos(x) / std::sqrt(1-x*x);
+            return -2*acos(x) / sqrt(1-x*x);
     }
 
     /** \brief Compute the second derivative of arccos^2 without getting unstable for x close to 1 */
     static T secondDerivativeOfArcCosSquared(const T& x) {
+        using std::acos;
+        using std::pow;
         const T eps = 1e-4;
         if (x > 1-eps) {  // regular expression is unstable, use the series expansion instead
             return 2.0/3 - 8*(x-1)/15;
         } else if (x < -1+eps) {  // The function is not differentiable
             DUNE_THROW(Dune::Exception, "arccos^2 is not differentiable at x==-1!");
         } else
-            return 2/(1-x*x) - 2*x*std::acos(x) / std::pow(1-x*x,1.5);
+            return 2/(1-x*x) - 2*x*acos(x) / pow(1-x*x,1.5);
     }
 
     /** \brief Compute the third derivative of arccos^2 without getting unstable for x close to 1 */
     static T thirdDerivativeOfArcCosSquared(const T& x) {
+        using std::acos;
+        using std::sqrt;
         const T eps = 1e-4;
         if (x > 1-eps) {  // regular expression is unstable, use the series expansion instead
             return -8.0/15 + 24*(x-1)/35;
@@ -67,7 +84,7 @@ class UnitVector
             DUNE_THROW(Dune::Exception, "arccos^2 is not differentiable at x==-1!");
         } else {
             T d = 1-x*x;
-            return 6*x/(d*d) - 6*x*x*std::acos(x)/(d*d*std::sqrt(d)) - 2*std::acos(x)/(d*std::sqrt(d));
+            return 6*x/(d*d) - 6*x*x*acos(x)/(d*d*sqrt(d)) - 2*acos(x)/(d*sqrt(d));
         }
     }
 
@@ -156,11 +173,13 @@ public:
      /** \brief The exponential map */
     static UnitVector exp(const UnitVector& p, const EmbeddedTangentVector& v) {
 
-        assert( std::abs(p.data_*v) < 1e-5 );
+        using std::abs;
+        using std::cos;
+        assert( abs(p.data_*v) < 1e-5 );
 
         const T norm = v.two_norm();
         UnitVector result = p;
-        result.data_ *= std::cos(norm);
+        result.data_ *= cos(norm);
         result.data_.axpy(sinc(norm), v);
         return result;
     }
@@ -176,15 +195,18 @@ public:
     /** \brief Length of the great arc connecting the two points */
      static T distance(const UnitVector& a, const UnitVector& b) {
 
+         using std::acos;
+         using std::min;
+
          // Not nice: we are in a class for unit vectors, but the class is actually
          // supposed to handle perturbations of unit vectors as well.  Therefore
          // we normalize here.
          T x = a.data_ * b.data_/a.data_.two_norm()/b.data_.two_norm();
 
          // paranoia:  if the argument is just eps larger than 1 acos returns NaN
-         x = std::min(x,1.0);
+         x = min(x,1.0);
 
-         return std::acos(x);
+         return acos(x);
     }
 
 #if ADOLC_ADOUBLE_H
@@ -197,7 +219,8 @@ public:
          adouble x = a.data_ * b.data_ / (a.data_.two_norm()*b.data_.two_norm());
 
          // paranoia:  if the argument is just eps larger than 1 acos returns NaN
-         x = std::min(x,1.0);
+         using std::min;
+         x = min(x,1.0);
 
          // Special implementation that remains AD-differentiable near x==1
          return arcCosSquared(x);
@@ -219,7 +242,8 @@ public:
         result = b.projectOntoTangentSpace(result);
 
         // Gradient must be a tangent vector at b, in other words, orthogonal to it
-        assert( std::abs(b.data_ * result) < 1e-5);
+        using std::abs;
+        assert(abs(b.data_ * result) < 1e-5);
 
         return result;
     }
diff --git a/problems/staticrod.parset b/problems/staticrod.parset
index 63d7044a8b016a38fa700b79777c062bc7c3e75f..2d001ecad0fbe15fff3188010c99d570ae8c0909 100644
--- a/problems/staticrod.parset
+++ b/problems/staticrod.parset
@@ -51,18 +51,17 @@ instrumented = no
 #   Problem specifications
 ############################
 
+# Interpolation method
+interpolationMethod = geodesic
+
 A = 1
 J1 = 1
 J2 = 1
 E = 2.5e5
 nu = 0.3
 
-dirichletValueX = 1
-dirichletValueY = 0
-dirichletValueZ = 0
+dirichletValue = 1 0 0
 
-dirichletAxisX = 1
-dirichletAxisY = 0
-dirichletAxisZ = 0
+dirichletAxis = 1 0 0
 
 dirichletAngle = 0
diff --git a/src/cosserat-continuum.cc b/src/cosserat-continuum.cc
index eb763ee627ae9684bef0a6436126649715778155..a34e177404fe0bb92d59a6ca1f35952bf9a08838 100644
--- a/src/cosserat-continuum.cc
+++ b/src/cosserat-continuum.cc
@@ -419,7 +419,7 @@ int main (int argc, char *argv[]) try
                         3,adouble> cosseratEnergyADOLCLocalStiffness(materialParameters,
                                                                      &neumannBoundary,
                                                                      neumannFunction,
-                                                                     nullptr);
+                                                                     volumeLoad);
 
     MixedLocalGFEADOLCStiffness<decltype(compositeBasis),
                                 RealTuple<double,3>,
diff --git a/src/rod3d.cc b/src/rod3d.cc
index 8d4a9abcac5d91b5051fddb28b0debbe0e5a30ca..866addb252c4b8174963e3d3d6f52c1087b0ffa2 100644
--- a/src/rod3d.cc
+++ b/src/rod3d.cc
@@ -1,5 +1,12 @@
 #include <config.h>
 
+// Includes for the ADOL-C automatic differentiation library
+// Need to come before (almost) all others.
+#include <adolc/drivers/drivers.h>
+#include <dune/fufem/utilities/adolcnamespaceinjections.hh>
+
+#include <optional>
+
 #include <dune/common/bitsetvector.hh>
 #include <dune/common/parametertree.hh>
 #include <dune/common/parametertreeparser.hh>
@@ -8,34 +15,53 @@
 
 #include <dune/istl/io.hh>
 
+#include <dune/functions/functionspacebases/interpolate.hh>
+#include <dune/functions/functionspacebases/lagrangebasis.hh>
+#include <dune/functions/functionspacebases/powerbasis.hh>
+#include <dune/functions/gridfunctions/discreteglobalbasisfunction.hh>
 
 #include <dune/solvers/solvers/iterativesolver.hh>
 #include <dune/solvers/norms/energynorm.hh>
 
+#if HAVE_DUNE_VTK
+#include <dune/vtk/vtkwriter.hh>
+#include <dune/vtk/datacollectors/lagrangedatacollector.hh>
+#else
 #include <dune/gfe/cosseratvtkwriter.hh>
+#endif
+
+#include <dune/gfe/cosseratrodenergy.hh>
+#include <dune/gfe/geodesicfeassembler.hh>
+#include <dune/gfe/localgeodesicfeadolcstiffness.hh>
+#include <dune/gfe/localgeodesicfefunction.hh>
+#include <dune/gfe/localprojectedfefunction.hh>
 #include <dune/gfe/rigidbodymotion.hh>
-#include <dune/gfe/geodesicdifference.hh>
 #include <dune/gfe/rotation.hh>
-#include <dune/gfe/rodassembler.hh>
 #include <dune/gfe/riemanniantrsolver.hh>
 
 typedef RigidBodyMotion<double,3> TargetSpace;
 
 const int blocksize = TargetSpace::TangentVector::dimension;
 
+// Approximation order of the finite element space
+constexpr int order = 2;
+
 using namespace Dune;
-using std::string;
 
 int main (int argc, char *argv[]) try
 {
+    MPIHelper::instance(argc, argv);
+
     typedef std::vector<RigidBodyMotion<double,3> > SolutionType;
 
     // parse data file
     ParameterTree parameterSet;
-    if (argc==2)
-        ParameterTreeParser::readINITree(argv[1], parameterSet);
-    else
-        ParameterTreeParser::readINITree("rod3d.parset", parameterSet);
+    if (argc < 2)
+      DUNE_THROW(Exception, "Usage: ./rod3d <parameter file>");
+
+    ParameterTreeParser::readINITree(argv[1], parameterSet);
+
+    ParameterTreeParser::readOptions(argc, argv, parameterSet);
 
     // read solver settings
     const int numLevels        = parameterSet.get<int>("numLevels");
@@ -71,33 +97,43 @@ int main (int argc, char *argv[]) try
     using GridView = GridType::LeafGridView;
     GridView gridView = grid.leafGridView();
 
-    using FEBasis = Functions::LagrangeBasis<GridView,1>;
+    using FEBasis = Functions::LagrangeBasis<GridView,order>;
     FEBasis feBasis(gridView);
 
     SolutionType x(feBasis.size());
 
-    // //////////////////////////
-    //   Initial solution
-    // //////////////////////////
+    //////////////////////////////////////////////
+    //  Create the stress-free configuration
+    //////////////////////////////////////////////
+
+    std::vector<double> referenceConfigurationX(feBasis.size());
+
+    auto identity = [](const FieldVector<double,1>& x) { return x; };
 
-    for (size_t i=0; i<x.size(); i++) {
-        x[i].r[0] = 0;
-        x[i].r[1] = 0;
-        x[i].r[2] = double(i)/(x.size()-1);
-        x[i].q    = Rotation<double,3>::identity();
+    Functions::interpolate(feBasis, referenceConfigurationX, identity);
+
+    std::vector<RigidBodyMotion<double,3> > referenceConfiguration(feBasis.size());
+
+    for (std::size_t i=0; i<referenceConfiguration.size(); i++)
+    {
+        referenceConfiguration[i].r[0] = 0;
+        referenceConfiguration[i].r[1] = 0;
+        referenceConfiguration[i].r[2] = referenceConfigurationX[i];
+        referenceConfiguration[i].q = Rotation<double,3>::identity();
     }
 
+    /////////////////////////////////////////////////////////////////
+    //   Select the reference configuration as initial iterate
+    /////////////////////////////////////////////////////////////////
+
+    x = referenceConfiguration;
+
     // /////////////////////////////////////////
     //   Read Dirichlet values
     // /////////////////////////////////////////
-    x.back().r[0] = parameterSet.get<double>("dirichletValueX");
-    x.back().r[1] = parameterSet.get<double>("dirichletValueY");
-    x.back().r[2] = parameterSet.get<double>("dirichletValueZ");
-
-    FieldVector<double,3> axis;
-    axis[0] = parameterSet.get<double>("dirichletAxisX");
-    axis[1] = parameterSet.get<double>("dirichletAxisY");
-    axis[2] = parameterSet.get<double>("dirichletAxisZ");
+    x.back().r = parameterSet.get<FieldVector<double,3> >("dirichletValue");
+
+    auto axis = parameterSet.get<FieldVector<double,3> >("dirichletAxis");
     double angle = parameterSet.get<double>("dirichletAngle");
 
     x.back().q = Rotation<double,3>(axis, M_PI*angle/180);
@@ -120,17 +156,43 @@ int main (int argc, char *argv[]) try
         
     dirichletNodes[0] = true;
     dirichletNodes.back() = true;
-    
-    // ///////////////////////////////////////////
-    //   Create a solver for the rod problem
-    // ///////////////////////////////////////////
 
-    RodLocalStiffness<GridView,double> localStiffness(gridView,
-                                                      A, J1, J2, E, nu);
+    //////////////////////////////////////////////
+    //  Create the energy and assembler
+    //////////////////////////////////////////////
+
+    using ATargetSpace = TargetSpace::rebind<adouble>::other;
+    using GeodesicInterpolationRule  = LocalGeodesicFEFunction<1, double, FEBasis::LocalView::Tree::FiniteElement, ATargetSpace>;
+    using ProjectedInterpolationRule = GFE::LocalProjectedFEFunction<1, double, FEBasis::LocalView::Tree::FiniteElement, ATargetSpace>;
+
+    // Assembler using ADOL-C
+    std::shared_ptr<GFE::LocalEnergy<FEBasis,ATargetSpace> > localRodEnergy;
 
-    LocalGeodesicFEFDStiffness<FEBasis,RigidBodyMotion<double,3> > localFDStiffness(&localStiffness);
+    if (parameterSet["interpolationMethod"] == "geodesic")
+    {
+        auto energy = std::make_shared<GFE::CosseratRodEnergy<FEBasis, GeodesicInterpolationRule, adouble> >(gridView,
+                                                                                                             A, J1, J2, E, nu);
+        energy->setReferenceConfiguration(referenceConfiguration);
+        localRodEnergy = energy;
+    }
+    else if (parameterSet["interpolationMethod"] == "projected")
+    {
+        auto energy = std::make_shared<GFE::CosseratRodEnergy<FEBasis, ProjectedInterpolationRule, adouble> >(gridView,
+                                                                                                              A, J1, J2, E, nu);
+        energy->setReferenceConfiguration(referenceConfiguration);
+        localRodEnergy = energy;
+    }
+    else
+        DUNE_THROW(Exception, "Unknown interpolation method " << parameterSet["interpolationMethod"] << " requested!");
 
-    RodAssembler<FEBasis,3> rodAssembler(gridView, localFDStiffness);
+    LocalGeodesicFEADOLCStiffness<FEBasis,
+                                  TargetSpace> localStiffness(localRodEnergy.get());
+
+    GeodesicFEAssembler<FEBasis,TargetSpace> rodAssembler(gridView, localStiffness);
+
+    /////////////////////////////////////////////
+    //   Create a solver for the rod problem
+    /////////////////////////////////////////////
 
     RiemannianTrustRegionSolver<FEBasis,RigidBodyMotion<double,3> > rodSolver;
 
@@ -162,87 +224,56 @@ int main (int argc, char *argv[]) try
     // //////////////////////////////
     //   Output result
     // //////////////////////////////
-    CosseratVTKWriter<GridType>::write<FEBasis>(feBasis,x, resultPath + "rod3d-result");
-
-    BlockVector<FieldVector<double, 6> > strain(x.size()-1);
-    rodAssembler.getStrain(x,strain);
-
-    // If convergence measurement is not desired stop here
-    if (!instrumented)
-        exit(0);
-
-    // //////////////////////////////////////////////////////////
-    //   Recompute and compare against exact solution
-    // //////////////////////////////////////////////////////////
-    
-    SolutionType exactSolution = x;
-
-    // //////////////////////////////////////////////////////////
-    //   Compute hessian of the rod functional at the exact solution
-    //   for use of the energy norm it creates.
-    // //////////////////////////////////////////////////////////
-
-    BCRSMatrix<FieldMatrix<double, 6, 6> > hessian;
-    MatrixIndexSet indices(exactSolution.size(), exactSolution.size());
-    rodAssembler.getNeighborsPerVertex(indices);
-    indices.exportIdx(hessian);
-    BlockVector<FieldVector<double,6> > dummyRhs(x.size());
-    rodAssembler.assembleGradientAndHessian(exactSolution, dummyRhs, hessian);
-
-
-    double error = std::numeric_limits<double>::max();
-
-    SolutionType intermediateSolution(x.size());
-
-    // Create statistics file
-    std::ofstream statisticsFile((resultPath + "trStatistics").c_str());
-
-    // Compute error of the initial iterate
-    typedef BlockVector<FieldVector<double,6> > RodDifferenceType;
-    RodDifferenceType rodDifference = computeGeodesicDifference(exactSolution, initialIterate);
-    double oldError = std::sqrt(EnergyNorm<BCRSMatrix<FieldMatrix<double, blocksize, blocksize> >, BlockVector<FieldVector<double,blocksize> > >::normSquared(rodDifference, hessian));
-
-    int i;
-    for (i=0; i<maxTrustRegionSteps; i++) {
-        
-        // /////////////////////////////////////////////////////
-        //   Read iteration from file
-        // /////////////////////////////////////////////////////
-        char iSolFilename[100];
-        sprintf(iSolFilename, "tmp/intermediateSolution_%04d", i);
-            
-        FILE* fp = fopen(iSolFilename, "rb");
-        if (!fp)
-            DUNE_THROW(IOError, "Couldn't open intermediate solution '" << iSolFilename << "'");
-        for (size_t j=0; j<intermediateSolution.size(); j++) {
-            fread(&intermediateSolution[j].r, sizeof(double), 3, fp);
-            fread(&intermediateSolution[j].q, sizeof(double), 4, fp);
-        }
-        
-        fclose(fp);
-
-        // /////////////////////////////////////////////////////
-        //   Compute error
-        // /////////////////////////////////////////////////////
-
-        rodDifference = computeGeodesicDifference(exactSolution, intermediateSolution);
-        
-        error = std::sqrt(EnergyNorm<BCRSMatrix<FieldMatrix<double, blocksize, blocksize> >, BlockVector<FieldVector<double,blocksize> > >::normSquared(rodDifference, hessian));
-        
-
-        double convRate = error / oldError;
-
-        // Output
-        std::cout << "Trust-region iteration: " << i << "  error : " << error << ",      "
-                  << "convrate " << convRate << std::endl;
-        statisticsFile << i << "  " << error << "  " << convRate << std::endl;
-
-        if (error < 1e-12)
-          break;
+#if HAVE_DUNE_VTK
+    using DataCollector = Vtk::LagrangeDataCollector<GridView,order>;
+    DataCollector dataCollector(gridView);
+    VtkUnstructuredGridWriter<GridView,DataCollector> vtkWriter(gridView, Vtk::ASCII);
+
+    // Make basis for R^3-valued data
+    using namespace Functions::BasisFactory;
+
+    auto worldBasis = makeBasis(
+      gridView,
+      power<3>(lagrange<order>())
+    );
+
+    // The rod displacement field
+    BlockVector<FieldVector<double,3> > displacement(worldBasis.size());
+    for (std::size_t i=0; i<x.size(); i++)
+      displacement[i] = x[i].r;
+
+    std::vector<double> xEmbedding;
+    Functions::interpolate(feBasis, xEmbedding, [](FieldVector<double,1> x){ return x; });
+
+    BlockVector<FieldVector<double,3> > gridEmbedding(xEmbedding.size());
+    for (std::size_t i=0; i<gridEmbedding.size(); i++)
+      gridEmbedding[i] = {xEmbedding[i], 0, 0};
+
+    displacement -= gridEmbedding;
+
+    auto displacementFunction = Functions::makeDiscreteGlobalBasisFunction<FieldVector<double,3> >(worldBasis, displacement);
+    vtkWriter.addPointData(displacementFunction, "displacement", 3);
+
+    // The three director fields
+    using FunctionType = decltype(displacementFunction);
+    std::array<std::optional<FunctionType>, 3> directorFunction;
+    std::array<BlockVector<FieldVector<double, 3> >, 3> director;
+    for (int i=0; i<3; i++)
+    {
+      director[i].resize(worldBasis.size());
+      for (std::size_t j=0; j<x.size(); j++)
+        director[i][j] = x[j].q.director(i);
+
+      directorFunction[i] = Functions::makeDiscreteGlobalBasisFunction<FieldVector<double,3> >(worldBasis, std::move(director[i]));
+      vtkWriter.addPointData(*directorFunction[i], "director " + std::to_string(i), 3);
+    }
 
-        oldError = error;
-        
-    }            
+    vtkWriter.write(resultPath + "rod3d-result");
+#else
+    std::cout << "Falling back to legacy file writing.  Get dune-vtk for better results" << std::endl;
+    // Fall-back solution for users without dune-vtk
+    CosseratVTKWriter<GridType>::write<FEBasis>(feBasis,x, resultPath + "rod3d-result");
+#endif
 
 } catch (Exception& e)
 {
diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt
index e1952d1af6c8993a4dcc161acec079f6a3436980..042be43e0174cf40caf74ceea13da7cbb8140169 100644
--- a/test/CMakeLists.txt
+++ b/test/CMakeLists.txt
@@ -2,14 +2,13 @@ set(TESTS
   adolctest
   averagedistanceassemblertest
   cosseratenergytest
-  frameinvariancetest
+  cosseratrodenergytest
   harmonicenergytest
   localgeodesicfefunctiontest
   localgfetestfunctiontest
   localprojectedfefunctiontest
   orthogonalmatrixtest
   rigidbodymotiontest
-  rodassemblertest
   rotationtest
   svdtest
   targetspacetest
diff --git a/test/cosseratenergytest.cc b/test/cosseratenergytest.cc
index 256fba6fe2adfd69f9ff72019df1b60d9071c1f1..cdfc0f38c9d95afdf49e1aadd9cb380d69296214 100644
--- a/test/cosseratenergytest.cc
+++ b/test/cosseratenergytest.cc
@@ -15,8 +15,6 @@
 #include "multiindex.hh"
 #include "valuefactory.hh"
 
-const double eps = 1e-4;
-
 typedef RigidBodyMotion<double,3> TargetSpace;
 
 using namespace Dune;
diff --git a/test/frameinvariancetest.cc b/test/cosseratrodenergytest.cc
similarity index 60%
rename from test/frameinvariancetest.cc
rename to test/cosseratrodenergytest.cc
index dcf53d480975d78a4b2fce61765376dd61a5e121..ff65271b6c6ed816cded185956c0158e4b1a1fd9 100644
--- a/test/frameinvariancetest.cc
+++ b/test/cosseratrodenergytest.cc
@@ -4,15 +4,10 @@
 
 #include <dune/functions/functionspacebases/lagrangebasis.hh>
 
-#include <dune/gfe/quaternion.hh>
-
-#include <dune/gfe/rodassembler.hh>
-
+#include <dune/gfe/cosseratrodenergy.hh>
+#include <dune/gfe/localgeodesicfefunction.hh>
 #include <dune/gfe/rigidbodymotion.hh>
 
-// Number of degrees of freedom: 
-// 7 (x, y, z, q_1, q_2, q_3, q_4) for a spatial rod
-const int blocksize = 6;
 
 using namespace Dune;
 
@@ -74,14 +69,36 @@ int main (int argc, char *argv[]) try
         rotatedX[i].q = rotation.mult(x[i].q);
     }
 
-    RodLocalStiffness<GridView,double> localRodFirstOrderModel(gridView,
-                                                               1,1,1,1e6,0.3);
+    using GeodesicInterpolationRule  = LocalGeodesicFEFunction<1, double,
+                                                               FEBasis::LocalView::Tree::FiniteElement,
+                                                               RigidBodyMotion<double,3> >;
+
+    GFE::CosseratRodEnergy<FEBasis,
+                           GeodesicInterpolationRule,
+                           double> localRodEnergy(gridView,
+                                                  1,1,1,1e6,0.3);
+
+    std::vector<RigidBodyMotion<double,3> > referenceConfiguration(gridView.size(1));
+
+    for (const auto vertex : vertices(gridView))
+    {
+        auto idx = gridView.indexSet().index(vertex);
+
+        referenceConfiguration[idx].r[0] = 0;
+        referenceConfiguration[idx].r[1] = 0;
+        referenceConfiguration[idx].r[2] = vertex.geometry().corner(0)[0];
+        referenceConfiguration[idx].q = Rotation<double,3>::identity();
+    }
+
+    localRodEnergy.setReferenceConfiguration(referenceConfiguration);
 
-    LocalGeodesicFEFDStiffness<FEBasis,RigidBodyMotion<double,3> > localFDStiffness(&localRodFirstOrderModel);
+    auto localView = feBasis.localView();
+    localView.bind(*gridView.begin<0>());
 
-    RodAssembler<FEBasis,3> assembler(feBasis, localFDStiffness);
+    SolutionType localX = {x[0], x[1]};
+    SolutionType localRotatedX = {rotatedX[0], rotatedX[1]};
 
-    if (std::abs(assembler.computeEnergy(x) - assembler.computeEnergy(rotatedX)) > 1e-6)
+    if (std::abs(localRodEnergy.energy(localView, localX) - localRodEnergy.energy(localView, localRotatedX)) > 1e-6)
         DUNE_THROW(Dune::Exception, "Rod energy not invariant under rigid body motions!");
 
  } catch (Exception& e) {
diff --git a/test/geodesicfeassemblerwrappertest.cc b/test/geodesicfeassemblerwrappertest.cc
index 3e78813537d2fc681af3723c304491920ccfc1f0..36250b3c9480635914866ebbd654feeb9e12ee25 100644
--- a/test/geodesicfeassemblerwrappertest.cc
+++ b/test/geodesicfeassemblerwrappertest.cc
@@ -114,7 +114,6 @@ int main (int argc, char *argv[])
   ));
 
   using CompositeBasis = decltype(compositeBasis);
-  using LocalView = typename CompositeBasis::LocalView;
 
   /////////////////////////////////////////////////////////////////////////
   //  Create the energy functions with their parameters
@@ -170,7 +169,7 @@ int main (int argc, char *argv[])
   x[_0].resize(compositeBasis.size({0}));
   x[_1].resize(compositeBasis.size({1}));
   std::vector<RBM> xRBM(compositeBasis.size({0}));
-  for (int i = 0; i < compositeBasis.size({0}); i++) {
+  for (std::size_t i = 0; i < compositeBasis.size({0}); i++) {
     for (int j = 0; j < gridDim; j++)
       initialDeformation[i][j] = identity[i][j];
     x[_0][i] = initialDeformation[i];
diff --git a/test/rodassemblertest.cc b/test/rodassemblertest.cc
deleted file mode 100644
index 554007834a7010f3f3a0eb1f35572d9ac4d88685..0000000000000000000000000000000000000000
--- a/test/rodassemblertest.cc
+++ /dev/null
@@ -1,587 +0,0 @@
-#include <config.h>
-
-#include <array>
-
-#include <dune/grid/onedgrid.hh>
-
-#include <dune/istl/io.hh>
-
-#include <dune/gfe/rigidbodymotion.hh>
-#include <dune/gfe/rodassembler.hh>
-
-// Number of degrees of freedom: 
-// 7 (x, y, z, q_1, q_2, q_3, q_4) for a spatial rod
-const int blocksize = 6;
-
-using namespace Dune;
-
-void infinitesimalVariation(RigidBodyMotion<double,3>& c, double eps, int i)
-{
-    if (i<3)
-        c.r[i] += eps;
-    else {
-        Dune::FieldVector<double,3> axial(0);
-        axial[i-3] = eps;
-        SkewMatrix<double,3> variation(axial);
-        c.q = c.q.mult(Rotation<double,3>::exp(variation));
-    }
-}
-
-template <class FEBasis>
-void strainFD(const std::vector<RigidBodyMotion<double,3> >& x, 
-              double pos,
-              std::array<FieldMatrix<double,2,6>, 6>& fdStrainDerivatives,
-              const RodAssembler<FEBasis,3>& assembler)
-{
-    assert(x.size()==2);
-    double eps = 1e-8;
-
-    auto element = assembler.basis_.gridView_.template begin<0>();
-
-    // ///////////////////////////////////////////////////////////
-    //   Compute gradient by finite-difference approximation
-    // ///////////////////////////////////////////////////////////
-    std::vector<RigidBodyMotion<double,3> > forwardSolution = x;
-    std::vector<RigidBodyMotion<double,3> > backwardSolution = x;
-    
-    for (size_t i=0; i<x.size(); i++) {
-        
-        Dune::FieldVector<double,6> fdGradient;
-        
-        for (int j=0; j<6; j++) {
-            
-            infinitesimalVariation(forwardSolution[i], eps, j);
-            infinitesimalVariation(backwardSolution[i], -eps, j);
-            
-//             fdGradient[j] = (assembler.computeEnergy(forwardSolution) - assembler.computeEnergy(backwardSolution))
-//                 / (2*eps);
-            Dune::FieldVector<double,6> strain;
-            strain = assembler.getStrain(forwardSolution, element, pos);
-            strain -= assembler.getStrain(backwardSolution, element, pos);
-            strain /= 2*eps;
-            
-            for (int m=0; m<6; m++)
-                fdStrainDerivatives[m][i][j] = strain[m];
-
-            forwardSolution[i] = x[i];
-            backwardSolution[i] = x[i];
-        }
-        
-    }
-
-}
-
-
-template <class FEBasis>
-void strain2ndOrderFD(const std::vector<RigidBodyMotion<double,3> >& x, 
-                      double pos,
-                      std::array<Matrix<FieldMatrix<double,6,6> >, 3>& translationDer,
-                      std::array<Matrix<FieldMatrix<double,3,3> >, 3>& rotationDer,
-                      const RodAssembler<FEBasis,3>& assembler)
-{
-    assert(x.size()==2);
-    double eps = 1e-3;
-
-    auto element = assembler.basis_.gridView_.template begin<0>();
-
-    for (int m=0; m<3; m++) {
-        
-        translationDer[m].setSize(2,2);
-        translationDer[m] = 0;
-        
-        rotationDer[m].setSize(2,2);
-        rotationDer[m] = 0;
-
-    }
-
-    // ///////////////////////////////////////////////////////////
-    //   Compute gradient by finite-difference approximation
-    // ///////////////////////////////////////////////////////////
-    std::vector<RigidBodyMotion<double,3> > forwardSolution = x;
-    std::vector<RigidBodyMotion<double,3> > backwardSolution = x;
-    
-    std::vector<RigidBodyMotion<double,3> > forwardForwardSolution = x;
-    std::vector<RigidBodyMotion<double,3> > forwardBackwardSolution = x;
-    std::vector<RigidBodyMotion<double,3> > backwardForwardSolution = x;
-    std::vector<RigidBodyMotion<double,3> > backwardBackwardSolution = x;
-
-    for (int i=0; i<2; i++) {
-        
-        for (int j=0; j<3; j++) {
-
-            for (int k=0; k<2; k++) {
-
-                for (int l=0; l<3; l++) {
-
-                    if (i==k && j==l) {
-
-                        infinitesimalVariation(forwardSolution[i], eps, j+3);
-                        infinitesimalVariation(backwardSolution[i], -eps, j+3);
-            
-                        // Second derivative
-//                         fdHessian[j][k] = (assembler.computeEnergy(forwardSolution) 
-//                                            - 2*assembler.computeEnergy(x) 
-//                                            + assembler.computeEnergy(backwardSolution)) / (eps*eps);
-                        
-                        Dune::FieldVector<double,6> strain;
-                        strain = assembler.getStrain(forwardSolution, element, pos);
-                        strain += assembler.getStrain(backwardSolution, element, pos);
-                        strain.axpy(-2, assembler.getStrain(x, element, pos));
-                        strain /= eps*eps;
-            
-                        for (int m=0; m<3; m++)
-                            rotationDer[m][i][k][j][l] = strain[3+m];
-
-                        forwardSolution = x;
-                        backwardSolution = x;
-
-                    } else {
-
-                        infinitesimalVariation(forwardForwardSolution[i],   eps, j+3);
-                        infinitesimalVariation(forwardForwardSolution[k],   eps, l+3);
-                        infinitesimalVariation(forwardBackwardSolution[i],  eps, j+3);
-                        infinitesimalVariation(forwardBackwardSolution[k], -eps, l+3);
-                        infinitesimalVariation(backwardForwardSolution[i], -eps, j+3);
-                        infinitesimalVariation(backwardForwardSolution[k],  eps, l+3);
-                        infinitesimalVariation(backwardBackwardSolution[i],-eps, j+3);
-                        infinitesimalVariation(backwardBackwardSolution[k],-eps, l+3);
-
-
-//                         fdHessian[j][k] = (assembler.computeEnergy(forwardForwardSolution)
-//                                            + assembler.computeEnergy(backwardBackwardSolution)
-//                                            - assembler.computeEnergy(forwardBackwardSolution)
-//                                            - assembler.computeEnergy(backwardForwardSolution)) / (4*eps*eps);
-
-                        Dune::FieldVector<double,6> strain;
-                        strain  = assembler.getStrain(forwardForwardSolution, element, pos);
-                        strain += assembler.getStrain(backwardBackwardSolution, element, pos);
-                        strain -= assembler.getStrain(forwardBackwardSolution, element, pos);
-                        strain -= assembler.getStrain(backwardForwardSolution, element, pos);
-                        strain /= 4*eps*eps;
-
-
-                        for (int m=0; m<3; m++)
-                            rotationDer[m][i][k][j][l] = strain[3+m];
-                        
-                        forwardForwardSolution   = x;
-                        forwardBackwardSolution  = x;
-                        backwardForwardSolution  = x;
-                        backwardBackwardSolution = x;
-
-
-                    }
-
-                }
-
-            }
-        }
-        
-    }
-
-}
-
-
-template <class GridType>
-void strain2ndOrderFD2(const std::vector<RigidBodyMotion<double,3> >& x, 
-                       double pos,
-                       Dune::FieldVector<double,1> shapeGrad[2],
-                       Dune::FieldVector<double,1> shapeFunction[2],
-                       std::array<Matrix<FieldMatrix<double,6,6> >, 3>& translationDer,
-                       std::array<Matrix<FieldMatrix<double,3,3> >, 3>& rotationDer,
-                       const RodAssembler<GridType,3>& assembler) 
-{
-    assert(x.size()==2);
-    double eps = 1e-3;
-
-    for (int m=0; m<3; m++) {
-        
-        translationDer[m].setSize(2,2);
-        translationDer[m] = 0;
-        
-        rotationDer[m].setSize(2,2);
-        rotationDer[m] = 0;
-
-    }
-
-    // ///////////////////////////////////////////////////////////
-    //   Compute gradient by finite-difference approximation
-    // ///////////////////////////////////////////////////////////
-    std::vector<RigidBodyMotion<double,3> > forwardSolution = x;
-    std::vector<RigidBodyMotion<double,3> > backwardSolution = x;
-    
-    for (int k=0; k<2; k++) {
-        
-        for (int l=0; l<3; l++) {
-
-            infinitesimalVariation(forwardSolution[k], eps, l+3);
-            infinitesimalVariation(backwardSolution[k], -eps, l+3);
-                
-            std::array<FieldMatrix<double,2,6>, 6> forwardStrainDer;
-            assembler.strainDerivative(forwardSolution, pos, shapeGrad, shapeFunction, forwardStrainDer);
-
-            std::array<FieldMatrix<double,2,6>, 6> backwardStrainDer;
-            assembler.strainDerivative(backwardSolution, pos, shapeGrad, shapeFunction, backwardStrainDer);
-            
-            for (int i=0; i<2; i++) {
-                for (int j=0; j<3; j++) {
-                    for (int m=0; m<3; m++) {
-                        rotationDer[m][i][k][j][l] = (forwardStrainDer[m][i][j]-backwardStrainDer[m][i][j]) / (2*eps);
-                    }
-                }
-            }
-
-            forwardSolution = x;
-            backwardSolution = x;
-            
-        }
-        
-    }
-    
-}
-
-
-
-
-
-template <class GridType>
-void expHessianFD()
-{
-    using namespace Dune;
-    double eps = 1e-3;
-
-    // ///////////////////////////////////////////////////////////
-    //   Compute gradient by finite-difference approximation
-    // ///////////////////////////////////////////////////////////
-    SkewMatrix<double,3> forward;
-    SkewMatrix<double,3> backward;
-    
-    SkewMatrix<double,3> forwardForward;
-    SkewMatrix<double,3> forwardBackward;
-    SkewMatrix<double,3> backwardForward;
-    SkewMatrix<double,3> backwardBackward;
-
-    for (int i=0; i<3; i++) {
-        
-        for (int j=0; j<3; j++) {
-
-            Quaternion<double> hessian;
-
-            if (i==j) {
-
-                forward = backward = 0;
-                forward.axial()[i]  += eps;
-                backward.axial()[i] -= eps;
-                
-                // Second derivative
-                //                         fdHessian[j][k] = (assembler.computeEnergy(forward) 
-                //                                            - 2*assembler.computeEnergy(x) 
-                //                                            + assembler.computeEnergy(backward)) / (eps*eps);
-                
-                hessian  = Rotation<double,3>::exp(forward);
-                hessian += Rotation<double,3>::exp(backward);
-                SkewMatrix<double,3> zero(0);
-                hessian.axpy(-2, Rotation<double,3>::exp(zero));
-                hessian /= eps*eps;
-                
-            } else {
-                
-                forwardForward = forwardBackward = 0;
-                backwardForward = backwardBackward = 0;
-
-                forwardForward.axial()[i]   += eps;
-                forwardForward.axial()[j]   += eps;
-                forwardBackward.axial()[i]  += eps;
-                forwardBackward.axial()[j]  -= eps;
-                backwardForward.axial()[i]  -= eps;
-                backwardForward.axial()[j]  += eps;
-                backwardBackward.axial()[i] -= eps;
-                backwardBackward.axial()[j] -= eps;
-                
-                
-                hessian  = Rotation<double,3>::exp(forwardForward);
-                hessian += Rotation<double,3>::exp(backwardBackward);
-                hessian -= Rotation<double,3>::exp(forwardBackward);
-                hessian -= Rotation<double,3>::exp(backwardForward);
-                hessian /= 4*eps*eps;
-                
-            }
-
-            printf("i: %d,  j: %d    ", i, j);
-            std::cout << hessian << std::endl;
-            
-        }
-        
-    }
-}
-
-
-template <class GridType>
-void gradientFDCheck(const std::vector<RigidBodyMotion<double,3> >& x, 
-                     const Dune::BlockVector<Dune::FieldVector<double,6> >& gradient, 
-                     const RodAssembler<GridType,3>& assembler)
-{
-#ifndef ABORT_ON_ERROR
-    static int gradientError = 0;
-    double maxError = -1;
-#endif
-    double eps = 1e-6;
-
-    // ///////////////////////////////////////////////////////////
-    //   Compute gradient by finite-difference approximation
-    // ///////////////////////////////////////////////////////////
-
-    std::vector<RigidBodyMotion<double,3> > forwardSolution = x;
-    std::vector<RigidBodyMotion<double,3> > backwardSolution = x;
-
-    for (size_t i=0; i<x.size(); i++) {
-        
-        Dune::FieldVector<double,6> fdGradient;
-        
-        for (int j=0; j<6; j++) {
-            
-            infinitesimalVariation(forwardSolution[i],   eps, j);
-            infinitesimalVariation(backwardSolution[i], -eps, j);
-            
-            fdGradient[j] = (assembler.computeEnergy(forwardSolution) - assembler.computeEnergy(backwardSolution))
-                / (2*eps);
-            
-            forwardSolution[i] = x[i];
-            backwardSolution[i] = x[i];
-        }
-        
-        if ( (fdGradient-gradient[i]).two_norm() > 1e-6 ) {
-#ifdef ABORT_ON_ERROR
-            std::cout << "Differing gradients at " << i 
-                      << "!  (" << (fdGradient-gradient[i]).two_norm() / gradient[i].two_norm()
-                      << ")    Analytical: " << gradient[i] << ",  fd: " << fdGradient << std::endl;
-            //std::cout << "Current configuration " << std::endl;
-            for (size_t j=0; j<x.size(); j++)
-                std::cout << x[j] << std::endl;
-            //abort();
-#else
-            gradientError++;
-            maxError = std::max(maxError, (fdGradient-gradient[i]).two_norm());
-#endif
-        }
-        
-    }
-
-#ifndef ABORT_ON_ERROR
-    std::cout << gradientError << " errors in the gradient corrected  (max: " << maxError << ")!" << std::endl;
-#endif
-
-}
-
-
-template <class GridType>
-void hessianFDCheck(const std::vector<RigidBodyMotion<double,3> >& x, 
-                    const Dune::BCRSMatrix<Dune::FieldMatrix<double,6,6> >& hessian, 
-                    const RodAssembler<GridType,3>& assembler)
-{
-#ifndef ABORT_ON_ERROR
-    static int hessianError = 0;
-#endif
-    double eps = 1e-2;
-
-    typedef typename Dune::BCRSMatrix<Dune::FieldMatrix<double,6,6> >::row_type::const_iterator ColumnIterator;
-
-    // ///////////////////////////////////////////////////////////
-    //   Compute gradient by finite-difference approximation
-    // ///////////////////////////////////////////////////////////
-    std::vector<RigidBodyMotion<double,3> > forwardSolution = x;
-    std::vector<RigidBodyMotion<double,3> > backwardSolution = x;
-
-    std::vector<RigidBodyMotion<double,3> > forwardForwardSolution = x;
-    std::vector<RigidBodyMotion<double,3> > forwardBackwardSolution = x;
-    std::vector<RigidBodyMotion<double,3> > backwardForwardSolution = x;
-    std::vector<RigidBodyMotion<double,3> > backwardBackwardSolution = x;
-    
-
-    // ///////////////////////////////////////////////////////////////
-    //   Loop over all blocks of the outer matrix
-    // ///////////////////////////////////////////////////////////////
-    for (size_t i=0; i<hessian.N(); i++) {
-
-        ColumnIterator cIt    = hessian[i].begin();
-        ColumnIterator cEndIt = hessian[i].end();
-
-        for (; cIt!=cEndIt; ++cIt) {
-
-            // ////////////////////////////////////////////////////////////////////////////
-            //   Compute a finite-difference approximation of this hessian matrix block
-            // ////////////////////////////////////////////////////////////////////////////
-
-            Dune::FieldMatrix<double,6,6> fdHessian;
-
-            for (int j=0; j<6; j++) {
-
-                for (int k=0; k<6; k++) {
-
-                    if (i==cIt.index() && j==k) {
-
-                        infinitesimalVariation(forwardSolution[i],   eps, j);
-                        infinitesimalVariation(backwardSolution[i], -eps, j);
-
-                        // Second derivative
-                        fdHessian[j][k] = (assembler.computeEnergy(forwardSolution) 
-                                           + assembler.computeEnergy(backwardSolution) 
-                                           - 2*assembler.computeEnergy(x) 
-                                           ) / (eps*eps);
-
-                        forwardSolution[i]  = x[i];
-                        backwardSolution[i] = x[i];
-
-                    } else {
-
-                        infinitesimalVariation(forwardForwardSolution[i],             eps, j);
-                        infinitesimalVariation(forwardForwardSolution[cIt.index()],   eps, k);
-                        infinitesimalVariation(forwardBackwardSolution[i],            eps, j);
-                        infinitesimalVariation(forwardBackwardSolution[cIt.index()], -eps, k);
-                        infinitesimalVariation(backwardForwardSolution[i],           -eps, j);
-                        infinitesimalVariation(backwardForwardSolution[cIt.index()],  eps, k);
-                        infinitesimalVariation(backwardBackwardSolution[i],          -eps, j);
-                        infinitesimalVariation(backwardBackwardSolution[cIt.index()],-eps, k);
-
-
-                        fdHessian[j][k] = (assembler.computeEnergy(forwardForwardSolution)
-                                           + assembler.computeEnergy(backwardBackwardSolution)
-                                           - assembler.computeEnergy(forwardBackwardSolution)
-                                           - assembler.computeEnergy(backwardForwardSolution)) / (4*eps*eps);
-
-                        forwardForwardSolution[i]             = x[i];
-                        forwardForwardSolution[cIt.index()]   = x[cIt.index()];
-                        forwardBackwardSolution[i]            = x[i];
-                        forwardBackwardSolution[cIt.index()]  = x[cIt.index()];
-                        backwardForwardSolution[i]            = x[i];
-                        backwardForwardSolution[cIt.index()]  = x[cIt.index()];
-                        backwardBackwardSolution[i]           = x[i];
-                        backwardBackwardSolution[cIt.index()] = x[cIt.index()];
-                        
-                    }
-                            
-                }
-
-            }
-                //exit(0);
-            // /////////////////////////////////////////////////////////////////////////////
-            //   Compare analytical and fd Hessians
-            // /////////////////////////////////////////////////////////////////////////////
-
-            Dune::FieldMatrix<double,6,6> diff = fdHessian;
-            diff -= *cIt;
-
-            if ( diff.frobenius_norm() > 1e-5 ) {
-#ifdef ABORT_ON_ERROR
-                std::cout << "Differing hessians at [(" << i << ", "<< cIt.index() << ")]!" << std::endl
-                          << "Analytical: " << std::endl << *cIt << std::endl
-                          << "fd: " << std::endl << fdHessian << std::endl;
-                abort();
-#else
-                hessianError++;
-#endif
-            }
-
-        }
-
-    }
-
-#ifndef ABORT_ON_ERROR
-    std::cout << hessianError << " errors in the Hessian corrected!" << std::endl;
-#endif
-
-}
-
-
-int main (int argc, char *argv[]) try
-{
-    typedef std::vector<RigidBodyMotion<double,3> > SolutionType;
-
-    // ///////////////////////////////////////
-    //    Create the grid
-    // ///////////////////////////////////////
-    typedef OneDGrid GridType;
-    GridType grid(1, 0, 1);
-
-    using GridView = GridType::LeafGridView;
-    GridView gridView = grid.leafGridView();
-
-    SolutionType x(gridView.size(1));
-
-    // //////////////////////////
-    //   Initial solution
-    // //////////////////////////
-    FieldVector<double,3>  xAxis(0);
-    xAxis[0] = 1;
-    FieldVector<double,3>  zAxis(0);
-    zAxis[2] = 1;
-
-    for (size_t i=0; i<x.size(); i++) {
-        x[i].r[0] = 0;    // x
-        x[i].r[1] = 0;                 // y
-        x[i].r[2] = double(i)/(x.size()-1);                 // z
-        //x[i].r[2] = i+5;
-        x[i].q = Quaternion<double>::identity();
-        //x[i].q = Quaternion<double>(zAxis, M_PI/2 * double(i)/(x.size()-1));
-    }
-
-    //x.back().r[1] = 0.1;
-    //x.back().r[2] = 2;
-    //x.back().q = Quaternion<double>(zAxis, M_PI/4);
-
-    std::cout << "Left boundary orientation:" << std::endl;
-    std::cout << "director 0:  " << x[0].q.director(0) << std::endl;
-    std::cout << "director 1:  " << x[0].q.director(1) << std::endl;
-    std::cout << "director 2:  " << x[0].q.director(2) << std::endl;
-    std::cout << std::endl;
-    std::cout << "Right boundary orientation:" << std::endl;
-    std::cout << "director 0:  " << x[x.size()-1].q.director(0) << std::endl;
-    std::cout << "director 1:  " << x[x.size()-1].q.director(1) << std::endl;
-    std::cout << "director 2:  " << x[x.size()-1].q.director(2) << std::endl;
-//     exit(0);
-
-    //x[0].r[2] = -1;
-
-    // ///////////////////////////////////////////
-    //   Create a solver for the rod problem
-    // ///////////////////////////////////////////
-
-    using Basis = Functions::LagrangeBasis<GridView,1>;
-    Basis basis(gridView);
-
-    RodLocalStiffness<GridView,double> localStiffness(gridView,
-                                                                    0.01, 0.0001, 0.0001, 2.5e5, 0.3);
-
-    LocalGeodesicFEFDStiffness<Basis,RigidBodyMotion<double,3> > localFDStiffness(&localStiffness);
-
-    RodAssembler<Basis,3> rodAssembler(basis, localFDStiffness);
-
-    std::cout << "Energy: " << rodAssembler.computeEnergy(x) << std::endl;
-
-    double pos = (argc==2) ? atof(argv[1]) : 0.5;
-
-    FieldVector<double,1> shapeGrad[2];
-    shapeGrad[0] = -1;
-    shapeGrad[1] =  1;
-
-    FieldVector<double,1> shapeFunction[2];
-    shapeFunction[0] = 1-pos;
-    shapeFunction[1] =  pos;
-
-    exit(0);
-    BlockVector<FieldVector<double,6> > rhs(x.size());
-    BCRSMatrix<FieldMatrix<double,6,6> > hessianMatrix;
-    MatrixIndexSet indices(grid.size(1), grid.size(1));
-    rodAssembler.getNeighborsPerVertex(indices);
-    indices.exportIdx(hessianMatrix);
-
-    rodAssembler.assembleGradientAndHessian(x, rhs, hessianMatrix);
-    
-    gradientFDCheck(x, rhs, rodAssembler);
-    hessianFDCheck(x, hessianMatrix, rodAssembler);
-        
-    // //////////////////////////////
- } catch (Exception& e) {
-
-    std::cout << e.what() << std::endl;
-
- }
diff --git a/test/rotationtest.cc b/test/rotationtest.cc
index ac4f2f6a32aeceb42bd568c64157ad318e595458..7b51c0a049f6463c74aae36205c72e20989b574b 100644
--- a/test/rotationtest.cc
+++ b/test/rotationtest.cc
@@ -5,12 +5,7 @@
 
 #include <dune/common/fmatrix.hh>
 
-#warning Do not include onedgrid.hh
-#include <dune/grid/onedgrid.hh>
-
 #include <dune/gfe/rotation.hh>
-#warning Do not include rodlocalstiffness.hh
-#include <dune/gfe/rodlocalstiffness.hh>
 #include "valuefactory.hh"
 
 using namespace Dune;
@@ -94,123 +89,6 @@ void testDDExp()
     }
 }
 
-void testDerivativeOfInterpolatedPosition()
-{
-    std::array<Rotation<double,3>, 6> q;
-
-    FieldVector<double,3>  xAxis = {1,0,0};
-    FieldVector<double,3>  yAxis = {0,1,0};
-    FieldVector<double,3>  zAxis = {0,0,1};
-
-    q[0] = Rotation<double,3>(xAxis, 0);
-    q[1] = Rotation<double,3>(xAxis, M_PI/2);
-    q[2] = Rotation<double,3>(yAxis, 0);
-    q[3] = Rotation<double,3>(yAxis, M_PI/2);
-    q[4] = Rotation<double,3>(zAxis, 0);
-    q[5] = Rotation<double,3>(zAxis, M_PI/2);
-
-    double eps = 1e-7;
-
-    for (int i=0; i<6; i++) {
-
-        for (int j=0; j<6; j++) {
-
-            for (int k=0; k<7; k++) {
-
-                double s = k/6.0;
-
-                std::array<Quaternion<double>,6> fdGrad;
-
-                // ///////////////////////////////////////////////////////////
-                //   First: test the interpolated position
-                // ///////////////////////////////////////////////////////////
-                for (int l=0; l<3; l++) {
-                    SkewMatrix<double,3> forward(FieldVector<double,3>(0));
-                    SkewMatrix<double,3> backward(FieldVector<double,3>(0));
-                    forward.axial()[l] += eps;
-                    backward.axial()[l] -= eps;
-                    fdGrad[l] =  Rotation<double,3>::interpolate(q[i].mult(Rotation<double,3>::exp(forward)), q[j], s);
-                    fdGrad[l] -= Rotation<double,3>::interpolate(q[i].mult(Rotation<double,3>::exp(backward)), q[j], s);
-                    fdGrad[l] /= 2*eps;
-
-                    fdGrad[3+l] =  Rotation<double,3>::interpolate(q[i], q[j].mult(Rotation<double,3>::exp(forward)), s);
-                    fdGrad[3+l] -= Rotation<double,3>::interpolate(q[i], q[j].mult(Rotation<double,3>::exp(backward)), s);
-                    fdGrad[3+l] /= 2*eps;
-                }
-
-                // Compute analytical gradient
-                std::array<Quaternion<double>,6> grad;
-                RodLocalStiffness<OneDGrid,double>::interpolationDerivative(q[i], q[j], s, grad);
-
-                for (int l=0; l<6; l++) {
-                    Quaternion<double> diff = fdGrad[l];
-                    diff -= grad[l];
-                    if (diff.two_norm() > 1e-6) {
-                        std::cout << "Error in position " << l << ":  fd: " << fdGrad[l]
-                                  << "    analytical: " << grad[l] << std::endl;
-                    }
-
-                }
-
-                // ///////////////////////////////////////////////////////////
-                //   Second: test the interpolated velocity vector
-                // ///////////////////////////////////////////////////////////
-
-                for (const double intervalLength : {1.0/3, 2.0/3, 3.0/3, 4.0/3, 5.0/3, 6.0/3, 7.0/3})
-                {
-                    Dune::FieldVector<double,3> variation;
-
-                    for (int m=0; m<3; m++) {
-                        variation = 0;
-                        variation[m] = eps;
-                        fdGrad[m] =  Rotation<double,3>::interpolateDerivative(q[i].mult(Rotation<double,3>::exp(SkewMatrix<double,3>(variation))),
-                                                                               q[j], s);
-                        variation = 0;
-                        variation[m] = -eps;
-                        fdGrad[m] -= Rotation<double,3>::interpolateDerivative(q[i].mult(Rotation<double,3>::exp(SkewMatrix<double,3>(variation))),
-                                                                               q[j], s);
-                        fdGrad[m] /= 2*eps;
-
-                        variation = 0;
-                        variation[m] = eps;
-                        fdGrad[3+m] =  Rotation<double,3>::interpolateDerivative(q[i], q[j].mult(Rotation<double,3>::exp(SkewMatrix<double,3>(variation))), s);
-                        variation = 0;
-                        variation[m] = -eps;
-                        fdGrad[3+m] -= Rotation<double,3>::interpolateDerivative(q[i], q[j].mult(Rotation<double,3>::exp(SkewMatrix<double,3>(variation))), s);
-                        fdGrad[3+m] /= 2*eps;
-
-                    }
-
-                    // Scale the finite difference gradient with the interval length
-                    for (auto& parDer : fdGrad)
-                        parDer /= intervalLength;
-
-                    // Compute analytical velocity vector gradient
-                    RodLocalStiffness<OneDGrid,double>::interpolationVelocityDerivative(q[i], q[j], s*intervalLength, intervalLength, grad);
-
-                    for (int m=0; m<6; m++) {
-                        Quaternion<double> diff = fdGrad[m];
-                        diff -= grad[m];
-                        if (diff.two_norm() > 1e-6) {
-                            std::cout << "Error in velocity " << m
-                                      << ":  s = " << s << " of (" << intervalLength << ")"
-                                      << "   fd: " << fdGrad[m] << "    analytical: " << grad[m] << std::endl;
-                        }
-
-                    }
-
-                }
-
-            }
-
-        }
-
-    }
-
-}
-
-
-
 void testRotation(Rotation<double,3> q)
 {
     // Make sure it really is a unit quaternion
@@ -388,11 +266,6 @@ int main (int argc, char *argv[]) try
     // //////////////////////////////////////////////
     testDDExp();
 
-    // //////////////////////////////////////////////
-    //   Test derivative of interpolated position
-    // //////////////////////////////////////////////
-    testDerivativeOfInterpolatedPosition();
-
     return not passed;
 
  } catch (Exception& e) {