diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt
index ef40b8d4bcb9fadeec50a841f047e3224ed74fe6..75384afe4d132733cd43fb03cd1d182c6f655bf8 100644
--- a/test/CMakeLists.txt
+++ b/test/CMakeLists.txt
@@ -3,6 +3,7 @@ set(TESTS
   averagedistanceassemblertest
   cosseratenergytest
   cosseratrodenergytest
+  cosseratrodtest
   harmonicenergytest
   localgeodesicfefunctiontest
   localgfetestfunctiontest
diff --git a/test/cosseratrodtest.cc b/test/cosseratrodtest.cc
new file mode 100644
index 0000000000000000000000000000000000000000..b3309e9d8094254cce194de799bedf47c31fc58a
--- /dev/null
+++ b/test/cosseratrodtest.cc
@@ -0,0 +1,206 @@
+#include <config.h>
+
+// Includes for the ADOL-C automatic differentiation library
+// Need to come before (almost) all others.
+#include <adolc/drivers/drivers.h>
+#include <dune/fufem/utilities/adolcnamespaceinjections.hh>
+
+#include <dune/common/bitsetvector.hh>
+
+#include <dune/grid/onedgrid.hh>
+
+#include <dune/functions/functionspacebases/interpolate.hh>
+#include <dune/functions/functionspacebases/lagrangebasis.hh>
+#include <dune/functions/functionspacebases/powerbasis.hh>
+
+#include <dune/fufem/boundarypatch.hh>
+#include <dune/fufem/functiontools/boundarydofs.hh>
+
+#include <dune/gfe/cosseratrodenergy.hh>
+#include <dune/gfe/geodesicfeassembler.hh>
+#include <dune/gfe/localgeodesicfeadolcstiffness.hh>
+#include <dune/gfe/localgeodesicfefunction.hh>
+#include <dune/gfe/localprojectedfefunction.hh>
+#include <dune/gfe/rigidbodymotion.hh>
+#include <dune/gfe/riemanniantrsolver.hh>
+
+typedef RigidBodyMotion<double,3> TargetSpace;
+
+const int blocksize = TargetSpace::TangentVector::dimension;
+
+// Approximation order of the finite element space
+constexpr int order = 2;
+
+using namespace Dune;
+
+int main (int argc, char *argv[]) try
+{
+  MPIHelper::instance(argc, argv);
+
+  // Rod parameter settings
+  const double A               = 1;
+  const double J1              = 1;
+  const double J2              = 1;
+  const double E               = 2.5e5;
+  const double nu              = 0.3;
+
+  /////////////////////////////////////////
+  //    Create the grid
+  /////////////////////////////////////////
+  using Grid = OneDGrid;
+  Grid grid(5, 0, 1);
+
+  grid.globalRefine(2);
+
+  using GridView = Grid::LeafGridView;
+  GridView gridView = grid.leafGridView();
+
+  //////////////////////////////////////////////
+  //  Create the stress-free configuration
+  //////////////////////////////////////////////
+
+  using ScalarBasis = Functions::LagrangeBasis<GridView,order>;
+  ScalarBasis scalarBasis(gridView);
+
+  std::vector<double> referenceConfigurationX(scalarBasis.size());
+
+  auto identity = [](const FieldVector<double,1>& x) { return x; };
+
+  Functions::interpolate(scalarBasis, referenceConfigurationX, identity);
+
+  using Configuration = std::vector<RigidBodyMotion<double,3> >;
+  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();
+  }
+
+  // Select the reference configuration as initial iterate
+  Configuration x = referenceConfiguration;
+
+  ///////////////////////////////////////////
+  //   Set Dirichlet values
+  ///////////////////////////////////////////
+
+  // A basis for the tangent space
+  using namespace Functions::BasisFactory;
+
+  auto tangentBasis = makeBasis(
+    gridView,
+    power<TargetSpace::TangentVector::dimension>(
+      lagrange<order>(),
+      blockedInterleaved()
+  ));
+
+  // Find all boundary dofs
+  BoundaryPatch<GridView> dirichletBoundary(gridView,
+                                            true);    // true: The entire boundary is Dirichlet boundary
+  BitSetVector<TargetSpace::TangentVector::dimension> dirichletNodes(tangentBasis.size(), false);
+  constructBoundaryDofs(dirichletBoundary,tangentBasis,dirichletNodes);
+
+  // Find the dof on the right boundary
+  std::size_t rightBoundaryDof;
+  for (std::size_t i=0; i<referenceConfigurationX.size(); i++)
+    if (std::fabs(referenceConfigurationX[i] - 1.0) < 1e-6)
+    {
+      rightBoundaryDof = i;
+      break;
+    }
+
+  // Set Dirichlet values
+  x[rightBoundaryDof].r = {1,0,0};
+
+  FieldVector<double,3> axis = {1,0,0};
+  double angle = 0;
+
+  x[rightBoundaryDof].q = Rotation<double,3>(axis, M_PI*angle/180);
+
+  //////////////////////////////////////////////
+  //  Create the energy and assembler
+  //////////////////////////////////////////////
+
+  using ATargetSpace = TargetSpace::rebind<adouble>::other;
+  using GeodesicInterpolationRule  = LocalGeodesicFEFunction<1, double, ScalarBasis::LocalView::Tree::FiniteElement, ATargetSpace>;
+  using ProjectedInterpolationRule = GFE::LocalProjectedFEFunction<1, double, ScalarBasis::LocalView::Tree::FiniteElement, ATargetSpace>;
+
+  // Assembler using ADOL-C
+  std::shared_ptr<GFE::LocalEnergy<ScalarBasis,ATargetSpace> > localRodEnergy;
+
+  std::string interpolationMethod = "geodesic";
+
+  if (interpolationMethod == "geodesic")
+  {
+    auto energy = std::make_shared<GFE::CosseratRodEnergy<ScalarBasis, GeodesicInterpolationRule, adouble> >(gridView,
+                                                                                                           A, J1, J2, E, nu);
+    energy->setReferenceConfiguration(referenceConfiguration);
+    localRodEnergy = energy;
+  }
+  else if (interpolationMethod == "projected")
+  {
+    auto energy = std::make_shared<GFE::CosseratRodEnergy<ScalarBasis, ProjectedInterpolationRule, adouble> >(gridView,
+                                                                                                            A, J1, J2, E, nu);
+    energy->setReferenceConfiguration(referenceConfiguration);
+    localRodEnergy = energy;
+  }
+  else
+    DUNE_THROW(Exception, "Unknown interpolation method " << interpolationMethod << " requested!");
+
+  LocalGeodesicFEADOLCStiffness<ScalarBasis,
+                                TargetSpace> localStiffness(localRodEnergy.get());
+
+  GeodesicFEAssembler<ScalarBasis,TargetSpace> rodAssembler(gridView, localStiffness);
+
+  /////////////////////////////////////////////
+  //   Create a solver for the rod problem
+  /////////////////////////////////////////////
+
+  RiemannianTrustRegionSolver<ScalarBasis,RigidBodyMotion<double,3> > solver;
+
+  solver.setup(grid,
+               &rodAssembler,
+               x,
+               dirichletNodes,
+               1e-6,      // tolerance
+               100,       // max trust region steps
+               1,         // initial trust region radius,
+               200,       // max multigrid iterations
+               1e-10,     // multigrid tolerance
+               1, 3, 3,   // V(3,3) multigrid cycle
+               100,       // base iterations
+               1e-8,      // base tolerance
+               false);    // No instrumentation for the solver
+
+  ///////////////////////////////////////////////////////
+  //   Solve!
+  ///////////////////////////////////////////////////////
+
+  solver.setInitialIterate(x);
+  solver.solve();
+
+  x = solver.getSol();
+        
+  std::size_t expectedFinalIteration = 4;
+  if (solver.getStatistics().finalIteration != expectedFinalIteration)
+  {
+    std::cerr << "Trust-region solver did " << solver.getStatistics().finalIteration+1
+              << " iterations, instead of the expected '" << expectedFinalIteration+1 << "'!" << std::endl;
+    return 1;
+  }
+
+  double expectedEnergy = 162852.7265417;
+  if ( std::abs(solver.getStatistics().finalEnergy - expectedEnergy) > 1e-7)
+  {
+    std::cerr << std::setprecision(15);
+    std::cerr << "Final energy is " << solver.getStatistics().finalEnergy
+              << " but '" << expectedEnergy << "' was expected!" << std::endl;
+    return 1;
+  }
+
+} catch (Exception& e)
+{
+    std::cout << e.what() << std::endl;
+}