diff --git a/CHANGELOG.md b/CHANGELOG.md
index 52d877d9b7d4c41dcc873e5b62a2d1b3e5f79c4a..b51284fef3cdeb1516e22e0a254a3e4b8e81f1f1 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,8 @@
 # Master
 
+- The `RigidBodyMotion` class has been removed.  Please use
+  `ProductManifold<RealTuple,Rotation>` from now on.
+
 - Building the module requires CMake version 3.16 now, to be in line
   with the current core modules.
 
diff --git a/dune/gfe/assemblers/cosseratenergystiffness.hh b/dune/gfe/assemblers/cosseratenergystiffness.hh
index 3caffc35ad99fa4ef61f53d22aaa00ddd34880aa..08831326982b1b697f3fd8062b650e38e0fd06fb 100644
--- a/dune/gfe/assemblers/cosseratenergystiffness.hh
+++ b/dune/gfe/assemblers/cosseratenergystiffness.hh
@@ -23,7 +23,9 @@
 #include <dune/gfe/tensor3.hh>
 #include <dune/gfe/cosseratstrain.hh>
 #include <dune/gfe/spaces/orthogonalmatrix.hh>
-#include <dune/gfe/spaces/rigidbodymotion.hh>
+#include <dune/gfe/spaces/productmanifold.hh>
+#include <dune/gfe/spaces/realtuple.hh>
+#include <dune/gfe/spaces/rotation.hh>
 
 #define DONT_USE_CURL
 
@@ -69,7 +71,7 @@ public:
 
 template<class Basis, int dim, class field_type=double>
 class CosseratEnergyLocalStiffness
-  : public Dune::GFE::LocalEnergy<Basis,RigidBodyMotion<field_type,dim> >,
+  : public Dune::GFE::LocalEnergy<Basis,Dune::GFE::ProductManifold<RealTuple<field_type,dim>,Rotation<field_type,dim> > >,
     public MixedLocalGeodesicFEStiffness<Basis,
         RealTuple<field_type,dim>,
         Rotation<field_type,dim> >
@@ -77,7 +79,7 @@ class CosseratEnergyLocalStiffness
   // grid types
   typedef typename Basis::GridView GridView;
   typedef typename GridView::ctype DT;
-  typedef RigidBodyMotion<field_type,dim> TargetSpace;
+  typedef Dune::GFE::ProductManifold<RealTuple<field_type,dim>,Rotation<field_type,dim> > TargetSpace;
   typedef typename TargetSpace::ctype RT;
   typedef typename GridView::template Codim<0>::Entity Entity;
 
@@ -342,12 +344,14 @@ public:
 };
 
 template <class Basis, int dim, class field_type>
