diff --git a/dune/gfe/assemblers/localintegralenergy.hh b/dune/gfe/assemblers/localintegralenergy.hh
index ca8e961f93048fa9424d2c8ff449bfc851ae757d..c26c4a03dae062e683e07b714985cd88a0f6b830 100644
--- a/dune/gfe/assemblers/localintegralenergy.hh
+++ b/dune/gfe/assemblers/localintegralenergy.hh
@@ -66,16 +66,35 @@ namespace Dune::GFE {
 
           const auto geometryJacobianInverse = element.geometry().jacobianInverse(quadPos);
 
-          // Function value at the quadrature point
-          // This is always needed: Either directly, or to compute the derivative below
-          TargetSpace q = localInterpolationRule.evaluate(quadPos);
-
-          // The derivative of the finite element function at the quadrature point
-          typename LocalInterpolationRule::DerivativeType derivative;
-          if (localDensity_->dependsOnDerivative())
-            derivative = localInterpolationRule.evaluateDerivative(quadPos, q) * geometryJacobianInverse;
-
-          energy += qp.weight() * integrationElement * (*localDensity_)(quadPos,q.globalCoordinates(),derivative);
+          if (localDensity_->dependsOnValue())
+          {
+            if (localDensity_->dependsOnDerivative())
+            {
+              auto [value, derivative] = localInterpolationRule.evaluateValueAndDerivative(quadPos);
+              derivative = derivative * geometryJacobianInverse;
+              energy += qp.weight() * integrationElement * (*localDensity_)(quadPos,value.globalCoordinates(),derivative);
+            }
+            else
+            {
+              auto value = localInterpolationRule.evaluate(quadPos);
+              typename LocalInterpolationRule::DerivativeType dummyDerivative;
+              energy += qp.weight() * integrationElement * (*localDensity_)(quadPos,value.globalCoordinates(),dummyDerivative);
+            }
+          }
+          else
+          {
+            if (localDensity_->dependsOnDerivative())
+            {
+              typename TargetSpace::CoordinateType dummyValue;
+              auto derivative = localInterpolationRule.evaluateDerivative(quadPos);
+              derivative = derivative * geometryJacobianInverse;
+              energy += qp.weight() * integrationElement * (*localDensity_)(quadPos,dummyValue,derivative);
+            }
+            else
+            {
+              // Density does not depend on anything.  That's rather pointless, but not an error.
+            }
+          }
         }
       }
 
diff --git a/dune/gfe/localgeodesicfefunction.hh b/dune/gfe/localgeodesicfefunction.hh
index 6892e93604dfd22ed4872f30835899739ea1e9d3..cb36d6aa583e3a05e00eab11d88c9ad730938ac5 100644
--- a/dune/gfe/localgeodesicfefunction.hh
+++ b/dune/gfe/localgeodesicfefunction.hh
@@ -93,6 +93,10 @@ public:
   DerivativeType evaluateDerivative(const Dune::FieldVector<ctype, dim>& local,
                                     const TargetSpace& q) const;
 