-[[deprecated("Use an std::vector<RealTuple<field_type,dim>> and an std::vector<Rotation<field_type,dim>> together with the MixedGFEAssembler and the GFEAssemblerWrapper instead of std::vector<RigidBodyMotion<field_type,dim>>.")]]
+[[deprecated("Use an std::vector<RealTuple<field_type,dim>> and an std::vector<Rotation<field_type,dim>> together with the MixedGFEAssembler and the GFEAssemblerWrapper instead of std::vector<Dune::GFE::ProductManifold<RealTuple<field_type,dim>,Rotation<field_type,dim> >>.")]]
 typename CosseratEnergyLocalStiffness<Basis,dim,field_type>::RT
 CosseratEnergyLocalStiffness<Basis,dim,field_type>::
 energy(const typename Basis::LocalView& localView,
-       const std::vector<RigidBodyMotion<field_type,dim> >& localSolution) const
+       const std::vector<Dune::GFE::ProductManifold<RealTuple<field_type,dim>,Rotation<field_type,dim> > >& localSolution) const
 {
+  using namespace Dune::Indices;
+
   RT energy = 0;
 
   auto element = localView.element();
@@ -378,7 +382,7 @@ energy(const typename Basis::LocalView& localView,
     DT weight = quad[pt].weight() * integrationElement;
 
     // The value of the local function
-    RigidBodyMotion<field_type,dim> value = localGeodesicFEFunction.evaluate(quadPos);
+    Dune::GFE::ProductManifold<RealTuple<field_type,dim>,Rotation<field_type,dim> > value = localGeodesicFEFunction.evaluate(quadPos);
 
     // The derivative of the local function defined on the reference element
     typename LocalGFEFunctionType::DerivativeType referenceDerivative = localGeodesicFEFunction.evaluateDerivative(quadPos,value);
@@ -396,7 +400,7 @@ energy(const typename Basis::LocalView& localView,
 
     //
     Dune::FieldMatrix<field_type,dim,dim> R;
-    value.q.matrix(R);
+    value[_1].matrix(R);
 
     Dune::GFE::CosseratStrain<field_type,dim,gridDim> U(derivative,R);
 
@@ -405,7 +409,13 @@ energy(const typename Basis::LocalView& localView,
     //  Note: we need it in matrix coordinates
     //////////////////////////////////////////////////////////
 
-    Tensor3<field_type,3,3,gridDim> DR = value.quaternionTangentToMatrixTangent(derivative);
+    // Extract the orientation derivative
+    Dune::FieldMatrix<field_type,4,gridDim> orientationDerivative;
+    for (size_t i=0; i<4; ++i)
+      for (size_t j=0; j<gridDim; ++j)
+        orientationDerivative[i][j] = derivative[3+i][j];
+
+    Tensor3<field_type,3,3,gridDim> DR = value[_1].quaternionTangentToMatrixTangent(orientationDerivative);
 
     // Add the local energy density
     if (gridDim==2) {
@@ -440,7 +450,7 @@ energy(const typename Basis::LocalView& localView,
 
     // Only translational dofs are affected by the volume load
     for (size_t i=0; i<volumeLoadDensity.size(); i++)
-      energy += (volumeLoadDensity[i] * value.r[i]) * quad[pt].weight() * integrationElement;
+      energy += (volumeLoadDensity[i] * value[_0].globalCoordinates()[i]) * quad[pt].weight() * integrationElement;
   }
 
 
@@ -467,14 +477,14 @@ energy(const typename Basis::LocalView& localView,
       const DT integrationElement = it.geometry().integrationElement(quad[pt].position());
 
       // The value of the local function
-      RigidBodyMotion<field_type,dim> value = localGeodesicFEFunction.evaluate(quadPos);
+      Dune::GFE::ProductManifold<RealTuple<field_type,dim>,Rotation<field_type,dim> > value = localGeodesicFEFunction.evaluate(quadPos);
 
       // Value of the Neumann data at the current position
       auto neumannValue = neumannFunction_(it.geometry().global(quad[pt].position()));
 
       // Only translational dofs are affected by the Neumann force
       for (size_t i=0; i<neumannValue.size(); i++)
-        energy += (neumannValue[i] * value.r[i]) * quad[pt].weight() * integrationElement;
+        energy += (neumannValue[i] * value[_0].globalCoordinates()[i]) * quad[pt].weight() * integrationElement;
 
     }
 
diff --git a/dune/gfe/assemblers/cosseratrodenergy.hh b/dune/gfe/assemblers/cosseratrodenergy.hh
index b2c6dced2911729df81ac55800222bac65e008db..5a3361354d1429d7bdfa5c23aea02443c07682a6 100644
--- a/dune/gfe/assemblers/cosseratrodenergy.hh
+++ b/dune/gfe/assemblers/cosseratrodenergy.hh
@@ -17,15 +17,17 @@
 #include <dune/fufem/boundarypatch.hh>
 
 #include <dune/gfe/assemblers/localenergy.hh>
-#include <dune/gfe/spaces/rigidbodymotion.hh>
+#include <dune/gfe/spaces/productmanifold.hh>
+#include <dune/gfe/spaces/realtuple.hh>
+#include <dune/gfe/spaces/rotation.hh>
 
 namespace Dune::GFE {
 
   template<class Basis, class LocalInterpolationRule, class RT>
   class CosseratRodEnergy
-    : public LocalEnergy<Basis, RigidBodyMotion<RT,3> >
+    : public LocalEnergy<Basis, ProductManifold<RealTuple<RT,3>,Rotation<RT,3> > >
   {
-    typedef RigidBodyMotion<RT,3> TargetSpace;
+    using TargetSpace = ProductManifold<RealTuple<RT,3>,Rotation<RT,3> >;
 
     // grid types
     using GridView = typename Basis::GridView;
@@ -50,7 +52,7 @@ namespace Dune::GFE {
        The referenceConfiguration is not a variable, and we don't
        want to use `adouble` for it.
      */
-    std::vector<RigidBodyMotion<double,3> > referenceConfiguration_;
+    std::vector<ProductManifold<RealTuple<double,3>,Rotation<double,3> > > referenceConfiguration_;
 
   public:
 
@@ -99,13 +101,13 @@ namespace Dune::GFE {
 
     /** \brief Set the stress-free configuration
      */
-    void setReferenceConfiguration(const std::vector<RigidBodyMotion<double,3> >& referenceConfiguration) {
+    void setReferenceConfiguration(const std::vector<ProductManifold<RealTuple<double,3>,Rotation<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;
+                       const std::vector<TargetSpace>& localSolution) const override;
 
     /** \brief Get the rod strain at one point in the rod
      *
@@ -121,16 +123,16 @@ namespace Dune::GFE {
      * \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,
+    auto getStress(const std::vector<ProductManifold<RealTuple<Number,3>,Rotation<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,
+    void getStrain(const std::vector<ProductManifold<RealTuple<double,3>,Rotation<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,
+    void getStress(const std::vector<ProductManifold<RealTuple<double,3>,Rotation<double,3> > >& sol,
                    BlockVector<FieldVector<double, blocksize> >& stress) const;
 
     /** \brief Return resultant force across boundary in canonical coordinates
@@ -138,14 +140,14 @@ namespace Dune::GFE {
        \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;
+                           const std::vector<ProductManifold<RealTuple<double,3>,Rotation<double,3> > >& sol) const;
 
   protected:
 
-    std::vector<RigidBodyMotion<double,3> > getLocalReferenceConfiguration(const typename Basis::LocalView& localView) const
+    std::vector<ProductManifold<RealTuple<double,3>,Rotation<double,3> > > getLocalReferenceConfiguration(const typename Basis::LocalView& localView) const
     {
       unsigned int numOfBaseFct = localView.size();
-      std::vector<RigidBodyMotion<double,3> > localReferenceConfiguration(numOfBaseFct);
+      std::vector<ProductManifold<RealTuple<double,3>,Rotation<double,3> > > localReferenceConfiguration(numOfBaseFct);
 
       for (size_t i=0; i<numOfBaseFct; i++)
         localReferenceConfiguration[i] = referenceConfiguration_[localView.index(i)];
@@ -170,7 +172,7 @@ namespace Dune::GFE {
   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 std::vector<TargetSpace>& localCoefficients) const
   {
     const auto& localFiniteElement = localView.tree().finiteElement();
     LocalInterpolationRule localConfiguration(localFiniteElement, localCoefficients);
@@ -179,8 +181,8 @@ namespace Dune::GFE {
 
     RT energy = 0;
 
-    std::vector<RigidBodyMotion<double,3> > localReferenceCoefficients = getLocalReferenceConfiguration(localView);
-    using InactiveLocalInterpolationRule = typename LocalInterpolationRule::template rebind<RigidBodyMotion<double,3> >::other;
+    std::vector<ProductManifold<RealTuple<double,3>,Rotation<double,3> > > localReferenceCoefficients = getLocalReferenceConfiguration(localView);
+    using InactiveLocalInterpolationRule = typename LocalInterpolationRule::template rebind<ProductManifold<RealTuple<double,3>,Rotation<double,3> > >::other;
     InactiveLocalInterpolationRule localReferenceConfiguration(localFiniteElement, localReferenceCoefficients);
 
     // ///////////////////////////////////////////////////////////////////////////////
@@ -268,15 +270,17 @@ namespace Dune::GFE {
     // /////////////////////////////////////////////
 
     // Strain defined on each element
+    using namespace Dune::Indices;
+
     // 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
+    strain[0] = r_s * value[_1].director(0);    // shear strain
+    strain[1] = r_s * value[_1].director(1);    // shear strain
+    strain[2] = r_s * value[_1].director(2);    // stretching strain
 
     // Part II: the Darboux vector
 
-    FieldVector<Number,3> u = darboux<Number>(value.q, q_s);
+    FieldVector<Number,3> u = darboux<Number>(value[_1], q_s);
     strain[3] = u[0];
     strain[4] = u[1];
     strain[5] = u[2];
@@ -287,7 +291,7 @@ namespace Dune::GFE {
   template<class Basis, class LocalInterpolationRule, class RT>
   template <class Number>
   auto CosseratRodEnergy<Basis, LocalInterpolationRule, RT>::
-  getStress(const std::vector<RigidBodyMotion<Number,3> >& localSolution,
+  getStress(const std::vector<ProductManifold<RealTuple<Number,3>,Rotation<Number,3> > >& localSolution,
             const Entity& element,
             const FieldVector<double, 1>& pos) const
   {
@@ -309,7 +313,7 @@ namespace Dune::GFE {
 
   template<class Basis, class LocalInterpolationRule, class RT>
   void CosseratRodEnergy<Basis, LocalInterpolationRule, RT>::
-  getStrain(const std::vector<RigidBodyMotion<double,3> >& sol,
+  getStrain(const std::vector<ProductManifold<RealTuple<double,3>,Rotation<double,3> > >& sol,
             BlockVector<FieldVector<double, blocksize> >& strain) const
   {
     const typename GridView::Traits::IndexSet& indexSet = this->basis_.gridView().indexSet();
@@ -330,7 +334,7 @@ namespace Dune::GFE {
       Dune::LagrangeSimplexLocalFiniteElement<double, double, 1, 1> localFiniteElement;
       int numOfBaseFct = localFiniteElement.localCoefficients().size();
 
-      std::vector<RigidBodyMotion<double,3> > localSolution(2);
+      std::vector<ProductManifold<RealTuple<double,3>,Rotation<double,3> > > localSolution(2);
 
       for (int i=0; i<numOfBaseFct; i++)
         localSolution[i] = sol[indexSet.subIndex(element,i,1)];
@@ -364,7 +368,7 @@ namespace Dune::GFE {
 
   template<class Basis, class LocalInterpolationRule, class RT>
   void CosseratRodEnergy<Basis, LocalInterpolationRule, RT>::
-  getStress(const std::vector<RigidBodyMotion<double,3> >& sol,
+  getStress(const std::vector<ProductManifold<RealTuple<double,3>,Rotation<double,3> > >& sol,
             BlockVector<FieldVector<double, blocksize> >& stress) const
   {
     // Get the strain
@@ -389,7 +393,7 @@ namespace Dune::GFE {
   template <class PatchGridView>
   auto CosseratRodEnergy<Basis, LocalInterpolationRule, RT>::
   getResultantForce(const BoundaryPatch<PatchGridView>& boundary,
-                    const std::vector<RigidBodyMotion<double,3> >& sol) const
+                    const std::vector<ProductManifold<RealTuple<double,3>,Rotation<double,3> > >& sol) const
   {
     const typename GridView::Traits::IndexSet& indexSet = this->basis_.gridView().indexSet();
 
@@ -408,11 +412,11 @@ namespace Dune::GFE {
 
       double pos = facet.geometryInInside().corner(0);
 
-      std::vector<RigidBodyMotion<double,3> > localSolution(2);
+      std::vector<ProductManifold<RealTuple<double,3>,Rotation<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);
+      std::vector<ProductManifold<RealTuple<double,3>,Rotation<double,3> > > localRefConf(2);
       localRefConf[0] = referenceConfiguration_[indexSet.subIndex(*facet.inside(),0,1)];
       localRefConf[1] = referenceConfiguration_[indexSet.subIndex(*facet.inside(),1,1)];
 
diff --git a/dune/gfe/assemblers/geodesicfeassemblerwrapper.hh b/dune/gfe/assemblers/geodesicfeassemblerwrapper.hh
index e6a3fdda5f6629bd2b8c7a60944e24fa7534e42b..12d2b789530bdbeb07227514992cedb4354d9ee9 100644
--- a/dune/gfe/assemblers/geodesicfeassemblerwrapper.hh
+++ b/dune/gfe/assemblers/geodesicfeassemblerwrapper.hh
@@ -4,7 +4,6 @@
 #include <dune/gfe/assemblers/mixedgfeassembler.hh>
 #include <dune/common/tuplevector.hh>
 #include <dune/gfe/spaces/productmanifold.hh>
-#include <dune/gfe/spaces/rigidbodymotion.hh>
 
 namespace Dune::GFE {
 
@@ -87,13 +86,8 @@ splitVector(const std::vector<TargetSpace>& sol) const {
   solutionSplit[_0].resize(n);
   solutionSplit[_1].resize(n);
   for (std::size_t i = 0; i < n; i++) {
-    if constexpr(std::is_base_of<TargetSpace,RigidBodyMotion<double, 3> >::value) {
-      solutionSplit[_0][i] = sol[i].r;       // Deformation part
-      solutionSplit[_1][i] = sol[i].q;       // Rotational part
-    } else if constexpr(std::is_base_of<TargetSpace,ProductManifold<RealTuple<double,3>,UnitVector<double,3> > >::value) {
-      solutionSplit[_0][i] = sol[i][_0];       // Deformation part
-      solutionSplit[_1][i] = sol[i][_1];       // Rotational part
-    }
+    solutionSplit[_0][i] = sol[i][_0];       // Deformation part
+    solutionSplit[_1][i] = sol[i][_1];       // Rotational part
   }
   return solutionSplit;
 }
diff --git a/dune/gfe/assemblers/localintegralenergy.hh b/dune/gfe/assemblers/localintegralenergy.hh
index 40fb241b0586f89a51817707b9661232e6c7c522..23c8dd8d2b34656fdb1dd3e07e3694d63f05a46e 100644
--- a/dune/gfe/assemblers/localintegralenergy.hh
+++ b/dune/gfe/assemblers/localintegralenergy.hh
@@ -10,7 +10,7 @@
 #include <dune/gfe/cosseratstrain.hh>
 #include <dune/gfe/densities/localdensity.hh>
 #include <dune/gfe/spaces/realtuple.hh>
-#include <dune/gfe/spaces/rigidbodymotion.hh>
+#include <dune/gfe/spaces/rotation.hh>
 #ifdef PROJECTED_INTERPOLATION
 #include <dune/gfe/localprojectedfefunction.hh>
 #else
@@ -65,9 +65,6 @@ namespace Dune::GFE {
       using TargetSpaceDeformation = typename std::tuple_element<0, std::tuple<TargetSpaces...> >::type;
       using TargetSpaceRotation = typename std::tuple_element<1, std::tuple<TargetSpaces...> >::type;
 
-      static_assert( (std::is_same<TargetSpaceDeformation, RigidBodyMotion<RT,gridDim> >::value)
-                     or (std::is_same<TargetSpaceDeformation, RealTuple<RT,gridDim> >::value), "The first TargetSpace of LocalGeodesicIntegralEnergy needs to be RigidBodyMotion or RealTuple!" );
-
       const std::vector<TargetSpaceDeformation>& localDeformationConfiguration = std::get<0>(std::forward_as_tuple(localSolutions ...));
       const std::vector<TargetSpaceRotation>& localOrientationConfiguration = std::get<1>(std::forward_as_tuple(localSolutions ...));
 
diff --git a/dune/gfe/assemblers/nonplanarcosseratshellenergy.hh b/dune/gfe/assemblers/nonplanarcosseratshellenergy.hh
index fd1a9eb04bda19594ae45814abbed3f2c1da1020..98d941b502a7cd2e5e6eafa75aa68ed40793788a 100644
--- a/dune/gfe/assemblers/nonplanarcosseratshellenergy.hh
+++ b/dune/gfe/assemblers/nonplanarcosseratshellenergy.hh
@@ -21,8 +21,9 @@
 #include <dune/gfe/tensor3.hh>
 #include <dune/gfe/localprojectedfefunction.hh>
 #include <dune/gfe/assemblers/mixedlocalgfeadolcstiffness.hh>
-#include <dune/gfe/spaces/rigidbodymotion.hh>
-#include <dune/gfe/spaces/unitvector.hh>
+#include <dune/gfe/spaces/productmanifold.hh>
+#include <dune/gfe/spaces/realtuple.hh>
+#include <dune/gfe/spaces/rotation.hh>
 
 #if HAVE_DUNE_CURVEDGEOMETRY
 #include <dune/curvedgeometry/curvedgeometry.hh>
@@ -38,7 +39,7 @@
  */
 template<class Basis, int dim, class field_type, class StressFreeStateGridFunction>
 class NonplanarCosseratShellEnergy
-  : public Dune::GFE::LocalEnergy<Basis,RigidBodyMotion<field_type,dim> >,
+  : public Dune::GFE::LocalEnergy<Basis,Dune::GFE::ProductManifold<RealTuple<field_type,dim>,Rotation<field_type,dim> > >,
     public MixedLocalGeodesicFEStiffness<Basis,
         RealTuple<field_type,dim>,
         Rotation<field_type,dim> >
@@ -46,7 +47,7 @@ class NonplanarCosseratShellEnergy
   // grid types
   typedef typename Basis::GridView GridView;
   typedef typename GridView::ctype DT;
-  typedef RigidBodyMotion<field_type,dim> TargetSpace;
+  typedef Dune::GFE::ProductManifold<RealTuple<field_type,dim>,Rotation<field_type,dim> > TargetSpace;
   typedef typename TargetSpace::ctype RT;
   typedef typename GridView::template Codim<0>::Entity Entity;
 
@@ -191,12 +192,14 @@ public:
 };
 
 template <class Basis, int dim, class field_type, class StressFreeStateGridFunction>
-[[deprecated("Use an std::vector<RealTuple<field_type,dim>> and an std::vector<Rotation<field_type,dim>> together with the MixedGFEAssembler and the GFEAssemblerWrapper instead of std::vector<RigidBodyMotion<field_type,dim>>.")]]
+[[deprecated("Use an std::vector<RealTuple<field_type,dim>> and an std::vector<Rotation<field_type,dim>> together with the MixedGFEAssembler and the GFEAssemblerWrapper instead of std::vector<Dune::GFE::ProductManifold<RealTuple<field_type,dim>,Rotation<field_type,dim> >>.")]]
 typename NonplanarCosseratShellEnergy<Basis, dim, field_type, StressFreeStateGridFunction>::RT
 NonplanarCosseratShellEnergy<Basis,dim,field_type, StressFreeStateGridFunction>::
 energy(const typename Basis::LocalView& localView,
-       const std::vector<RigidBodyMotion<field_type,dim> >& localSolution) const
+       const std::vector<Dune::GFE::ProductManifold<RealTuple<field_type,dim>,Rotation<field_type,dim> > >& localSolution) const
 {
+  using namespace Dune::Indices;
+
   // The element geometry
   auto element = localView.element();
 
@@ -240,7 +243,7 @@ energy(const typename Basis::LocalView& localView,
     const DT integrationElement = geometry.integrationElement(quadPos);
 
     // The value of the local function
-    RigidBodyMotion<field_type,dim> value = localGeodesicFEFunction.evaluate(quadPos);
+    Dune::GFE::ProductManifold<RealTuple<field_type,dim>,Rotation<field_type,dim> > value = localGeodesicFEFunction.evaluate(quadPos);
 
     // The derivative of the local function w.r.t. the coordinate system of the tangent space
     auto derivative = localGeodesicFEFunction.evaluateDerivative(quadPos,value);
@@ -251,11 +254,17 @@ energy(const typename Basis::LocalView& localView,
     //////////////////////////////////////////////////////////
 
     Dune::FieldMatrix<field_type,dim,dim> R;
-    value.q.matrix(R);
+    value[_1].matrix(R);
     auto RT = Dune::GFE::transpose(R);
 
+    // Extract the orientation derivative
+    Dune::FieldMatrix<field_type,4,gridDim> orientationDerivative;
+    for (size_t i=0; i<4; ++i)
+      for (size_t j=0; j<gridDim; ++j)
+        orientationDerivative[i][j] = derivative[3+i][j];
+
     //Derivative of the rotation w.r.t. the coordinate system of the tangent space
-    Tensor3<field_type,3,3,gridDim> DR = value.quaternionTangentToMatrixTangent(derivative);
+    Tensor3<field_type,3,3,gridDim> DR = value[_1].quaternionTangentToMatrixTangent(orientationDerivative);
 
     //////////////////////////////////////////////////////////
     //  Fundamental forms and curvature
@@ -389,7 +398,7 @@ energy(const typename Basis::LocalView& localView,
 
     // Only translational dofs are affected by the volume load
     for (size_t i=0; i<volumeLoadDensity.size(); i++)
-      energy += (volumeLoadDensity[i] * value.r[i]) * quad[pt].weight() * integrationElement;
+      energy += (volumeLoadDensity[i] * value[_0].globalCoordinates()[i]) * quad[pt].weight() * integrationElement;
   }
 
 
@@ -415,14 +424,14 @@ energy(const typename Basis::LocalView& localView,
       const DT integrationElement = it.geometry().integrationElement(quad[pt].position());
 
       // The value of the local function
-      RigidBodyMotion<field_type,dim> value = localGeodesicFEFunction.evaluate(quadPos);
+      Dune::GFE::ProductManifold<RealTuple<field_type,dim>,Rotation<field_type,dim> > value = localGeodesicFEFunction.evaluate(quadPos);
 
       // Value of the Neumann data at the current position
       Dune::FieldVector<double,3> neumannValue = neumannFunction_(it.geometry().global(quad[pt].position()));
 
       // Only translational dofs are affected by the Neumann force
       for (size_t i=0; i<neumannValue.size(); i++)
-        energy += (neumannValue[i] * value.r[i]) * quad[pt].weight() * integrationElement;
+        energy += (neumannValue[i] * value[_0].globalCoordinates()[i]) * quad[pt].weight() * integrationElement;
     }
   }
 
diff --git a/dune/gfe/assemblers/surfacecosseratenergy.hh b/dune/gfe/assemblers/surfacecosseratenergy.hh
index b5d6c16b39a4a3e8c04b733ed3865bb2d88d7a6a..e70d84150e64900b765f8acc5a3198688b6b80a1 100644
--- a/dune/gfe/assemblers/surfacecosseratenergy.hh
+++ b/dune/gfe/assemblers/surfacecosseratenergy.hh
@@ -13,7 +13,9 @@
 #include <dune/gfe/localprojectedfefunction.hh>
 #include <dune/gfe/assemblers/mixedlocalgeodesicfestiffness.hh>
 #include <dune/gfe/tensor3.hh>
-#include <dune/gfe/spaces/rigidbodymotion.hh>
+#include <dune/gfe/spaces/productmanifold.hh>
+#include <dune/gfe/spaces/realtuple.hh>
+#include <dune/gfe/spaces/rotation.hh>
 
 #include <dune/curvedgeometry/curvedgeometry.hh>
 #include <dune/localfunctions/lagrange/lfecache.hh>
@@ -35,7 +37,7 @@ namespace Dune::GFE {
     using Entity = typename GridView::template Codim<0>::Entity ;
     using RBM0 = RealTuple<RT,GridView::dimensionworld> ;
     using RBM1 = Rotation<RT,GridView::dimensionworld> ;
-    using RBM = RigidBodyMotion<RT,GridView::dimensionworld> ;
+    using RBM = ProductManifold<RBM0,RBM1> ;
 
     constexpr static int dimWorld = GridView::dimensionworld;
     constexpr static int gridDim = GridView::dimension;
@@ -60,7 +62,7 @@ namespace Dune::GFE {
       //
       // So, DR[i][j][k] contains \partial R_ij / \partial k
       Tensor3<RT, dimWorld, dimWorld, 4> dd_dq;
-      value.q.getFirstDerivativesOfDirectors(dd_dq);
+      value[Indices::_1].getFirstDerivativesOfDirectors(dd_dq);
 
       derivative_rotation = RT(0);
       for (int i=0; i<dimWorld; i++)
@@ -144,8 +146,8 @@ namespace Dune::GFE {
       std::vector<RBM> localSolutionRBM(localSolution0.size());
       for (int i = 0; i < localSolution0.size(); i++) {
         for (int j = 0; j < dimWorld; j++)
-          localSolutionRBM[i].r[j] = localSolution0[i][j];
-        localSolutionRBM[i].q = localSolution1[i];
+          localSolutionRBM[i][_0][j] = localSolution0[i][j];
+        localSolutionRBM[i][_1] = localSolution1[i];
       }
       typedef LocalGeodesicFEFunction<gridDim, DT, decltype(deformationLocalFiniteElement), RBM> LocalGFEFunctionType;
       LocalGFEFunctionType localGeodesicFEFunction(deformationLocalFiniteElement,localSolutionRBM);
@@ -232,7 +234,7 @@ namespace Dune::GFE {
           //////////////////////////////////////////////////////////
 
           Dune::FieldMatrix<RT,dimWorld,dimWorld> R;
-          value.q.matrix(R);
+          value[_1].matrix(R);
           auto rt = Dune::GFE::transpose(R);
 
           Tensor3<RT,dimWorld,dimWorld,boundaryDim> derivative_rotation;
diff --git a/dune/gfe/cosseratvtkreader.hh b/dune/gfe/cosseratvtkreader.hh
index 7e0e6109999849cf1fe6b2f1d5577efaa212b65b..659634ff549deab6a2e56441ad37e8f3918c2589 100644
--- a/dune/gfe/cosseratvtkreader.hh
+++ b/dune/gfe/cosseratvtkreader.hh
@@ -1,7 +1,9 @@
 #ifndef DUNE_GFE_COSSERATVTKREADER_HH
 #define DUNE_GFE_COSSERATVTKREADER_HH
 
-#include <dune/gfe/spaces/rigidbodymotion.hh>
+#include <dune/gfe/spaces/productmanifold.hh>
+#include <dune/gfe/spaces/realtuple.hh>
+#include <dune/gfe/spaces/rotation.hh>
 
 namespace Dune
 {
@@ -13,7 +15,7 @@ namespace Dune
     {
     public:
 
-      static void read(std::vector<RigidBodyMotion<double,3> >& configuration,
+      static void read(std::vector<ProductManifold<RealTuple<double,3>,Rotation<double,3> > >& configuration,
                        const std::string& filename)
       {
         VTKFile vtkFile;
@@ -23,14 +25,14 @@ namespace Dune
 
         for (size_t i=0; i<configuration.size(); i++)
         {
-          configuration[i].r = vtkFile.points_[i];
+          configuration[i][Indices::_0].globalCoordinates() = vtkFile.points_[i];
 
           FieldMatrix<double,3,3> R;
           for (int j=0; j<3; j++)
             for (int k=0; k<3; k++)
               R[j][k] = vtkFile.directors_[k][i][j];
 
-          configuration[i].q.set(R);
+          configuration[i][Indices::_1].set(R);
         }
 
       }
diff --git a/dune/gfe/cosseratvtkwriter.hh b/dune/gfe/cosseratvtkwriter.hh
index feb41c418e052da2c6c8209828a2183393fd40fd..1bd513471403dc999432e53feafb49e675024833 100644
--- a/dune/gfe/cosseratvtkwriter.hh
+++ b/dune/gfe/cosseratvtkwriter.hh
@@ -11,7 +11,9 @@
 #include <dune/functions/gridfunctions/discreteglobalbasisfunction.hh>
 
 #include <dune/gfe/vtkfile.hh>
-#include <dune/gfe/spaces/rigidbodymotion.hh>
+#include <dune/gfe/spaces/productmanifold.hh>
+#include <dune/gfe/spaces/realtuple.hh>
+#include <dune/gfe/spaces/rotation.hh>
 
 
 /** \brief Write the configuration of a Cosserat material in VTK format */
@@ -22,8 +24,8 @@ class CosseratVTKWriter
   static const int dim = GridType::dimension;
 
   template <typename Basis1, typename Basis2>
-  static void downsample(const Basis1& basis1, const std::vector<RigidBodyMotion<double,3> >& v1,
-                         const Basis2& basis2,       std::vector<RigidBodyMotion<double,3> >& v2)
+  static void downsample(const Basis1& basis1, const std::vector<Dune::GFE::ProductManifold<RealTuple<double,3>,Rotation<double,3> > >& v1,
+                         const Basis2& basis2,       std::vector<Dune::GFE::ProductManifold<RealTuple<double,3>,Rotation<double,3> > >& v2)
   {
     // Embed v1 into R^7
     std::vector<Dune::FieldVector<double,7> > v1Embedded(v1.size());
@@ -35,10 +37,10 @@ class CosseratVTKWriter
     std::vector<Dune::FieldVector<double,7> > v2Embedded;
     Dune::Functions::interpolate(basis2, v2Embedded, function);
 
-    // Copy back from R^7 into RigidBodyMotions
+    // Copy back from R^7 into ProductManifold
     v2.resize(v2Embedded.size());
     for (size_t i=0; i<v2.size(); i++)
-      v2[i] = RigidBodyMotion<double,3>(v2Embedded[i]);
+      v2[i] = Dune::GFE::ProductManifold<RealTuple<double,3>,Rotation<double,3> >(v2Embedded[i]);
   }
 
   template <typename Basis1, typename Basis2>
@@ -118,11 +120,11 @@ public:
                     const std::string& filename)
   {
     using namespace Dune::TypeTree::Indices;
-    std::vector<RigidBodyMotion<double,3> > xRBM(basis.size());
+    std::vector<Dune::GFE::ProductManifold<RealTuple<double,3>,Rotation<double,3> > > xRBM(basis.size());
     for (std::size_t i = 0; i < basis.size(); i++) {
       for (int j = 0; j < 3; j ++)   // Displacement part
-        xRBM[i].r[j] = configuration[_0][i][j];
-      xRBM[i].q = configuration[_1][i];      // Rotation part
+        xRBM[i][_0].globalCoordinates()[j] = configuration[_0][i][j];
+      xRBM[i][_1] = configuration[_1][i];      // Rotation part
     }
     write(basis,xRBM,filename);
   }
@@ -134,10 +136,10 @@ public:
                     const std::string& filename)
   {
     using namespace Dune::TypeTree::Indices;
-    std::vector<RigidBodyMotion<double,3> > xRBM(basis.size());
+    std::vector<Dune::GFE::ProductManifold<RealTuple<double,3>,Rotation<double,3> > > xRBM(basis.size());
     for (std::size_t i = 0; i < basis.size(); i++) {
       for (int j = 0; j < 3; j ++)   // Displacement part
-        xRBM[i].r[j] = configuration[i][j];
+        xRBM[i][_0].globalCoordinates()[j] = configuration[i][j];
     }
     write(basis,xRBM,filename);
   }
@@ -146,9 +148,11 @@ public:
    */
   template <typename Basis>
   static void write(const Basis& basis,
-                    const std::vector<RigidBodyMotion<double,3> >& configuration,
+                    const std::vector<Dune::GFE::ProductManifold<RealTuple<double,3>,Rotation<double,3> > >& configuration,
                     const std::string& filename)
   {
+    using namespace Dune::Indices;
+
     assert(basis.size() == configuration.size());
     auto gridView = basis.gridView();
 
@@ -173,7 +177,7 @@ public:
           blockedInterleaved()
           ));
 
-      std::vector<RigidBodyMotion<double,3> > downsampledConfig;
+      std::vector<Dune::GFE::ProductManifold<RealTuple<double,3>,Rotation<double,3> > > downsampledConfig;
 
       downsample(basis, configuration, blockedP2Basis, downsampledConfig);
 
@@ -198,7 +202,7 @@ public:
     // Enter vertex coordinates
     std::vector<Dune::FieldVector<double, 3> > points(configuration.size());
     for (size_t i=0; i<configuration.size(); i++)
-      points[i] = configuration[i].r;
+      points[i] = configuration[i][_0].globalCoordinates();
 
     vtkFile.points_ = points;
 
@@ -363,7 +367,7 @@ public:
     // Z coordinate for better visualization of wrinkles
     std::vector<double> zCoord(points.size());
     for (size_t i=0; i<configuration.size(); i++)
-      zCoord[i] = configuration[i].r[2];
+      zCoord[i] = configuration[i][_0].globalCoordinates()[2];
 
     vtkFile.zCoord_ = zCoord;
 
@@ -372,7 +376,7 @@ public:
     {
       vtkFile.directors_[i].resize(configuration.size());
       for (size_t j=0; j<configuration.size(); j++)
-        vtkFile.directors_[i][j] = configuration[j].q.director(i);
+        vtkFile.directors_[i][j] = configuration[j][_1].director(i);
     }
 
     // Actually write the VTK file to disk
diff --git a/dune/gfe/localgeodesicfefunction.hh b/dune/gfe/localgeodesicfefunction.hh
index 76e0d86417eee26bdf66c38d57a607954f65d781..6892e93604dfd22ed4872f30835899739ea1e9d3 100644
--- a/dune/gfe/localgeodesicfefunction.hh
+++ b/dune/gfe/localgeodesicfefunction.hh
@@ -10,7 +10,9 @@
 #include <dune/gfe/averagedistanceassembler.hh>
 #include <dune/gfe/targetspacertrsolver.hh>
 #include <dune/gfe/localquickanddirtyfefunction.hh>
-#include <dune/gfe/spaces/rigidbodymotion.hh>
+#include <dune/gfe/spaces/productmanifold.hh>
+#include <dune/gfe/spaces/realtuple.hh>
+#include <dune/gfe/spaces/rotation.hh>
 
 #include <dune/gfe/tensor3.hh>
 #include <dune/gfe/tensorssd.hh>
@@ -551,18 +553,17 @@ evaluateFDDerivativeOfGradientWRTCoefficient(const Dune::FieldVector<ctype, dim>
 
 
 /** \brief A function defined by simplicial geodesic interpolation
-           from the reference element to a RigidBodyMotion.
+           from the reference element to a ProductManifold<RealTuple,Rotation>.
 
    This is a specialization for speeding up the code.
-   We use that a RigidBodyMotion is a product manifold.
 
    \tparam dim Dimension of the reference element
    \tparam ctype Type used for coordinates on the reference element
  */
 template <int dim, class ctype, class LocalFiniteElement, class field_type>
-class LocalGeodesicFEFunction<dim,ctype,LocalFiniteElement,RigidBodyMotion<field_type,3> >
+class LocalGeodesicFEFunction<dim,ctype,LocalFiniteElement, Dune::GFE::ProductManifold<RealTuple<field_type,3>, Rotation<field_type,3> > >
 {
-  typedef RigidBodyMotion<field_type,3> TargetSpace;
+  using TargetSpace = Dune::GFE::ProductManifold<RealTuple<field_type,3>, Rotation<field_type,3> >;
 
   typedef typename TargetSpace::EmbeddedTangentVector EmbeddedTangentVector;
   static const int embeddedDim = EmbeddedTangentVector::dimension;
@@ -583,14 +584,15 @@ public:
     : localFiniteElement_(localFiniteElement),
     translationCoefficients_(coefficients.size())
   {
+    using namespace Dune::Indices;
     assert(localFiniteElement.localBasis().size() == coefficients.size());
 
     for (size_t i=0; i<coefficients.size(); i++)
-      translationCoefficients_[i] = coefficients[i].r;
+      translationCoefficients_[i] = coefficients[i][_0].globalCoordinates();
 
     std::vector<Rotation<field_type,3> > orientationCoefficients(coefficients.size());
     for (size_t i=0; i<coefficients.size(); i++)
-      orientationCoefficients[i] = coefficients[i].q;
+      orientationCoefficients[i] = coefficients[i][_1];
 
     orientationFEFunction_ = std::unique_ptr<LocalGeodesicFEFunction<dim,ctype,LocalFiniteElement,Rotation<field_type,3> > > (new LocalGeodesicFEFunction<dim,ctype,LocalFiniteElement,Rotation<field_type,3> >(localFiniteElement,orientationCoefficients));
 
@@ -618,17 +620,19 @@ public:
   /** \brief Evaluate the function */
   TargetSpace evaluate(const Dune::FieldVector<ctype, dim>& local) const
   {
+    using namespace Dune::Indices;
+
     TargetSpace result;
 
     // Evaluate the weighting factors---these are the Lagrangian shape function values at 'local'
     std::vector<Dune::FieldVector<ctype,1> > w;
     localFiniteElement_.localBasis().evaluateFunction(local,w);
 
-    result.r = 0;
+    result[_0] = Dune::FieldVector<field_type,3>(0.0);
     for (size_t i=0; i<w.size(); i++)
-      result.r.axpy(w[i][0], translationCoefficients_[i]);
+      result[_0].globalCoordinates().axpy(w[i][0], translationCoefficients_[i]);
 
-    result.q = orientationFEFunction_->evaluate(local);
+    result[_1] = orientationFEFunction_->evaluate(local);
     return result;
   }
 
@@ -661,6 +665,8 @@ public:
   DerivativeType evaluateDerivative(const Dune::FieldVector<ctype, dim>& local,
                                     const TargetSpace& q) const
   {
+    using namespace Dune::Indices;
+
     DerivativeType result(0);
 
     // get translation part
@@ -672,7 +678,7 @@ public:
         result[j].axpy(translationCoefficients_[i][j], sfDer[i][0]);
 
     // get orientation part
-    Dune::FieldMatrix<field_type,4,dim> qResult = orientationFEFunction_->evaluateDerivative(local,q.q);
+    Dune::FieldMatrix<field_type,4,dim> qResult = orientationFEFunction_->evaluateDerivative(local,q[_1]);
     for (int i=0; i<4; i++)
       for (int j=0; j<dim; j++)
         result[3+i][j] = qResult[i][j];
@@ -777,9 +783,7 @@ private:
    */
   const LocalFiniteElement& localFiniteElement_;
 
-  // The two factors of a RigidBodyMotion
-  //LocalGeodesicFEFunction<dim,ctype,RealTuple<3> > translationFEFunction_;
-
+  // Coefficients for the two factors of the product manifold
   std::vector<Dune::FieldVector<field_type,3> > translationCoefficients_;
 
   std::unique_ptr<LocalGeodesicFEFunction<dim,ctype,LocalFiniteElement,Rotation<field_type,3> > > orientationFEFunction_;
diff --git a/dune/gfe/localprojectedfefunction.hh b/dune/gfe/localprojectedfefunction.hh
index 46acb95ad1710e5fa1136c5dff9d7be7b2082b95..5f1a0c49d8ea8493529d82bf6b76fcb6d7045955 100644
--- a/dune/gfe/localprojectedfefunction.hh
+++ b/dune/gfe/localprojectedfefunction.hh
@@ -11,7 +11,7 @@
 #include <dune/gfe/linearalgebra.hh>
 #include <dune/gfe/polardecomposition.hh>
 #include <dune/gfe/spaces/realtuple.hh>
-#include <dune/gfe/spaces/rigidbodymotion.hh>
+#include <dune/gfe/spaces/productmanifold.hh>
 #include <dune/gfe/spaces/rotation.hh>
 
 namespace Dune {
@@ -414,10 +414,10 @@ namespace Dune {
      * \tparam LocalFiniteElement A Lagrangian finite element whose shape functions define the interpolation weights
      */
     template <int dim, class ctype, class LocalFiniteElement, class field_type>
-    class LocalProjectedFEFunction<dim,ctype,LocalFiniteElement,RigidBodyMotion<field_type,3> >
+    class LocalProjectedFEFunction<dim,ctype,LocalFiniteElement,ProductManifold<RealTuple<field_type,3>,Rotation<field_type,3> > >
     {
     public:
-      typedef RigidBodyMotion<field_type,3> TargetSpace;
+      using TargetSpace = ProductManifold<RealTuple<field_type,3>,Rotation<field_type,3> >;
     private:
       typedef typename TargetSpace::ctype RT;
 
@@ -441,13 +441,14 @@ namespace Dune {
         translationCoefficients_(coefficients.size())
       {
         assert(localFiniteElement.localBasis().size() == coefficients.size());
+        using namespace Dune::Indices;
 
         for (size_t i=0; i<coefficients.size(); i++)
-          translationCoefficients_[i] = coefficients[i].r;
+          translationCoefficients_[i] = coefficients[i][_0].globalCoordinates();
 
         std::vector<Rotation<field_type,3> > orientationCoefficients(coefficients.size());
         for (size_t i=0; i<coefficients.size(); i++)
-          orientationCoefficients[i] = coefficients[i].q;
+          orientationCoefficients[i] = coefficients[i][_1];
 
         orientationFunction_ = std::make_unique<LocalProjectedFEFunction<dim,ctype,LocalFiniteElement,Rotation<field_type,3> > > (localFiniteElement,orientationCoefficients);
       }
@@ -474,17 +475,19 @@ namespace Dune {
       /** \brief Evaluate the function */
       TargetSpace evaluate(const Dune::FieldVector<ctype, dim>& local) const
       {
-        RigidBodyMotion<field_type,3> result;
+        using namespace Dune::Indices;
+
+        TargetSpace result;
 
         // Evaluate the weighting factors---these are the Lagrangian shape function values at 'local'
         std::vector<Dune::FieldVector<ctype,1> > w;
         localFiniteElement_.localBasis().evaluateFunction(local,w);
 
-        result.r = 0;
+        result[_0] = FieldVector<field_type,3>(0.0);
         for (size_t i=0; i<w.size(); i++)
-          result.r.axpy(w[i][0], translationCoefficients_[i]);
+          result[_0].globalCoordinates().axpy(w[i][0], translationCoefficients_[i]);
 
-        result.q = orientationFunction_->evaluate(local);
+        result[_1] = orientationFunction_->evaluate(local);
 
         return result;
       }
@@ -506,6 +509,8 @@ namespace Dune {
       DerivativeType evaluateDerivative(const Dune::FieldVector<ctype, dim>& local,
                                         const TargetSpace& q) const
       {
+        using namespace Dune::Indices;
+
         DerivativeType result(0);
 
         // get translation part
@@ -517,7 +522,7 @@ namespace Dune {
             result[j].axpy(translationCoefficients_[i][j], sfDer[i][0]);
 
         // get orientation part
-        Dune::FieldMatrix<field_type,4,dim> qResult = orientationFunction_->evaluateDerivative(local,q.q);
+        Dune::FieldMatrix<field_type,4,dim> qResult = orientationFunction_->evaluateDerivative(local,q[_1]);
 
         for (int i=0; i<4; i++)
           for (int j=0; j<dim; j++)
diff --git a/dune/gfe/rodfactory.hh b/dune/gfe/rodfactory.hh
index 3f27c7d544db4b507a7776de58596695abc401a2..bea34db0b847c2aa602a59babb5e5c053d1662d5 100644
--- a/dune/gfe/rodfactory.hh
+++ b/dune/gfe/rodfactory.hh
@@ -7,11 +7,13 @@
 
 #include <dune/matrix-vector/crossproduct.hh>
 
-#include <dune/gfe/rigidbodymotion.hh>
 #include <dune/gfe/localgeodesicfefunction.hh>
 
 #include <dune/gfe/rodassembler.hh>
 #include <dune/gfe/riemanniantrsolver.hh>
+#include <dune/gfe/spaces/productmanifold.hh>
+#include <dune/gfe/spaces/realtuple.hh>
+#include <dune/gfe/spaces/rotation.hh>
 
 /** \brief A factory class that implements various ways to create rod configurations
  */
@@ -33,7 +35,7 @@ public:
      \param[in] n The number of vertices
    */
   template <int dim>
-  void create(std::vector<RigidBodyMotion<double,dim> >& rod,
+  void create(std::vector<Dune::GFE::ProductManifold<RealTuple<double,dim>,Rotation<double,dim> > >& rod,
               const Dune::FieldVector<double,3>& beginning, const Dune::FieldVector<double,3>& end)
   {
     // Compute the correct orientation
@@ -54,7 +56,9 @@ public:
       orientation = Rotation<double,3>(axis, angle);
 
     // Set the values
-    create(rod, RigidBodyMotion<double,dim>(beginning,orientation), RigidBodyMotion<double,dim>(end,orientation));
+    create(rod,
+           Dune::GFE::ProductManifold<RealTuple<double,dim>,Rotation<double,dim> > (beginning,orientation),
+           Dune::GFE::ProductManifold<RealTuple<double,dim>,Rotation<double,dim> > (end,orientation));
   }
 
 
@@ -63,9 +67,9 @@ public:
      \param[out] rod The new rod
    */
   template <int spaceDim>
-  void create(std::vector<RigidBodyMotion<double,spaceDim> >& rod,
-              const RigidBodyMotion<double,spaceDim>& beginning,
-              const RigidBodyMotion<double,spaceDim>& end)
+  void create(std::vector<Dune::GFE::ProductManifold<RealTuple<double,spaceDim>,Rotation<double,spaceDim> >  >& rod,
+              const Dune::GFE::ProductManifold<RealTuple<double,spaceDim>,Rotation<double,spaceDim> > & beginning,
+              const Dune::GFE::ProductManifold<RealTuple<double,spaceDim>,Rotation<double,spaceDim> > & end)
   {
 
     static const int dim = GridView::dimension;  // de facto: 1
@@ -106,8 +110,8 @@ public:
      \param[out] rod The new rod
    */
   template <int spaceDim>
-  void create(std::vector<RigidBodyMotion<double,spaceDim> >& rod,
-              const RigidBodyMotion<double,spaceDim>& value)
+  void create(std::vector<Dune::GFE::ProductManifold<RealTuple<double,spaceDim>,Rotation<double,spaceDim> >  >& rod,
+              const Dune::GFE::ProductManifold<RealTuple<double,spaceDim>,Rotation<double,spaceDim> > & value)
   {
     rod.resize(gridView_.size(1));
     std::fill(rod.begin(), rod.end(), value);
@@ -119,7 +123,7 @@ public:
       \param[in,out] rod The new rod
    */
   template <int spaceDim>
-  void create(std::vector<RigidBodyMotion<double,spaceDim> >& rod)
+  void create(std::vector<Dune::GFE::ProductManifold<RealTuple<double,spaceDim>,Rotation<double,spaceDim> > >& rod)
   {
     static const int dim = GridView::dimension;      // de facto: 1
     assert(gridView_.size(dim)==rod.size());
@@ -133,7 +137,7 @@ public:
 
     double min =  std::numeric_limits<double>::max();
     double max = -std::numeric_limits<double>::max();
-    RigidBodyMotion<double,spaceDim> beginning, end;
+    Dune::GFE::ProductManifold<RealTuple<double,spaceDim>,Rotation<double,spaceDim> > beginning, end;
 
     for (; vIt != vEndIt; ++vIt) {
       if (vIt->geometry().corner(0)[0] < min) {
@@ -174,10 +178,10 @@ public:
      \param[out] rod The new rod
    */
   template <int spaceDim>
-  void create(std::vector<RigidBodyMotion<double,spaceDim> >& rod,
+  void create(std::vector<Dune::GFE::ProductManifold<RealTuple<double,spaceDim>,Rotation<double,spaceDim> > >& rod,
               double radius, double E, double nu,
-              const RigidBodyMotion<double,spaceDim>& beginning,
-              const RigidBodyMotion<double,spaceDim>& end)
+              const Dune::GFE::ProductManifold<RealTuple<double,spaceDim>,Rotation<double,spaceDim> > & beginning,
+              const Dune::GFE::ProductManifold<RealTuple<double,spaceDim>,Rotation<double,spaceDim> > & end)
   {
 
     // Make Dirichlet bitfields for the rods as well
@@ -207,7 +211,7 @@ public:
     rod.back() = end;
 
     // Trust--Region solver
-    RiemannianTrustRegionSolver<RodP1Basis, RigidBodyMotion<double,spaceDim> > rodSolver;
+    RiemannianTrustRegionSolver<RodP1Basis, Dune::GFE::ProductManifold<RealTuple<double,spaceDim>,Rotation<double,spaceDim> > > rodSolver;
     rodSolver.setup(gridView_.grid(), &assembler, rod,
                     rodDirichletNodes,
                     1e-10, 100, // TR tolerance and iterations
diff --git a/dune/gfe/spaces/CMakeLists.txt b/dune/gfe/spaces/CMakeLists.txt
index f158d6058cc5376c7eafc6889e595d9595678227..bb85104de0a572b451e47267359b0047bc58db45 100644
--- a/dune/gfe/spaces/CMakeLists.txt
+++ b/dune/gfe/spaces/CMakeLists.txt
@@ -5,7 +5,6 @@ install(FILES
         productmanifold.hh
         quaternion.hh
         realtuple.hh
-        rigidbodymotion.hh
         rotation.hh
         unitvector.hh
         DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/dune/gfe/spaces)
diff --git a/dune/gfe/spaces/rigidbodymotion.hh b/dune/gfe/spaces/rigidbodymotion.hh
deleted file mode 100644
index e284c18f904f380184bca94dbf64cbab861ca35a..0000000000000000000000000000000000000000
--- a/dune/gfe/spaces/rigidbodymotion.hh
+++ /dev/null
@@ -1,431 +0,0 @@
-#ifndef DUNE_GFE_SPACES_RIGIDBODYMOTION_HH
-#define DUNE_GFE_SPACES_RIGIDBODYMOTION_HH
-
-#include <dune/common/fvector.hh>
-
-#include <dune/gfe/spaces/realtuple.hh>
-#include <dune/gfe/spaces/rotation.hh>
-
-/** \brief A rigid-body motion in R^N, i.e., a member of SE(N) */
-template <class T, int N>
-struct RigidBodyMotion
-{
-public:
-
-  /** \brief Dimension of manifold */
-  static const int dim = N + Rotation<T,N>::dim;
-
-  /** \brief Dimension of the embedding space */
-  static const int embeddedDim = N + Rotation<T,N>::embeddedDim;
-
-  /** \brief Type of an infinitesimal rigid body motion */
-  typedef Dune::FieldVector<T, dim> TangentVector;
-
-  /** \brief Type of an infinitesimal rigid body motion */
-  typedef Dune::FieldVector<T, embeddedDim> EmbeddedTangentVector;
-
-  /** \brief The type used for coordinates */
-  typedef T ctype;
-  typedef T field_type;
-
-  /** \brief The type used for global coordinates */
-  typedef Dune::FieldVector<T,embeddedDim> CoordinateType;
-
-  /** \brief The global convexity radius of the rigid body motions */
-  static constexpr double convexityRadius = Rotation<T,N>::convexityRadius;
-
-  /** \brief Default constructor */
-  RigidBodyMotion()
-  {}
-
-  /** \brief Constructor from a translation and a rotation */
-  RigidBodyMotion(const Dune::FieldVector<ctype, N>& translation,
-                  const Rotation<ctype,N>& rotation)
-    : r(translation), q(rotation)
-  {}
-
-  RigidBodyMotion(const CoordinateType& globalCoordinates)
-  {
-    for (int i=0; i<N; i++)
-      r[i] = globalCoordinates[i];
-
-    for (int i=N; i<embeddedDim; i++)
-      q[i-N] = globalCoordinates[i];
-
-    // Turn this into a unit quaternion if it isn't already
-    q.normalize();
-  }
-
-  /** \brief Assignment from RigidBodyMotion with different type -- used for automatic differentiation with ADOL-C */
-  template <class T2>
-  RigidBodyMotion& operator <<= (const RigidBodyMotion<T2,N>& other) {
-    for (int i=0; i<N; i++)
-      r[i] <<= other.r[i];
-    q <<= other.q;
-    return *this;
-  }
-
-  /** \brief Rebind the RigidBodyMotion to another coordinate type */
-  template<class U>
-  struct rebind
-  {
-    typedef RigidBodyMotion<U,N> other;
-  };
-
-  /** \brief The exponential map from a given point $p \in SE(d)$.
-
-     Why the template parameter?  Well, it should work with both TangentVector and EmbeddedTangentVector.
-     In general these differ and we could just have two exp methods.  However in 2d they do _not_ differ,
-     and then the compiler complains about having two methods with the same signature.
-   */
-  template <class TVector>
-  static RigidBodyMotion<ctype,N> exp(const RigidBodyMotion<ctype,N>& p, const TVector& v) {
-
-    RigidBodyMotion<ctype,N> result;
-
-    // Add translational correction
-    for (int i=0; i<N; i++)
-      result.r[i] = p.r[i] + v[i];
-
-    // Add rotational correction
-    typedef typename std::conditional<std::is_same<TVector,TangentVector>::value,
-        typename Rotation<ctype,N>::TangentVector,
-        typename Rotation<ctype,N>::EmbeddedTangentVector>::type RotationTangentVector;
-    RotationTangentVector qCorr;
-    for (int i=0; i<RotationTangentVector::dimension; i++)
-      qCorr[i] = v[N+i];
-
-    result.q = Rotation<ctype,N>::exp(p.q, qCorr);
-    return result;
-  }
-
-  /** \brief Compute difference vector from a to b on the tangent space of a */
-  static EmbeddedTangentVector log(const RigidBodyMotion<ctype,N>& a,
-                                   const RigidBodyMotion<ctype,N>& b)
-  {
-    EmbeddedTangentVector result;
-
-    // Usual linear difference
-    for (int i=0; i<N; i++)
-      result[i] = b.r[i] - a.r[i];
-
-    // Subtract orientations on the tangent space of 'a'
-    typename Rotation<ctype,N>::EmbeddedTangentVector v = Rotation<ctype,N>::log(a.q, b.q);
-
-    // Compute difference on T_a SO(3)
-    for (int i=0; i<Rotation<ctype,N>::EmbeddedTangentVector::dimension; i++)
-      result[i+N] = v[i];
-
-    return result;
-  }
-
-  /** \brief Compute geodesic distance from a to b */
-  static T distance(const RigidBodyMotion<ctype,N>& a, const RigidBodyMotion<ctype,N>& b) {
-
-    T euclideanDistanceSquared = (a.r - b.r).two_norm2();
-
-    T rotationDistance = Rotation<ctype,N>::distance(a.q, b.q);
-
-    return std::sqrt(euclideanDistanceSquared + rotationDistance*rotationDistance);
-  }
-
-  /** \brief Compute difference vector from a to b on the tangent space of a
-
-   * \warning The method is buggy!  See https://gitlab.mn.tu-dresden.de/osander/dune-gfe/-/merge_requests/2
-   * \deprecated Use the log method instead!
-   */
-  [[deprecated("Use RigidBodyMotion::log instead of RigidBodyMotion::difference!")]]
-  static TangentVector difference(const RigidBodyMotion<ctype,N>& a,
-                                  const RigidBodyMotion<ctype,N>& b) {
-
-    TangentVector result;
-
-    // Usual linear difference
-    for (int i=0; i<N; i++)
-      result[i] = a.r[i] - b.r[i];
-
-    // Subtract orientations on the tangent space of 'a'
-    typename Rotation<ctype,N>::TangentVector v = Rotation<ctype,N>::difference(a.q, b.q).axial();
-
-    // Compute difference on T_a SO(3)
-    for (int i=0; i<Rotation<ctype,N>::TangentVector::dimension; i++)
-      result[i+N] = v[i];
-
-    return result;
-  }
-
-  static EmbeddedTangentVector derivativeOfDistanceSquaredWRTSecondArgument(const RigidBodyMotion<ctype,N>& a,
-                                                                            const RigidBodyMotion<ctype,N>& b) {
-
-    // linear part
-    Dune::FieldVector<ctype,N> linearDerivative = a.r;
-    linearDerivative -= b.r;
-    linearDerivative *= -2;
-
-    // rotation part
-    typename Rotation<ctype,N>::EmbeddedTangentVector rotationDerivative
-      = Rotation<ctype,N>::derivativeOfDistanceSquaredWRTSecondArgument(a.q, b.q);
-
-    return concat(linearDerivative, rotationDerivative);
-  }
-
-  /** \brief Compute the Hessian of the squared distance function keeping the first argument fixed */
-  static Dune::SymmetricMatrix<T,embeddedDim> secondDerivativeOfDistanceSquaredWRTSecondArgument(const RigidBodyMotion<ctype,N> & p, const RigidBodyMotion<ctype,N> & q)
-  {
-    Dune::SymmetricMatrix<T,embeddedDim> result;
-
-    // The linear part
-    Dune::SymmetricMatrix<T,N> linearPart = RealTuple<T,N>::secondDerivativeOfDistanceSquaredWRTSecondArgument(p.r,q.r);
-    for (int i=0; i<N; i++)
-      for (int j=0; j<=i; j++)
-        result(i,j) = linearPart(i,j);
-
-    // The rotation part
-    Dune::SymmetricMatrix<T,Rotation<T,N>::embeddedDim> rotationPart
-      = Rotation<ctype,N>::secondDerivativeOfDistanceSquaredWRTSecondArgument(p.q,q.q);
-    for (int i=0; i<Rotation<T,N>::embeddedDim; i++)
-    {
-      for (int j=0; j<N; j++)
-        result(N+i,j) = 0;
-      for (int j=0; j<=i; j++)
-        result(N+i,N+j) = rotationPart(i,j);
-    }
-
-    return result;
-  }
-
-  /** \brief Compute the mixed second derivate \partial d^2 / \partial da db
-
-     Unlike the distance itself the squared distance is differentiable at zero
-   */
-  static Dune::FieldMatrix<T,embeddedDim,embeddedDim> secondDerivativeOfDistanceSquaredWRTFirstAndSecondArgument(const RigidBodyMotion<ctype,N> & p, const RigidBodyMotion<ctype,N> & q)
-  {
-    Dune::FieldMatrix<T,embeddedDim,embeddedDim> result(0);
-
-    // The linear part
-    Dune::FieldMatrix<T,N,N> linearPart = RealTuple<T,N>::secondDerivativeOfDistanceSquaredWRTFirstAndSecondArgument(p.r,q.r);
-    for (int i=0; i<N; i++)
-      for (int j=0; j<N; j++)
-        result[i][j] = linearPart[i][j];
-
-    // The rotation part
-    Dune::FieldMatrix<T,Rotation<T,N>::embeddedDim,Rotation<T,N>::embeddedDim> rotationPart
-      = Rotation<ctype,N>::secondDerivativeOfDistanceSquaredWRTFirstAndSecondArgument(p.q,q.q);
-    for (int i=0; i<Rotation<T,N>::embeddedDim; i++)
-      for (int j=0; j<Rotation<T,N>::embeddedDim; j++)
-        result[N+i][N+j] = rotationPart[i][j];
-
-    return result;
-  }
-
-  /** \brief Compute the third derivative \partial d^3 / \partial dq^3
-
-     Unlike the distance itself the squared distance is differentiable at zero
-   */
-  static Tensor3<T,embeddedDim,embeddedDim,embeddedDim> thirdDerivativeOfDistanceSquaredWRTSecondArgument(const RigidBodyMotion<ctype,N> & p, const RigidBodyMotion<ctype,N> & q)
-  {
-    Tensor3<T,embeddedDim,embeddedDim,embeddedDim> result(0);
-
-    // The linear part
-    Tensor3<T,N,N,N> linearPart = RealTuple<T,N>::thirdDerivativeOfDistanceSquaredWRTSecondArgument(p.r,q.r);
-    for (int i=0; i<N; i++)
-      for (int j=0; j<N; j++)
-        for (int k=0; k<N; k++)
-          result[i][j][k] = linearPart[i][j][k];
-
-    // The rotation part
-    Tensor3<T,Rotation<T,N>::embeddedDim,Rotation<T,N>::embeddedDim,Rotation<T,N>::embeddedDim> rotationPart
-      = Rotation<ctype,N>::thirdDerivativeOfDistanceSquaredWRTSecondArgument(p.q,q.q);
-
-    for (int i=0; i<Rotation<T,N>::embeddedDim; i++)
-      for (int j=0; j<Rotation<T,N>::embeddedDim; j++)
-        for (int k=0; k<Rotation<T,N>::embeddedDim; k++)
-          result[N+i][N+j][N+k] = rotationPart[i][j][k];
-
-    return result;
-  }
-
-  /** \brief Compute the mixed third derivative \partial d^3 / \partial da db^2
-
-     Unlike the distance itself the squared distance is differentiable at zero
-   */
-  static Tensor3<T,embeddedDim,embeddedDim,embeddedDim> thirdDerivativeOfDistanceSquaredWRTFirst1AndSecond2Argument(const RigidBodyMotion<ctype,N> & p, const RigidBodyMotion<ctype,N> & q)
-  {
-    Tensor3<T,embeddedDim,embeddedDim,embeddedDim> result(0);
-
-    // The linear part
-    Tensor3<T,N,N,N> linearPart = RealTuple<T,N>::thirdDerivativeOfDistanceSquaredWRTFirst1AndSecond2Argument(p.r,q.r);
-    for (int i=0; i<N; i++)
-      for (int j=0; j<N; j++)
-        for (int k=0; k<N; k++)
-          result[i][j][k] = linearPart[i][j][k];
-
-    // The rotation part
-    Tensor3<T,Rotation<T,N>::embeddedDim,Rotation<T,N>::embeddedDim,Rotation<T,N>::embeddedDim> rotationPart = Rotation<ctype,N>::thirdDerivativeOfDistanceSquaredWRTFirst1AndSecond2Argument(p.q,q.q);
-    for (int i=0; i<Rotation<T,N>::embeddedDim; i++)
-      for (int j=0; j<Rotation<T,N>::embeddedDim; j++)
-        for (int k=0; k<Rotation<T,N>::embeddedDim; k++)
-          result[N+i][N+j][N+k] = rotationPart[i][j][k];
-
-    return result;
-  }
-
-
-
-  /** \brief Project tangent vector of R^n onto the tangent space */
-  EmbeddedTangentVector projectOntoTangentSpace(const EmbeddedTangentVector& v) const {
-    EmbeddedTangentVector result;
-
-    // translation part
-    for (int i=0; i<N; i++)
-      result[i] = v[i];
-
-    // rotation part
-    typename Rotation<T,N>::EmbeddedTangentVector rotV;
-    for (int i=0; i<Rotation<T,N>::embeddedDim; i++)
-      rotV[i] = v[i+N];
-
-    rotV = q.projectOntoTangentSpace(rotV);
-
-    for (int i=0; i<Rotation<T,N>::embeddedDim; i++)
-      result[i+N] = rotV[i];
-
-    return result;
-  }
-
-  /** \brief Project tangent vector of R^n onto the normal space space */
-  EmbeddedTangentVector projectOntoNormalSpace(const EmbeddedTangentVector& v) const {
-
-    EmbeddedTangentVector result;
-
-    // translation part
-    for (int i=0; i<N; i++)
-      result[i] = 0;
-
-    // rotation part
-    T sp = 0;
-    for (int i=0; i<Rotation<T,N>::embeddedDim; i++)
-      sp += v[i+N] * q[i];
-
-    for (int i=0; i<Rotation<T,N>::embeddedDim; i++)
-      result[i+N] = sp * q[i];
-
-    return result;
-  }
-
-  /** \brief Transform tangent vectors from quaternion representation to matrix representation
-   *
-   * This class represents rotations as unit quaternions, and therefore variations of rotations
-   * (i.e., tangent vector) are represented in quaternion space, too.  However, some applications
-   * require the tangent vectors as matrices. To obtain matrix coordinates we use the
-   * chain rule, which means that we have to multiply the given derivative with
-   * the derivative of the embedding of the unit quaternion into the space of 3x3 matrices.
-   * This second derivative is almost given by the method getFirstDerivativesOfDirectors.
-   * However, since the directors of a given unit quaternion are the _columns_ of the
-   * corresponding orthogonal matrix, we need to invert the i and j indices
-   *
-   * As a typical GFE assembler will require this for several tangent vectors at once,
-   * the implementation here is a vector one: It allows to treat several tangent vectors
-   * together, which have to come as the columns of the `derivative` parameter.
-   *
-   * So, if I am not mistaken, result[i][j][k] contains \partial R_ij / \partial k
-   *
-   * \param derivative Tangent vector in quaternion coordinates
-   * \returns DR Tangent vector in matrix coordinates
-   */
-  template <int blocksize>
-  Tensor3<T,3,3,blocksize> quaternionTangentToMatrixTangent(const Dune::FieldMatrix<T,7,blocksize>& derivative) const
-  {
-    Tensor3<T,3,3,blocksize> result = T(0);
-
-    Tensor3<T,3 , 3, 4> dd_dq;
-    q.getFirstDerivativesOfDirectors(dd_dq);
-
-    for (int i=0; i<3; i++)
-      for (int j=0; j<3; j++)
-        for (int k=0; k<blocksize; k++)
-          for (int l=0; l<4; l++)
-            result[i][j][k] += dd_dq[j][i][l] * derivative[l+3][k];
-
-    return result;
-  }
-
-  /** \brief The Weingarten map */
-  EmbeddedTangentVector weingarten(const EmbeddedTangentVector& z, const EmbeddedTangentVector& v) const {
-
-    EmbeddedTangentVector result;
-
-    // translation part: nothing, the space is flat
-    for (int i=0; i<N; i++)
-      result[i] = 0;
-
-    // rotation part
-    T sp = 0;
-    for (int i=0; i<Rotation<T,N>::embeddedDim; i++)
-      sp += v[i+N] * q[i];
-
-    for (int i=0; i<Rotation<T,N>::embeddedDim; i++)
-      result[i+N] = -sp * z[i+N];
-
-    return result;
-  }
-
-  /** \brief Compute an orthonormal basis of the tangent space of SE(3).
-
-     This basis may not be globally continuous.
-   */
-  Dune::FieldMatrix<T,dim,embeddedDim> orthonormalFrame() const {
-    Dune::FieldMatrix<T,dim,embeddedDim> result(0);
-
-    // Get the R^d part
-    for (int i=0; i<N; i++)
-      result[i][i] = 1;
-
-    Dune::FieldMatrix<T,Rotation<T,N>::dim,Rotation<T,N>::embeddedDim> SO3Part = q.orthonormalFrame();
-
-    for (int i=0; i<Rotation<T,N>::dim; i++)
-      for (int j=0; j<Rotation<T,N>::embeddedDim; j++)
-        result[N+i][N+j] = SO3Part[i][j];
-
-    return result;
-  }
-
-  /** \brief The global coordinates, if you really want them */
-  CoordinateType globalCoordinates() const {
-    return concat(r, q.globalCoordinates());
-  }
-
-
-
-  // Translational part
-  Dune::FieldVector<ctype, N> r;
-
-  // Rotational part
-  Rotation<ctype,N> q;
-
-private:
-
-  /** \brief Concatenate two FieldVectors */
-  template <int NN, int M>
-  static Dune::FieldVector<ctype,NN+M> concat(const Dune::FieldVector<ctype,NN>& a,
-                                              const Dune::FieldVector<ctype,M>& b)
-  {
-    Dune::FieldVector<ctype,NN+M> result;
-    for (int i=0; i<NN; i++)
-      result[i] = a[i];
-    for (int i=0; i<M; i++)
-      result[i+NN] = b[i];
-    return result;
-  }
-
-};
-
-//! Send configuration to output stream
-template <int N, class ctype>
-std::ostream& operator<< (std::ostream& s, const RigidBodyMotion<ctype,N>& c)
-{
-  s << "(" << c.r << ")  (" << c.q << ")";
-  return s;
-}
-
-#endif
diff --git a/src/compute-disc-error.cc b/src/compute-disc-error.cc
index f5b5b2776560481484d2d83b5d5025de0dcc3afb..db771c377dc1ff0cfdc8e348a519b8a27a9567fd 100644
--- a/src/compute-disc-error.cc
+++ b/src/compute-disc-error.cc
@@ -222,7 +222,7 @@ void measureDiscreteEOC(const GridView gridView,
   auto localReferenceSolution = localFunction(referenceSolution);
   auto localNumericalSolution = localFunction(numericalSolution);
 
-  if (std::is_same<TargetSpace,RigidBodyMotion<double,3> >::value)
+  if (std::is_same<TargetSpace,GFE::ProductManifold<RealTuple<double,3>,Rotation<double,3> > >::value)
   {
     double deformationL2ErrorSquared = 0;
     double orientationL2ErrorSquared = 0;
@@ -852,9 +852,9 @@ int main (int argc, char *argv[]) try
                                                parameterSet);
     } else if (targetSpace=="RigidBodyMotion")
     {
-      measureEOC<GridType,RigidBodyMotion<double,2> >(grid,
-                                                      referenceGrid,
-                                                      parameterSet);
+      measureEOC<GridType,GFE::ProductManifold<RealTuple<double,2>,Rotation<double,2> > >(grid,
+                                                                                          referenceGrid,
+                                                                                          parameterSet);
 #endif
     } else
       DUNE_THROW(NotImplemented, "Target space '" << targetSpace << "' is not implemented");
@@ -878,9 +878,9 @@ int main (int argc, char *argv[]) try
                                                parameterSet);
     } else if (targetSpace=="RigidBodyMotion")
     {
-      measureEOC<GridType,RigidBodyMotion<double,3> >(grid,
-                                                      referenceGrid,
-                                                      parameterSet);
+      measureEOC<GridType,GFE::ProductManifold<RealTuple<double,3>,Rotation<double,3> > >(grid,
+                                                                                          referenceGrid,
+                                                                                          parameterSet);
     } else
       DUNE_THROW(NotImplemented, "Target space '" << targetSpace << "' is not implemented");
     break;
@@ -904,9 +904,9 @@ int main (int argc, char *argv[]) try
                                                parameterSet);
     } else if (targetSpace=="RigidBodyMotion")
     {
-      measureEOC<GridType,RigidBodyMotion<double,4> >(grid,
-                                                      referenceGrid,
-                                                      parameterSet);
+      measureEOC<GridType,GFE::ProductManifold<RealTuple<double,4>,Rotation<double,4> > >(grid,
+                                                                                          referenceGrid,
+                                                                                          parameterSet);
 #endif
     } else
       DUNE_THROW(NotImplemented, "Target space '" << targetSpace << "' is not implemented");
diff --git a/src/cosserat-continuum.cc b/src/cosserat-continuum.cc
index c81a9192ca8a3a29e7d5ff7cdf98ba5c43c4c294..8906f52794c4407784e626f6f220a299e0e1d8e8 100644
--- a/src/cosserat-continuum.cc
+++ b/src/cosserat-continuum.cc
@@ -70,7 +70,9 @@
 #include <dune/gfe/assemblers/geodesicfeassemblerwrapper.hh>
 #include <dune/gfe/riemannianpnsolver.hh>
 #include <dune/gfe/riemanniantrsolver.hh>
-#include <dune/gfe/spaces/rigidbodymotion.hh>
+#include <dune/gfe/spaces/productmanifold.hh>
+#include <dune/gfe/spaces/realtuple.hh>
+#include <dune/gfe/spaces/rotation.hh>
 #endif
 
 #if HAVE_DUNE_VTK
@@ -80,6 +82,8 @@
 #include <dune/gmsh4/gmsh4reader.hh>
 #include <dune/gmsh4/gridcreators/lagrangegridcreator.hh>
 
+using namespace Dune;
+
 // grid dimension
 const int dim = GRID_DIM;
 const int dimworld = WORLD_DIM;
@@ -94,10 +98,9 @@ const int rotationOrder = GFE_ORDER;
 static_assert(displacementOrder==rotationOrder, "displacement and rotation order do not match!");
 
 // Image space of the geodesic fe functions
-using TargetSpace = RigidBodyMotion<double, 3>;
+using TargetSpace = GFE::ProductManifold<RealTuple<double,3>,Rotation<double,3> >;
 #endif
 
-using namespace Dune;
 
 int main (int argc, char *argv[]) try
 {
@@ -381,8 +384,8 @@ int main (int argc, char *argv[]) try
 
     for (size_t i=0; i<x.size(); i++) {
       auto vTargetSpace = TargetSpace(v[i]);
-      x[_0][i] = vTargetSpace.r;
-      x[_1][i] = vTargetSpace.q;
+      x[_0][i] = vTargetSpace[_0];
+      x[_1][i] = vTargetSpace[_1];
     }
   }
 #endif
@@ -523,16 +526,16 @@ int main (int argc, char *argv[]) try
       x = solver.getSol();
 #else
       //The MixedRiemannianTrustRegionSolver can treat the Displacement and Orientation Space as separate ones
-      //The RiemannianTrustRegionSolver can only treat the Displacement and Rotation together in a RigidBodyMotion
-      //Therefore, x and the dirichletDofs are converted to a RigidBodyMotion structure, as well as the Hessian and Gradient that are returned by the assembler
+      //The RiemannianTrustRegionSolver can only treat the Displacement and Rotation together in a ProductManifold.
+      //Therefore, x and the dirichletDofs are converted to a ProductManifold structure, as well as the Hessian and Gradient that are returned by the assembler
       std::vector<TargetSpace> xTargetSpace(compositeBasis.size({0}));
       BitSetVector<TargetSpace::TangentVector::dimension> dirichletDofsTargetSpace(compositeBasis.size({0}), false);
       for (std::size_t i = 0; i < compositeBasis.size({0}); i++) {
         for (int j = 0; j < 3; j ++) {       // Displacement part
-          xTargetSpace[i].r[j] = x[_0][i][j];
+          xTargetSpace[i][_0].globalCoordinates()[j] = x[_0][i][j];
           dirichletDofsTargetSpace[i][j] = deformationDirichletDofs[i][j];
         }
-        xTargetSpace[i].q = x[_1][i];       // Rotation part
+        xTargetSpace[i][_1] = x[_1][i];       // Rotation part
         for (int j = 3; j < TargetSpace::TangentVector::dimension; j ++)
           dirichletDofsTargetSpace[i][j] = orientationDirichletDofs[i][j-3];
       }
@@ -575,8 +578,8 @@ int main (int argc, char *argv[]) try
         xTargetSpace = solver.getSol();
       }
       for (std::size_t i = 0; i < xTargetSpace.size(); i++) {
-        x[_0][i] = xTargetSpace[i].r;
-        x[_1][i] = xTargetSpace[i].q;
+        x[_0][i] = xTargetSpace[i][_0];
+        x[_1][i] = xTargetSpace[i][_1];
       }
 #endif
     } else {     //dim != dimworld
@@ -623,16 +626,16 @@ int main (int argc, char *argv[]) try
       x = solver.getSol();
 #else
       //The MixedRiemannianTrustRegionSolver can treat the Displacement and Orientation Space as separate ones
-      //The RiemannianTrustRegionSolver can only treat the Displacement and Rotation together in a RigidBodyMotion
-      //Therefore, x and the dirichletDofs are converted to a RigidBodyMotion structure, as well as the Hessian and Gradient that are returned by the assembler
+      //The RiemannianTrustRegionSolver can only treat the Displacement and Rotation together in a ProductManifold.
+      //Therefore, x and the dirichletDofs are converted to a ProductManifold structure, as well as the Hessian and Gradient that are returned by the assembler
       std::vector<TargetSpace> xTargetSpace(compositeBasis.size({0}));
       BitSetVector<TargetSpace::TangentVector::dimension> dirichletDofsTargetSpace(compositeBasis.size({0}), false);
       for (std::size_t i = 0; i < compositeBasis.size({0}); i++) {
         for (int j = 0; j < 3; j ++) {       // Displacement part
-          xTargetSpace[i].r[j] = x[_0][i][j];
+          xTargetSpace[i][_0].globalCoordinates()[j] = x[_0][i][j];
           dirichletDofsTargetSpace[i][j] = deformationDirichletDofs[i][j];
         }
-        xTargetSpace[i].q = x[_1][i];       // Rotation part
+        xTargetSpace[i][_1] = x[_1][i];       // Rotation part
         for (int j = 3; j < TargetSpace::TangentVector::dimension; j ++)
           dirichletDofsTargetSpace[i][j] = orientationDirichletDofs[i][j-3];
       }
@@ -676,8 +679,8 @@ int main (int argc, char *argv[]) try
       }
 
       for (std::size_t i = 0; i < xTargetSpace.size(); i++) {
-        x[_0][i] = xTargetSpace[i].r;
-        x[_1][i] = xTargetSpace[i].q;
+        x[_0][i] = xTargetSpace[i][_0];
+        x[_1][i] = xTargetSpace[i][_1];
       }
 #endif
     }
diff --git a/src/film-on-substrate.cc b/src/film-on-substrate.cc
index 016275d86a3feb39c810eec7f8d044295df7114a..33fb40eb7741f4765326e3687c739b38a9e08e8f 100644
--- a/src/film-on-substrate.cc
+++ b/src/film-on-substrate.cc
@@ -69,7 +69,7 @@
 #include <dune/gfe/assemblers/geodesicfeassemblerwrapper.hh>
 #include <dune/gfe/riemannianpnsolver.hh>
 #include <dune/gfe/riemanniantrsolver.hh>
-#include <dune/gfe/spaces/rigidbodymotion.hh>
+#include <dune/gfe/spaces/productmanifold.hh>
 #endif
 
 #include <dune/istl/multitypeblockvector.hh>
@@ -564,18 +564,18 @@ int main (int argc, char *argv[]) try
         x[_1][i].set(dOV[i]);
 
 #if !MIXED_SPACE
-    //The MixedRiemannianTrustRegionSolver can treat the Displacement and Orientation Space as separate ones
-    //The RiemannianTrustRegionSolver can only treat the Displacement and Rotation together in a RigidBodyMotion
-    //Therefore, x and the dirichletDofs are converted to a RigidBodyMotion structure, as well as the Hessian and Gradient that are returned by the assembler
-    typedef RigidBodyMotion<double, dim> RBM;
+    //The MixedRiemannianTrustRegionSolver can treat the Deformation and Orientation Space as separate ones
+    //The RiemannianTrustRegionSolver can only treat the Deformation and Rotation together in a ProductManifold
+    //Therefore, x and the dirichletDofs are converted to a ProductManifold structure, as well as the Hessian and Gradient that are returned by the assembler
+    using RBM = GFE::ProductManifold<RealTuple<double, dim>,Rotation<double,dim> >;
     std::vector<RBM> xRBM(compositeBasis.size({0}));
     BitSetVector<RBM::TangentVector::dimension> dirichletDofsRBM(compositeBasis.size({0}), false);
     for (int i = 0; i < compositeBasis.size({0}); i++) {
       for (int j = 0; j < dim; j ++) { // Displacement part
-        xRBM[i].r[j] = x[_0][i][j];
+        xRBM[i][_0].globalCoordinates()[j] = x[_0][i][j];
         dirichletDofsRBM[i][j] = dirichletDofs[_0][i][j];
       }
-      xRBM[i].q = x[_1][i]; // Rotation part
+      xRBM[i][_1] = x[_1][i]; // Rotation part
       for (int j = dim; j < RBM::TangentVector::dimension; j ++)
         dirichletDofsRBM[i][j] = dirichletDofs[_1][i][j-dim];
     }
@@ -632,8 +632,8 @@ int main (int argc, char *argv[]) try
       solver.solve();
       xRBM = solver.getSol();
       for (int i = 0; i < xRBM.size(); i++) {
-        x[_0][i] = xRBM[i].r;
-        x[_1][i] = xRBM[i].q;
+        x[_0][i] = xRBM[i][_0];
+        x[_1][i] = xRBM[i][_1];
       }
 #endif
     } else { //parameterSet.get<std::string>("solvertype") == "proximalNewton"
@@ -655,8 +655,8 @@ int main (int argc, char *argv[]) try
       solver.solve();
       xRBM = solver.getSol();
       for (int i = 0; i < xRBM.size(); i++) {
-        x[_0][i] = xRBM[i].r;
-        x[_1][i] = xRBM[i].q;
+        x[_0][i] = xRBM[i][_0];
+        x[_1][i] = xRBM[i][_1];
       }
 #endif
     }
diff --git a/src/harmonicmaps.cc b/src/harmonicmaps.cc
index 4033c84227f1845277bc2574f364ee9a953925bc..940e55dab9f448e16b486768e5314a55959f6960 100644
--- a/src/harmonicmaps.cc
+++ b/src/harmonicmaps.cc
@@ -47,7 +47,7 @@
 #include <dune/gfe/riemanniantrsolver.hh>
 #include <dune/gfe/embeddedglobalgfefunction.hh>
 #include <dune/gfe/spaces/realtuple.hh>
-#include <dune/gfe/spaces/rigidbodymotion.hh>
+#include <dune/gfe/spaces/productmanifold.hh>
 #include <dune/gfe/spaces/rotation.hh>
 #include <dune/gfe/spaces/unitvector.hh>
 
@@ -58,7 +58,6 @@ const int dimworld = 2;
 // Image space of the geodesic fe functions
 // typedef Rotation<double,2> TargetSpace;
 // typedef Rotation<double,3> TargetSpace;
-// typedef RigidBodyMotion<double,3> TargetSpace;
 // typedef UnitVector<double,2> TargetSpace;
 typedef UnitVector<double,3> TargetSpace;
 // typedef UnitVector<double,4> TargetSpace;
diff --git a/src/rod3d.cc b/src/rod3d.cc
index d934c906df95da45c888d15e0d427fb8eb6985a2..e0e25e63b2e31d82f37cf04a8dac7d2f346023af 100644
--- a/src/rod3d.cc
+++ b/src/rod3d.cc
@@ -39,16 +39,20 @@
 #include <dune/gfe/localgeodesicfefunction.hh>
 #include <dune/gfe/localprojectedfefunction.hh>
 #include <dune/gfe/riemanniantrsolver.hh>
-#include <dune/gfe/spaces/rigidbodymotion.hh>
+#include <dune/gfe/spaces/productmanifold.hh>
+#include <dune/gfe/spaces/realtuple.hh>
+#include <dune/gfe/spaces/rotation.hh>
 
-typedef RigidBodyMotion<double,3> TargetSpace;
+using namespace Dune;
+using namespace Dune::Indices;
+
+using TargetSpace = GFE::ProductManifold<RealTuple<double,3>,Rotation<double,3> >;
 
 const int blocksize = TargetSpace::TangentVector::dimension;
 
 // Approximation order of the finite element space
 constexpr int order = 2;
 
-using namespace Dune;
 
 int main (int argc, char *argv[]) try
 {
@@ -112,15 +116,13 @@ int main (int argc, char *argv[]) try
 
   Functions::interpolate(scalarBasis, referenceConfigurationX, identity);
 
-  using Configuration = std::vector<RigidBodyMotion<double,3> >;
+  using Configuration = std::vector<TargetSpace>;
   Configuration referenceConfiguration(scalarBasis.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();
+    referenceConfiguration[i][_0] = {0, 0, referenceConfigurationX[i]};
+    referenceConfiguration[i][_1] = Rotation<double,3>::identity();
   }
 
   // Select the reference configuration as initial iterate
@@ -157,18 +159,18 @@ int main (int argc, char *argv[]) try
     }
 
   // Set Dirichlet values
-  x[rightBoundaryDof].r = parameterSet.get<FieldVector<double,3> >("dirichletValue");
+  x[rightBoundaryDof][_0] = parameterSet.get<FieldVector<double,3> >("dirichletValue");
 
   auto axis = parameterSet.get<FieldVector<double,3> >("dirichletAxis");
   double angle = parameterSet.get<double>("dirichletAngle");
 
-  x[rightBoundaryDof].q = Rotation<double,3>(axis, M_PI*angle/180);
+  x[rightBoundaryDof][_1] = Rotation<double,3>(axis, M_PI*angle/180);
 
   // backup for error measurement later
   std::cout << "Right boundary orientation:" << std::endl;
-  std::cout << "director 0:  " << x[rightBoundaryDof].q.director(0) << std::endl;
-  std::cout << "director 1:  " << x[rightBoundaryDof].q.director(1) << std::endl;
-  std::cout << "director 2:  " << x[rightBoundaryDof].q.director(2) << std::endl;
+  std::cout << "director 0:  " << x[rightBoundaryDof][_1].director(0) << std::endl;
+  std::cout << "director 1:  " << x[rightBoundaryDof][_1].director(1) << std::endl;
+  std::cout << "director 2:  " << x[rightBoundaryDof][_1].director(2) << std::endl;
 
   //////////////////////////////////////////////
   //  Create the energy and assembler
@@ -207,7 +209,7 @@ int main (int argc, char *argv[]) try
   //   Create a solver for the rod problem
   /////////////////////////////////////////////
 
-  RiemannianTrustRegionSolver<ScalarBasis,RigidBodyMotion<double,3> > rodSolver;
+  RiemannianTrustRegionSolver<ScalarBasis,TargetSpace> rodSolver;
 
   rodSolver.setup(grid,
                   &rodAssembler,
@@ -253,7 +255,7 @@ int main (int argc, char *argv[]) try
   // 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;
+    displacement[i] = x[i][_0].globalCoordinates();
 
   std::vector<double> xEmbedding;
   Functions::interpolate(scalarBasis, xEmbedding, [](FieldVector<double,1> x){
@@ -277,7 +279,7 @@ int main (int argc, char *argv[]) try
   {
     director[i].resize(worldBasis.size());
     for (std::size_t j=0; j<x.size(); j++)
-      director[i][j] = x[j].q.director(i);
+      director[i][j] = x[j][_1].director(i);
 
     directorFunction[i] = Functions::makeDiscreteGlobalBasisFunction<FieldVector<double,3> >(worldBasis, std::move(director[i]));
     vtkWriter.addPointData(*directorFunction[i], "director " + std::to_string(i), 3);
diff --git a/src/rodobstacle.cc b/src/rodobstacle.cc
index 6267e6d2ee6ca9089a6e2655e44499078f72be16..c1b58b705625900b1c08bb6a7e8e3480fad001e9 100644
--- a/src/rodobstacle.cc
+++ b/src/rodobstacle.cc
@@ -19,6 +19,9 @@
 
 #include <dune/gfe/rodwriter.hh>
 #include <dune/gfe/rodassembler.hh>
+#include <dune/gfe/spaces/productmanifold.hh>
+#include <dune/gfe/spaces/realtuple.hh>
+#include <dune/gfe/spaces/rotation.hh>
 
 
 // 3 (x, y, theta) for a planar rod
@@ -71,7 +74,7 @@ int main (int argc, char *argv[]) try
   // Some types that I need
   typedef BCRSMatrix<FieldMatrix<double, blocksize, blocksize> > MatrixType;
   typedef BlockVector<FieldVector<double, blocksize> >           CorrectionType;
-  typedef std::vector<RigidBodyMotion<double,2> >                SolutionType;
+  typedef std::vector<GFE::ProductManifold<RealTuple<double,2>,Rotation<doublee,2> > > SolutionType;
 
   // parse data file
   ParameterTree parameterSet;
@@ -293,7 +296,7 @@ int main (int argc, char *argv[]) try
 
       SolutionType newIterate = x;
       for (int j=0; j<newIterate.size(); j++)
-        newIterate[j] = RigidBodyMotion<double,2>::exp(newIterate[j], corr[j]);
+        newIterate[j] = exp(newIterate[j], corr[j]);
 
       /** \todo Don't always recompute oldEnergy */
       double oldEnergy = rodAssembler.computeEnergy(x);
@@ -304,7 +307,7 @@ int main (int argc, char *argv[]) try
 
       //  Add correction to the current solution
       for (int j=0; j<x.size(); j++)
-        x[j] = RigidBodyMotion<double,2>::exp(x[j], corr[j]);
+        x[j] = exp(x[j], corr[j]);
 
       // Subtract correction from the current obstacle
       for (int k=0; k<corr.size(); k++)
diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt
index 296f756ec74104177e2228887c4e4f55639d5119..3ce0039e093b9151c38b48c7db1306db1cad13f3 100644
--- a/test/CMakeLists.txt
+++ b/test/CMakeLists.txt
@@ -12,7 +12,6 @@ set(TESTS
   localprojectedfefunctiontest
   orthogonalmatrixtest
   polardecompositiontest
-  rigidbodymotiontest
   rotationtest
   svdtest
   targetspacetest
@@ -62,4 +61,4 @@ file(COPY stressPlotData/stressPlotTestRotation DESTINATION ${CMAKE_CURRENT_BINA
 file(COPY stressPlotData/stressPlotTestInitialDeformation DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/stressPlotData)
 
 # Copy an .adolcrc file into the build dir to make sure the tapes stay in memory and do not get written to disk because this causes errors sometimes
-file(COPY .adolcrc DESTINATION ${CMAKE_CURRENT_BINARY_DIR})
\ No newline at end of file
+file(COPY .adolcrc DESTINATION ${CMAKE_CURRENT_BINARY_DIR})
diff --git a/test/adolctest-scalar-and-vector-mode.cc b/test/adolctest-scalar-and-vector-mode.cc
index 61d8f1e5d65c6b1aa8d9a63b2b522f84da9d79a1..a06d3b981c2f28de2e8923d2055ae3d55117e44f 100644
--- a/test/adolctest-scalar-and-vector-mode.cc
+++ b/test/adolctest-scalar-and-vector-mode.cc
@@ -55,7 +55,7 @@ using MatrixRow1 = MultiTypeBlockVector<BCRSMatrix<FieldMatrix<double,dimCR,dim>
 using MatrixTypeMixed = MultiTypeBlockMatrix<MatrixRow0,MatrixRow1>;
 
 //Types for the Non-mixed space
-using RBM = RigidBodyMotion<double, dim>;
+using RBM = GFE::ProductManifold<RealTuple<double,dim>,Rotation<double,dim> >;
 using RBMVector = std::vector<RBM>;
 const static int blocksize = RBM::TangentVector::dimension;
 using CorrectionType = BlockVector<FieldVector<double, blocksize> >;
@@ -170,7 +170,7 @@ int main (int argc, char *argv[])
       initialDeformation[i][j] = std::cos(identity[i][j]);
     initialDeformation[i][2] = identity[i][0]*identity[i][0];
     x[_0][i] = initialDeformation[i];
-    xRBM[i].r = initialDeformation[i];
+    xRBM[i][_0] = initialDeformation[i];
   }
 
   //////////////////////////////////////////////////////////////////////////////
diff --git a/test/adolctest.cc b/test/adolctest.cc
index b43c90621949af6a17d0b5ca5c1cfd5c236208f4..d53f84b746547818c6392801fa2eb1e6b470eeaf 100644
--- a/test/adolctest.cc
+++ b/test/adolctest.cc
@@ -42,15 +42,17 @@ typedef double FDType;
 #include <dune/gfe/assemblers/cosseratenergystiffness.hh>
 #include <dune/gfe/assemblers/localgeodesicfeadolcstiffness.hh>
 #include <dune/gfe/assemblers/localgeodesicfefdstiffness.hh>
-#include <dune/gfe/spaces/rigidbodymotion.hh>
+#include <dune/gfe/spaces/productmanifold.hh>
+#include <dune/gfe/spaces/realtuple.hh>
+#include <dune/gfe/spaces/rotation.hh>
+
+using namespace Dune;
 
 // grid dimension
 const int dim = 2;
 
 // Image space of the geodesic fe functions
-typedef RigidBodyMotion<double,3> TargetSpace;
-
-using namespace Dune;
+using TargetSpace = GFE::ProductManifold<RealTuple<double,3>,Rotation<double,3> >;
 
 /** \brief Assembles energy gradient and Hessian with ADOL-C
  */
@@ -477,7 +479,7 @@ int main (int argc, char *argv[]) try
   Functions::interpolate(powerBasis, v, identity);
 
   for (size_t i=0; i<x.size(); i++)
-    x[i].r = v[i];
+    x[i][Indices::_0] = v[i];
 #endif
 
   // ////////////////////////////////////////////////////////////
diff --git a/test/cosseratenergytest.cc b/test/cosseratenergytest.cc
index f9348a2fa3a23500b484d26b0372a86262fa3ccc..9589bb562992ebf4e407d57f5d6d82d3f1341f1f 100644
--- a/test/cosseratenergytest.cc
+++ b/test/cosseratenergytest.cc
@@ -8,15 +8,18 @@
 #include <dune/functions/functionspacebases/lagrangebasis.hh>
 
 #include <dune/gfe/assemblers/cosseratenergystiffness.hh>
-#include <dune/gfe/spaces/rigidbodymotion.hh>
+#include <dune/gfe/spaces/productmanifold.hh>
+#include <dune/gfe/spaces/realtuple.hh>
+#include <dune/gfe/spaces/rotation.hh>
 
 #include "multiindex.hh"
 #include "valuefactory.hh"
 
-typedef RigidBodyMotion<double,3> TargetSpace;
-
 using namespace Dune;
+using namespace Dune::Indices;
+
 
+using TargetSpace = GFE::ProductManifold<RealTuple<double,3>,Rotation<double,3> >;
 
 // ////////////////////////////////////////////////////////
 //   Make a test grid consisting of a single simplex
@@ -97,10 +100,10 @@ void testEnergy(const GridType* grid, const std::vector<TargetSpace>& coefficien
 
     for (size_t j=0; j<coefficients.size(); j++) {
       FieldVector<double,3> tmp;
-      matrix.mv(coefficients[j].r, tmp);
-      rotatedCoefficients[j].r = tmp;
+      matrix.mv(coefficients[j][_0].globalCoordinates(), tmp);
+      rotatedCoefficients[j][_0].globalCoordinates() = tmp;
 
-      rotatedCoefficients[j].q = testRotations[i].mult(coefficients[j].q);
+      rotatedCoefficients[j][_1] = testRotations[i].mult(coefficients[j][_1]);
     }
 
     double energy = assembler.energy(localView,
@@ -143,7 +146,7 @@ void testFrameInvariance()
     bool identicalPoints = false;
     for (int j=0; j<domainDim+1; j++)
       for (int k=0; k<domainDim+1; k++)
-        if (j!=k and (testPoints[index[j]].r - testPoints[index[k]].r).two_norm() < 1e-5)
+        if (j!=k and (testPoints[index[j]][_0].globalCoordinates() - testPoints[index[k]][_0].globalCoordinates()).two_norm() < 1e-5)
           identicalPoints = true;
 
     if (identicalPoints)
diff --git a/test/cosseratrodenergytest.cc b/test/cosseratrodenergytest.cc
index 95cbc183b4e40dc0f12c243efb7cc0603443663d..7a875cac7ef7fa36fc43f7552820d0f9c883a73d 100644
--- a/test/cosseratrodenergytest.cc
+++ b/test/cosseratrodenergytest.cc
@@ -6,16 +6,20 @@
 
 #include <dune/gfe/assemblers/cosseratrodenergy.hh>
 #include <dune/gfe/localgeodesicfefunction.hh>
-#include <dune/gfe/spaces/rigidbodymotion.hh>
+#include <dune/gfe/spaces/productmanifold.hh>
+#include <dune/gfe/spaces/realtuple.hh>
+#include <dune/gfe/spaces/rotation.hh>
 
 
 using namespace Dune;
+using namespace Dune::Indices;
 
 
 int main (int argc, char *argv[]) try
 {
-  // Some types that I need
-  typedef std::vector<RigidBodyMotion<double,3> > SolutionType;
+  // Type used for algebraic rod configurations
+  using TargetSpace = GFE::ProductManifold<RealTuple<double,3>,Rotation<double,3> >;
+  using SolutionType = std::vector<TargetSpace>;
 
   // Problem settings
   const int numRodBaseElements = 100;
@@ -40,15 +44,13 @@ int main (int argc, char *argv[]) try
   for (size_t i=0; i<x.size(); i++)
   {
     double s = double(i)/(x.size()-1);
-    x[i].r[0] = 0.1*std::cos(2*M_PI*s);
-    x[i].r[1] = 0.1*std::sin(2*M_PI*s);
-    x[i].r[2] = s;
-    x[i].q = Rotation<double,3>::identity();
+    x[i][_0] = {0.1*std::cos(2*M_PI*s), 0.1*std::sin(2*M_PI*s), s};
+    x[i][_1] = Rotation<double,3>::identity();
     //x[i].q = Quaternion<double>(zAxis, (double(i)*M_PI)/(2*(x.size()-1)) );
   }
 
   FieldVector<double,3> zAxis(0);  zAxis[2]=1;
-  x.back().q = Rotation<double,3>(zAxis, M_PI/4);
+  x.back()[_1] = Rotation<double,3>(zAxis, M_PI/4);
 
   // /////////////////////////////////////////////////////////////////////
   //   Create a second, rotated copy of the configuration
@@ -63,31 +65,29 @@ int main (int argc, char *argv[]) try
 
   for (size_t i=0; i<rotatedX.size(); i++)
   {
-    rotatedX[i].r = rotation.rotate(x[i].r);
-    rotatedX[i].r += displacement;
+    rotatedX[i][_0] = rotation.rotate(x[i][_0].globalCoordinates());
+    rotatedX[i][_0].globalCoordinates() += displacement;
 
-    rotatedX[i].q = rotation.mult(x[i].q);
+    rotatedX[i][_1] = rotation.mult(x[i][_1]);
   }
 
   using GeodesicInterpolationRule  = LocalGeodesicFEFunction<1, double,
       FEBasis::LocalView::Tree::FiniteElement,
-      RigidBodyMotion<double,3> >;
+      TargetSpace>;
 
   GFE::CosseratRodEnergy<FEBasis,
       GeodesicInterpolationRule,
       double> localRodEnergy(gridView,
                              1,1,1,1e6,0.3);
 
-  std::vector<RigidBodyMotion<double,3> > referenceConfiguration(gridView.size(1));
+  SolutionType 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();
+    referenceConfiguration[idx][_0] = {0.0, 0.0, vertex.geometry().corner(0)[0]};
+    referenceConfiguration[idx][_1] = Rotation<double,3>::identity();
   }
 
   localRodEnergy.setReferenceConfiguration(referenceConfiguration);
diff --git a/test/cosseratrodtest.cc b/test/cosseratrodtest.cc
index 59fc5a5862a26ea509de680fc4e116957e22238c..2bb105815cef03448a18c9eb6ddf7c04d061d7f1 100644
--- a/test/cosseratrodtest.cc
+++ b/test/cosseratrodtest.cc
@@ -22,17 +22,20 @@
 #include <dune/gfe/localgeodesicfefunction.hh>
 #include <dune/gfe/localprojectedfefunction.hh>
 #include <dune/gfe/riemanniantrsolver.hh>
-#include <dune/gfe/spaces/rigidbodymotion.hh>
+#include <dune/gfe/spaces/productmanifold.hh>
+#include <dune/gfe/spaces/realtuple.hh>
+#include <dune/gfe/spaces/rotation.hh>
 
-typedef RigidBodyMotion<double,3> TargetSpace;
+using namespace Dune;
+using namespace Dune::Indices;
+
+using TargetSpace = GFE::ProductManifold<RealTuple<double,3>,Rotation<double,3> >;
 
 const int blocksize = TargetSpace::TangentVector::dimension;
 
 // Approximation order of the finite element space
 constexpr int order = 2;
 
-using namespace Dune;
-
 int main (int argc, char *argv[]) try
 {
   MPIHelper::instance(argc, argv);
@@ -70,15 +73,13 @@ int main (int argc, char *argv[]) try
 
   Functions::interpolate(scalarBasis, referenceConfigurationX, identity);
 
-  using Configuration = std::vector<RigidBodyMotion<double,3> >;
+  using Configuration = std::vector<TargetSpace>;
   Configuration referenceConfiguration(scalarBasis.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();
+    referenceConfiguration[i][_0] = {0.0, 0.0, referenceConfigurationX[i]};
+    referenceConfiguration[i][_1] = Rotation<double,3>::identity();
   }
 
   // Select the reference configuration as initial iterate
@@ -114,12 +115,12 @@ int main (int argc, char *argv[]) try
     }
 
   // Set Dirichlet values
-  x[rightBoundaryDof].r = {1,0,0};
+  x[rightBoundaryDof][_0] = {1,0,0};
 
   FieldVector<double,3> axis = {1,0,0};
   double angle = 0;
 
-  x[rightBoundaryDof].q = Rotation<double,3>(axis, M_PI*angle/180);
+  x[rightBoundaryDof][_1] = Rotation<double,3>(axis, M_PI*angle/180);
 
   //////////////////////////////////////////////
   //  Create the energy and assembler
@@ -160,7 +161,7 @@ int main (int argc, char *argv[]) try
   //   Create a solver for the rod problem
   /////////////////////////////////////////////
 
-  RiemannianTrustRegionSolver<ScalarBasis,RigidBodyMotion<double,3> > solver;
+  RiemannianTrustRegionSolver<ScalarBasis,TargetSpace> solver;
 
   solver.setup(grid,
                &rodAssembler,
diff --git a/test/geodesicfeassemblerwrappertest.cc b/test/geodesicfeassemblerwrappertest.cc
index ae08c341bc5772c22a3592c187d7b07a18ecc459..79d0940d16442095d41ebb54c2e52d2895abad10 100644
--- a/test/geodesicfeassemblerwrappertest.cc
+++ b/test/geodesicfeassemblerwrappertest.cc
@@ -30,6 +30,9 @@
 #include <dune/gfe/assemblers/mixedgfeassembler.hh>
 #include <dune/gfe/assemblers/mixedlocalgfeadolcstiffness.hh>
 #include <dune/gfe/riemanniantrsolver.hh>
+#include <dune/gfe/spaces/productmanifold.hh>
+#include <dune/gfe/spaces/realtuple.hh>
+#include <dune/gfe/spaces/rotation.hh>
 
 #include <dune/gfe/assemblers/geodesicfeassemblerwrapper.hh>
 
@@ -64,7 +67,7 @@ using MatrixRow1 = MultiTypeBlockVector<BCRSMatrix<FieldMatrix<double,dimCR,dim>
 using MatrixType = MultiTypeBlockMatrix<MatrixRow0,MatrixRow1>;
 
 //Types for the Non-mixed space
-using RBM = RigidBodyMotion<double, dim>;
+using RBM = GFE::ProductManifold<RealTuple<double,dim>,Rotation<double, dim> >;
 const static int blocksize = RBM::TangentVector::dimension;
 using CorrectionTypeWrapped = BlockVector<FieldVector<double, blocksize> >;
 using MatrixTypeWrapped = BCRSMatrix<FieldMatrix<double, blocksize, blocksize> >;
@@ -150,7 +153,6 @@ int main (int argc, char *argv[])
       RealTuple<double,dim>,
       Rotation<double,dim> > mixedAssembler(compositeBasis, &mixedLocalGFEADOLCStiffness);
 
-  using RBM = RigidBodyMotion<double, dim>;
   using DeformationFEBasis = Functions::LagrangeBasis<GridView,displacementOrder>;
   DeformationFEBasis deformationFEBasis(gridView);
   using GFEAssemblerWrapper = GFE::GeodesicFEAssemblerWrapper<CompositeBasis, DeformationFEBasis, RBM, RealTuple<double, dim>, Rotation<double,dim> >;
@@ -179,10 +181,8 @@ int main (int argc, char *argv[])
     for (int j = 0; j < gridDim; j++)
       initialDeformation[i][j] = identity[i][j];
     x[_0][i] = initialDeformation[i];
-    for (int j = 0; j < dim; j ++) { // Displacement part
-      xRBM[i].r[j] = x[_0][i][j];
-    }
-    xRBM[i].q = x[_1][i]; // Rotation part
+    xRBM[i][_0] = x[_0][i];
+    xRBM[i][_1] = x[_1][i]; // Rotation part
   }
 
   //////////////////////////////////////////////////////////////////////////////
diff --git a/test/localgeodesicfefunctiontest.cc b/test/localgeodesicfefunctiontest.cc
index 1ff9526d1ccdcb04d60855351b2f2e285fcbd8dd..400493ea1c93b302f3297f5f8a6c626c4047d894 100644
--- a/test/localgeodesicfefunctiontest.cc
+++ b/test/localgeodesicfefunctiontest.cc
@@ -303,7 +303,6 @@ int main()
   test<UnitVector<double,2>,1>(GeometryTypes::simplex(1));
   test<UnitVector<double,3>,1>(GeometryTypes::simplex(1));
   test<Rotation<double,3>,1>(GeometryTypes::simplex(1));
-  test<RigidBodyMotion<double,3>,1>(GeometryTypes::simplex(1));
   typedef Dune::GFE::ProductManifold<RealTuple<double,1>,Rotation<double,3>,UnitVector<double,2> > CrazyManifold;
   test<CrazyManifold,1>(GeometryTypes::simplex(1));
 
@@ -315,7 +314,6 @@ int main()
   test<UnitVector<double,2>,2>(GeometryTypes::simplex(2));
   test<UnitVector<double,3>,2>(GeometryTypes::simplex(2));
   test<Rotation<double,3>,2>(GeometryTypes::simplex(2));
-  test<RigidBodyMotion<double,3>,2>(GeometryTypes::simplex(2));
   typedef Dune::GFE::ProductManifold<RealTuple<double,1>,Rotation<double,3>,UnitVector<double,2> > CrazyManifold;
   test<CrazyManifold,2>(GeometryTypes::simplex(2));
 
@@ -327,7 +325,6 @@ int main()
   test<UnitVector<double,2>,2>(GeometryTypes::cube(2));
   test<UnitVector<double,3>,2>(GeometryTypes::cube(2));
   test<Rotation<double,3>,2>(GeometryTypes::cube(2));
-  test<RigidBodyMotion<double,3>,2>(GeometryTypes::cube(2));
   typedef Dune::GFE::ProductManifold<RealTuple<double,1>,Rotation<double,3>,UnitVector<double,2> > CrazyManifold;
   test<CrazyManifold,2>(GeometryTypes::cube(2));
 
diff --git a/test/localprojectedfefunctiontest.cc b/test/localprojectedfefunctiontest.cc
index 58373aba475d8538f2add22a51552bc0796a1fdf..31d3ff6c64b9052320e532b09ec52481194f70db 100644
--- a/test/localprojectedfefunctiontest.cc
+++ b/test/localprojectedfefunctiontest.cc
@@ -98,12 +98,6 @@ void testDerivativeTangentiality(const Rotation<double,vectorDim-1>& x,
                                  const FieldMatrix<double,vectorDim,domainDim>& derivative)
 {}
 
-// the columns of the derivative must be tangential to the manifold
-template <int domainDim, int vectorDim>
-void testDerivativeTangentiality(const RigidBodyMotion<double,3>& x,
-                                 const FieldMatrix<double,vectorDim,domainDim>& derivative)
-{}
-
 // the columns of the derivative must be tangential to the manifold
 template <int domainDim, int vectorDim,typename ... TargetSpaces>
 void testDerivativeTangentiality(const Dune::GFE::ProductManifold<TargetSpaces...>& x,
@@ -270,7 +264,6 @@ int main()
   test<UnitVector<double,2>,1>(GeometryTypes::line);
   test<UnitVector<double,3>,1>(GeometryTypes::line);
   test<Rotation<double,3>,1>(GeometryTypes::line);
-  test<RigidBodyMotion<double,3>,1>(GeometryTypes::line);
   typedef Dune::GFE::ProductManifold<RealTuple<double,1>,Rotation<double,3>,UnitVector<double,2> > CrazyManifold;
   test<CrazyManifold, 1>(GeometryTypes::line);
 
@@ -283,7 +276,6 @@ int main()
   test<RealTuple<double,3>,2>(GeometryTypes::triangle);
   test<UnitVector<double,3>,2>(GeometryTypes::triangle);
   test<Rotation<double,3>,2>(GeometryTypes::triangle);
-  test<RigidBodyMotion<double,3>,2>(GeometryTypes::triangle);
   typedef Dune::GFE::ProductManifold<RealTuple<double,1>,Rotation<double,3>,UnitVector<double,2> > CrazyManifold;
   test<CrazyManifold, 2>(GeometryTypes::triangle);
 
@@ -295,7 +287,6 @@ int main()
   test<UnitVector<double,2>,2>(GeometryTypes::quadrilateral);
   test<UnitVector<double,3>,2>(GeometryTypes::quadrilateral);
   test<Rotation<double,3>,2>(GeometryTypes::quadrilateral);
-  test<RigidBodyMotion<double,3>,2>(GeometryTypes::quadrilateral);
   typedef Dune::GFE::ProductManifold<RealTuple<double,1>,Rotation<double,3>,UnitVector<double,2> > CrazyManifold;
   test<CrazyManifold, 2>(GeometryTypes::quadrilateral);
 
diff --git a/test/nonplanarcosseratenergytest.cc b/test/nonplanarcosseratenergytest.cc
index ddb2ee83f4e0bc2a8a94acbe2a5bb374b923fe04..5753614b30ff5f0df15c7bc8f6162b1fc0d7eca0 100644
--- a/test/nonplanarcosseratenergytest.cc
+++ b/test/nonplanarcosseratenergytest.cc
@@ -13,7 +13,9 @@
 
 #include <dune/gfe/cosseratvtkwriter.hh>
 #include <dune/gfe/assemblers/nonplanarcosseratshellenergy.hh>
-#include <dune/gfe/spaces/rigidbodymotion.hh>
+#include <dune/gfe/spaces/productmanifold.hh>
+#include <dune/gfe/spaces/realtuple.hh>
+#include <dune/gfe/spaces/rotation.hh>
 
 #include "multiindex.hh"
 #include "valuefactory.hh"
@@ -24,7 +26,7 @@ static const int dim = 2;
 static const int dimworld = 3;
 
 using GridType = FoamGrid<dim,dimworld>;
-using TargetSpace = RigidBodyMotion<double,dimworld>;
+using TargetSpace = GFE::ProductManifold<RealTuple<double,dimworld>,Rotation<double,dimworld> >;
 
 //////////////////////////////////////////////////////////
 //   Make a test grid consisting of a single triangle
@@ -102,16 +104,15 @@ double calculateEnergy(const int numLevels, const F1 referenceConfigurationFunct
   BlockVector<FieldVector<double,3> > helperVector2(feBasis.size());
   Dune::Functions::interpolate(deformationPowerBasis, helperVector2, configurationFunction);
   for (std::size_t i = 0; i < feBasis.size(); i++) {
-    for (int j = 0; j < dimworld; j++)
-      sol[i].r[j] = helperVector2[i][j];
+    sol[i][_0].globalCoordinates() = helperVector2[i];
 
     FieldVector<double,4> idRotation = {0, 0, 0, 1};     //set rotation = Id everywhere
     Rotation<double,dimworld> rotation(idRotation);
     FieldMatrix<double,dimworld,dimworld> rotationMatrix(0);
     rotation.matrix(rotationMatrix);
-    sol[i].q.set(rotationMatrix);
-    solTuple[_0][i] = sol[i].r;
-    solTuple[_1][i] = sol[i].q;
+    sol[i][_1].set(rotationMatrix);
+    solTuple[_0][i] = sol[i][_0];
+    solTuple[_1][i] = sol[i][_1];
   }
   CosseratVTKWriter<GridType>::write<FEBasis>(feBasis, solTuple, "configuration_l" + std::to_string(numLevels));
 
diff --git a/test/rigidbodymotiontest.cc b/test/rigidbodymotiontest.cc
deleted file mode 100644
index af824ad2ae13a24497ad274072382f35b0c7b2da..0000000000000000000000000000000000000000
--- a/test/rigidbodymotiontest.cc
+++ /dev/null
@@ -1,129 +0,0 @@
-#include "config.h"
-
-#include <dune/common/parallel/mpihelper.hh>
-
-#include <dune/geometry/type.hh>
-#include <dune/geometry/quadraturerules.hh>
-
-#include <dune/localfunctions/lagrange/lagrangelfecache.hh>
-
-#include <dune/gfe/localgeodesicfefunction.hh>
-#include <dune/gfe/spaces/rigidbodymotion.hh>
-
-#include "multiindex.hh"
-#include "valuefactory.hh"
-
-const double eps = 1e-4;
-
-typedef RigidBodyMotion<double,3> TargetSpace;
-
-using namespace Dune;
-
-
-template <int domainDim,class LocalFiniteElement>
-Tensor3<double,3,3,domainDim> evaluateDerivativeFD(const LocalGeodesicFEFunction<domainDim,double,LocalFiniteElement,TargetSpace>& f,
-                                                   const Dune::FieldVector<double,domainDim>& local)
-{
-  const double stepSize = std::sqrt(std::numeric_limits<double>::epsilon());
-  Tensor3<double,3,3,domainDim> result(0);
-
-  for (int i=0; i<domainDim; i++) {
-
-    Dune::FieldVector<double, domainDim> forward  = local;
-    Dune::FieldVector<double, domainDim> backward = local;
-
-    forward[i]  += stepSize;
-    backward[i] -= stepSize;
-
-    TargetSpace forwardValue = f.evaluate(forward);
-    TargetSpace backwardValue = f.evaluate(backward);
-
-    FieldMatrix<double,3,3> forwardMatrix, backwardMatrix;
-    forwardValue.q.matrix(forwardMatrix);
-    backwardValue.q.matrix(backwardMatrix);
-
-    FieldMatrix<double,3,3> fdDer = (forwardMatrix - backwardMatrix) / (2*stepSize);
-
-    for (int j=0; j<3; j++)
-      for (int k=0; k<3; k++)
-        result[j][k][i] = fdDer[j][k];
-
-  }
-
-  return result;
-
-}
-
-template <int domainDim>
-void testDerivativeOfRotationMatrix(const std::vector<TargetSpace>& corners)
-{
-  // Make local fe function to be tested
-  LagrangeLocalFiniteElementCache<double,double,domainDim,1> feCache;
-  typedef typename LagrangeLocalFiniteElementCache<double,double,domainDim,1>::FiniteElementType LocalFiniteElement;
-
-  LocalGeodesicFEFunction<domainDim,double,LocalFiniteElement, TargetSpace> f(feCache.get(GeometryTypes::simplex(domainDim)), corners);
-
-  // A quadrature rule as a set of test points
-  int quadOrder = 3;
-
-  const auto& quad = Dune::QuadratureRules<double, domainDim>::rule(GeometryTypes::simplex(domainDim), quadOrder);
-
-  for (size_t pt=0; pt<quad.size(); pt++) {
-
-    const Dune::FieldVector<double,domainDim>& quadPos = quad[pt].position();
-
-    // evaluate actual derivative
-    Dune::FieldMatrix<double, TargetSpace::EmbeddedTangentVector::dimension, domainDim> derivative = f.evaluateDerivative(quadPos);
-
-    Tensor3<double,3,3,domainDim> DR = f.evaluate(quadPos).quaternionTangentToMatrixTangent(derivative);
-
-    // evaluate fd approximation of derivative
-    Tensor3<double,3,3,domainDim> DR_fd = evaluateDerivativeFD(f,quadPos);
-
-    double maxDiff = 0;
-    for (int i=0; i<3; i++)
-      for (int j=0; j<3; j++)
-        for (int k=0; k<domainDim; k++)
-          maxDiff = std::max(maxDiff, std::abs(DR[i][j][k] - DR_fd[i][j][k]));
-
-    if ( maxDiff > 100*eps ) {
-      std::cout << className(corners[0]) << ": Analytical gradient does not match fd approximation." << std::endl;
-      std::cout << "Analytical:\n " << DR << std::endl;
-      std::cout << "FD        :\n " << DR_fd << std::endl;
-      assert(false);
-    }
-
-  }
-}
-
-int main(int argc, char** argv)
-{
-  MPIHelper::instance(argc, argv);
-
-  const int domainDim = 2;
-
-  ////////////////////////////////////////////////////////////////////////////
-  //  Create a local assembler object
-  ////////////////////////////////////////////////////////////////////////////
-  std::cout << " --- Testing derivative of rotation matrix, domain dimension: " << domainDim << " ---" << std::endl;
-
-  std::vector<Rotation<double,3> > testPoints;
-
-  ValueFactory<Rotation<double,3> >::get(testPoints);
-
-  int nTestPoints = testPoints.size();
-
-  // Set up elements of SO(3)
-  std::vector<TargetSpace> corners(domainDim+1);
-
-  ::MultiIndex index(domainDim+1, nTestPoints);
-  int numIndices = index.cycle();
-
-  for (int i=0; i<numIndices; i++, ++index)
-  {
-    for (int j=0; j<domainDim+1; j++)
-      corners[j].q = testPoints[index[j]];
-
-    testDerivativeOfRotationMatrix<domainDim>(corners);
-  }
-}
diff --git a/test/targetspacetest.cc b/test/targetspacetest.cc
index 5c2d855c6de2278aa2754403e12b0ca973f5b3df..a0eb6b039279a2daadac95748f72ac1b8a3559d8 100644
--- a/test/targetspacetest.cc
+++ b/test/targetspacetest.cc
@@ -412,8 +412,6 @@ int main() try
   test<Dune::GFE::ProductManifold<RealTuple<double,1>,Rotation<double,3>,UnitVector<double,2> > >();
   test<Dune::GFE::ProductManifold<Rotation<double,3>,UnitVector<double,5> > >();
 
-  // Test the RigidBodyMotion class
-  test<RigidBodyMotion<double,3> >();
   //
   //     test<HyperbolicHalfspacePoint<double,2> >();
 
diff --git a/test/valuefactory.hh b/test/valuefactory.hh
index 303f5e09cb5dc880cf4ba1d0cf4279875e1203e2..ed853b9e2b727de55c88bace5d584d76c1bf969f 100644
--- a/test/valuefactory.hh
+++ b/test/valuefactory.hh
@@ -6,7 +6,7 @@
 #include <dune/gfe/spaces/hyperbolichalfspacepoint.hh>
 #include <dune/gfe/spaces/orthogonalmatrix.hh>
 #include <dune/gfe/spaces/productmanifold.hh>
-#include <dune/gfe/spaces/rigidbodymotion.hh>
+#include <dune/gfe/spaces/realtuple.hh>
 #include <dune/gfe/spaces/rotation.hh>
 #include <dune/gfe/spaces/unitvector.hh>
 
@@ -174,13 +174,15 @@ public:
 
 /** \brief A class that creates sets of values of various types, to be used in unit tests
  *
- * This is the specialization for RigidBodyMotion<3>
+ * This is the specialization for a ProductManifold<RealTuple,Rotation>
  */
 template <>
-class ValueFactory<RigidBodyMotion<double,3> >
+class ValueFactory<Dune::GFE::ProductManifold<RealTuple<double,3>,Rotation<double,3> > >
 {
 public:
-  static void get(std::vector<RigidBodyMotion<double,3> >& values) {
+  static void get(std::vector<Dune::GFE::ProductManifold<RealTuple<double,3>,Rotation<double,3> > >& values) {
+
+    using namespace Dune::Indices;
 
     std::vector<RealTuple<double,3> > rValues;
     ValueFactory<RealTuple<double,3> >::get(rValues);
@@ -194,7 +196,10 @@ public:
 
     // Set up elements of SE(3)
     for (int i=0; i<nTestPoints; i++)
-      values[i] = RigidBodyMotion<double,3>(rValues[i].globalCoordinates(),qValues[i]);
+    {
+      values[i][_0] = rValues[i];
+      values[i][_1] = qValues[i];
+    }
 
   }