+  /** \brief Evaluate the value and the derivative of the interpolation function
+   */
+  std::pair<TargetSpace,DerivativeType> evaluateValueAndDerivative(const Dune::FieldVector<ctype, dim>& local) const;
+
   /** \brief Evaluate the derivative of the function value with respect to a coefficient */
   void evaluateDerivativeOfValueWRTCoefficient(const Dune::FieldVector<ctype, dim>& local,
                                                int coefficient,
@@ -304,6 +308,17 @@ evaluateDerivative(const Dune::FieldVector<ctype, dim>& local, const TargetSpace
   return result;
 }
 
+template <int dim, class ctype, class LocalFiniteElement, class TargetSpace>
+std::pair<TargetSpace,typename LocalGeodesicFEFunction<dim,ctype,LocalFiniteElement,TargetSpace>::DerivativeType>
+LocalGeodesicFEFunction<dim,ctype,LocalFiniteElement,TargetSpace>::
+evaluateValueAndDerivative(const Dune::FieldVector<ctype, dim>& local) const
+{
+  std::pair<TargetSpace,DerivativeType> result;
+  result.first = evaluate(local);
+  result.second = evaluateDerivative(local,result.first);
+  return result;
+}
+
 template <int dim, class ctype, class LocalFiniteElement, class TargetSpace>
 void LocalGeodesicFEFunction<dim,ctype,LocalFiniteElement,TargetSpace>::
 evaluateDerivativeOfValueWRTCoefficient(const Dune::FieldVector<ctype, dim>& local,
diff --git a/dune/gfe/localprojectedfefunction.hh b/dune/gfe/localprojectedfefunction.hh
index 5eb2c03a0072afa337946018ad62b61d418d6554..5c394feec193d6670e8cf46bcf62bb39256389c2 100644
--- a/dune/gfe/localprojectedfefunction.hh
+++ b/dune/gfe/localprojectedfefunction.hh
@@ -81,10 +81,21 @@ namespace Dune {
       /** \brief Evaluate the derivative of the function, if you happen to know the function value (much faster!)
        *        \param local Local coordinates in the reference element where to evaluate the derivative
        *        \param q Value of the local gfe function at 'local'.  If you provide something wrong here the result will be wrong, too!
+       *
+       * \note This method is only usable in the conforming setting, because it requires the caller
+       * to hand over the interpolation value as a TargetSpace object.
        */
       DerivativeType evaluateDerivative(const Dune::FieldVector<ctype, dim>& local,
                                         const TargetSpace& q) const;
 
+      /** \brief Evaluate the value and the derivative of the interpolation function
+       *
+       * \return A std::pair containing the value and the first derivative of the interpolation function.
+       * If the interpolation is conforming then the first member of the pair will be a TargetSpace.
+       * Otherwise it will be a RealTuple.
+       */
+      auto evaluateValueAndDerivative(const Dune::FieldVector<ctype, dim>& local) const;
+
       /** \brief Get the i'th base coefficient. */
       TargetSpace coefficient(int i) const
       {
@@ -175,6 +186,55 @@ namespace Dune {
       return derivativeOfProjection*derivative;
     }
 
+    template <int dim, class ctype, class LocalFiniteElement, class TargetSpace,bool conforming>
+    auto
+    LocalProjectedFEFunction<dim,ctype,LocalFiniteElement,TargetSpace,conforming>::
+    evaluateValueAndDerivative(const Dune::FieldVector<ctype, dim>& local) const
+    {
+      // Construct the type of the result -- it depends on whether the interpolation
+      // is conforming or not.
+      using Value = std::conditional_t<conforming,TargetSpace,RealTuple<RT,embeddedDim> >;
+
+      std::pair<Value,DerivativeType> result;
+
+      ///////////////////////////////////////////////////////////
+      //  Compute the value of the interpolation function
+      ///////////////////////////////////////////////////////////
+
+      std::vector<Dune::FieldVector<ctype,1> > w;
+      localFiniteElement_.localBasis().evaluateFunction(local,w);
+
+      typename TargetSpace::CoordinateType embeddedInterpolation(0);
+      for (size_t i=0; i<coefficients_.size(); i++)
+        embeddedInterpolation.axpy(w[i][0], coefficients_[i].globalCoordinates());
+
+      if constexpr (conforming)
+        result.first = TargetSpace::projectOnto(embeddedInterpolation);
+      else
+        result.first = (RealTuple<RT, TargetSpace::CoordinateType::dimension>)embeddedInterpolation;
+
+      ///////////////////////////////////////////////////////////
+      //  Compute the derivative of the interpolation function
+      ///////////////////////////////////////////////////////////
+
+      // Compute the interpolation in the surrounding space
+      std::vector<Dune::FieldMatrix<ctype,1,dim> > wDer;
+      localFiniteElement_.localBasis().evaluateJacobian(local,wDer);
+
+      result.second = 0.0;
+      for (size_t i=0; i<embeddedDim; i++)
+        for (size_t j=0; j<dim; j++)
+          for (size_t k=0; k<coefficients_.size(); k++)
+            result.second[i][j] += wDer[k][0][j] * coefficients_[k].globalCoordinates()[i];
+
+      // The derivative of the projection onto the manifold
+      if constexpr(conforming)
+        result.second = TargetSpace::derivativeOfProjection(embeddedInterpolation) * result.second;
+
+      return result;
+    }
+
+
     /** \brief Interpolate in an embedding Euclidean space, and project back onto the Riemannian manifold -- specialization for SO(3)
      *
      * \tparam dim Dimension of the reference element
diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt
index 59a4390e214d06b4b5eab33b91cfb686348533c1..b32a0b3432cf29a957c9b59d9ccbdd84699b8f02 100644
--- a/test/CMakeLists.txt
+++ b/test/CMakeLists.txt
@@ -39,8 +39,20 @@ foreach(_test ${TESTS})
   target_compile_options(${_test} PRIVATE -g)
 endforeach()
 
+dune_add_test(NAME harmonicmaptest-geodesic
+              SOURCES harmonicmaptest.cc
+              COMPILE_DEFINITIONS "GEODESICINTERPOLATION=1; CONFORMING=1"
+              TIMEOUT 1200)
+
+dune_add_test(NAME harmonicmaptest-projected
+              SOURCES harmonicmaptest.cc
+              COMPILE_DEFINITIONS "GEODESICINTERPOLATION=0; CONFORMING=1"
+              TIMEOUT 1200)
+
 # Run distributed tests
-dune_add_test(SOURCES harmonicmaptest.cc
+dune_add_test(NAME harmonicmaptest-projected-nonconforming
+              SOURCES harmonicmaptest.cc
+              COMPILE_DEFINITIONS "GEODESICINTERPOLATION=0; CONFORMING=0"
               MPI_RANKS 1 4
               TIMEOUT 1200
               CMAKE_GUARD MPI_FOUND)
diff --git a/test/harmonicmaptest.cc b/test/harmonicmaptest.cc
index 8f16768a156b63f85f6c4eb302c3995733c5a72a..5dcefa4725599969614379eb77facfa756b89145 100644
--- a/test/harmonicmaptest.cc
+++ b/test/harmonicmaptest.cc
@@ -149,12 +149,20 @@ int main (int argc, char *argv[])
   //////////////////////////////////////////////////////////////
 
   using ATargetSpace = TargetSpace::rebind<adouble>::other;
-  //using GeodesicInterpolationRule  = LocalGeodesicFEFunction<dim, double, FEBasis::LocalView::Tree::FiniteElement, ATargetSpace>;
-  using ProjectedInterpolationRule = GFE::LocalProjectedFEFunction<dim, double, FEBasis::LocalView::Tree::FiniteElement, ATargetSpace>;
+
+#if GEODESICINTERPOLATION
+  using InterpolationRule = LocalGeodesicFEFunction<dim, double, FEBasis::LocalView::Tree::FiniteElement, ATargetSpace>;
+#else
+#if CONFORMING
+  using InterpolationRule = GFE::LocalProjectedFEFunction<dim, double, FEBasis::LocalView::Tree::FiniteElement, ATargetSpace,true>;
+#else
+  using InterpolationRule = GFE::LocalProjectedFEFunction<dim, double, FEBasis::LocalView::Tree::FiniteElement, ATargetSpace,false>;
+#endif
+#endif
 
   auto harmonicDensity = std::make_shared<GFE::HarmonicDensity<GridType::Codim<0>::Entity::Geometry::LocalCoordinate, ATargetSpace> >();
-  //std::shared_ptr<GFE::LocalEnergy<FEBasis,ATargetSpace> > localEnergy = std::make_shared<HarmonicEnergy<FEBasis, GeodesicInterpolationRule, ATargetSpace> >();
-  std::shared_ptr<GFE::LocalEnergy<FEBasis,ATargetSpace> > localEnergy = std::make_shared<GFE::LocalIntegralEnergy<FEBasis, ProjectedInterpolationRule, ATargetSpace> >(harmonicDensity);
+
+  std::shared_ptr<GFE::LocalEnergy<FEBasis,ATargetSpace> > localEnergy = std::make_shared<GFE::LocalIntegralEnergy<FEBasis, InterpolationRule, ATargetSpace> >(harmonicDensity);
 
   LocalGeodesicFEADOLCStiffness<FEBasis,TargetSpace> localGFEADOLCStiffness(localEnergy.get());
 
@@ -188,7 +196,16 @@ int main (int argc, char *argv[])
 
   x = solver.getSol();
 
+#if GEODESICINTERPOLATION
+  std::size_t expectedFinalIteration = 8;
+#else
+#if CONFORMING
   std::size_t expectedFinalIteration = 10;
+#else
+  std::size_t expectedFinalIteration = 6;
+#endif
+#endif
+
   if (solver.getStatistics().finalIteration != expectedFinalIteration)
   {
     std::cerr << "Trust-region solver did " << solver.getStatistics().finalIteration+1
@@ -196,7 +213,15 @@ int main (int argc, char *argv[])
     return 1;
   }
 
+#if GEODESICINTERPOLATION
+  double expectedEnergy = 12.3154833;
+#else
+#if CONFORMING
   double expectedEnergy = 12.2927849;
+#else
+  double expectedEnergy = 0.436857464;
+#endif
+#endif
   if ( std::abs(solver.getStatistics().finalEnergy - expectedEnergy) > 1e-7)
   {
     std::cerr << std::setprecision(9);