From a7ed421501ae3c811db1289060b45d1100c62566 Mon Sep 17 00:00:00 2001
From: Oliver Sander <oliver.sander@tu-dresden.de>
Date: Fri, 5 Apr 2024 06:39:50 +0200
Subject: [PATCH] Use plain std::vector<double> for element energy gradients

This is what dune-function mandates.  We don't actually use
dune-functions here a lot, but it is still nice to stay in the spirit.
Also, I am thinking about using dune-functions bases for *some*
indexing work in the future.

Plus, I hope that getting rid of the blocking will improve run-times
of debug builds a little bit, in particular in the
LocalIntegralStiffness class.
---
 dune/gfe/assemblers/geodesicfeassembler.hh    | 10 +++---
 dune/gfe/assemblers/localfirstordermodel.hh   | 31 ++---------------
 .../localgeodesicfeadolcstiffness.hh          | 34 +++++++++++++------
 .../assemblers/localgeodesicfefdstiffness.hh  | 20 +++++------
 .../assemblers/localgeodesicfestiffness.hh    |  8 ++---
 dune/gfe/assemblers/mixedgfeassembler.hh      | 11 +++---
 test/adolctest.cc                             |  4 +--
 7 files changed, 52 insertions(+), 66 deletions(-)

diff --git a/dune/gfe/assemblers/geodesicfeassembler.hh b/dune/gfe/assemblers/geodesicfeassembler.hh
index 467db9e3..070c4164 100644
--- a/dune/gfe/assemblers/geodesicfeassembler.hh
+++ b/dune/gfe/assemblers/geodesicfeassembler.hh
@@ -167,7 +167,7 @@ assembleGradientAndHessian(const std::vector<TargetSpace>& sol,
     for (int i=0; i<numOfBaseFct; i++)
       localSolution[i] = sol[localView.index(i)];
 
-    std::vector<Dune::FieldVector<double,blocksize> > localGradient(numOfBaseFct);
+    std::vector<double> localGradient(numOfBaseFct*blocksize);
     Dune::Matrix<Dune::FieldMatrix<double,blocksize,blocksize> > localHessian(numOfBaseFct,numOfBaseFct);
 
     // setup local matrix and gradient
@@ -188,7 +188,8 @@ assembleGradientAndHessian(const std::vector<TargetSpace>& sol,
 
     // Add local gradient to global gradient
     for (int i=0; i<numOfBaseFct; i++)
-      gradient[localView.index(i)] += localGradient[i];
+      for (int j=0; j<blocksize; j++)
+        gradient[localView.index(i)][j] += localGradient[i*blocksize + j];
 
   }
 
@@ -223,13 +224,14 @@ assembleGradient(const std::vector<TargetSpace>& sol,
       localSolution[i] = sol[localView.index(i)];
 
     // Assemble local gradient
-    std::vector<Dune::FieldVector<double,blocksize> > localGradient(nDofs);
+    std::vector<double> localGradient(nDofs*blocksize);
 
     localStiffness_->assembleGradient(localView, localSolution, localGradient);
 
     // Add to global gradient
     for (size_t i=0; i<nDofs; i++)
-      grad[localView.index(i)[0]] += localGradient[i];
+      for (size_t j=0; j<blocksize; j++)
+        grad[localView.index(i)[0]][j] += localGradient[i*blocksize+j];
   }
 
 }
diff --git a/dune/gfe/assemblers/localfirstordermodel.hh b/dune/gfe/assemblers/localfirstordermodel.hh
index 6e2f4132..7ab06435 100644
--- a/dune/gfe/assemblers/localfirstordermodel.hh
+++ b/dune/gfe/assemblers/localfirstordermodel.hh
@@ -5,33 +5,6 @@
 
 namespace Dune::GFE
 {
-  namespace Impl
-  {
-    /** \brief A class exporting container types for sets of tangent vectors
-     *
-     * This generic template handles TargetSpaces that are not product manifolds.
-     */
-    template <class TargetSpace>
-    struct LocalFirstOrderModelTypes
-      : public LocalEnergyTypes<TargetSpace>
-    {
-      using Gradient = std::vector<typename TargetSpace::TangentVector>;
-      using CompositeGradient = TupleVector<std::vector<typename TargetSpace::TangentVector> >;
-    };
-
-    /** \brief A class exporting container types for sets of tangent vectors -- specialization for product manifolds
-     */
-    template <class ... Factors>
-    struct LocalFirstOrderModelTypes<ProductManifold<Factors...> >
-      : public LocalEnergyTypes<ProductManifold<Factors...> >
-    {
-      using Gradient = std::vector<typename ProductManifold<Factors...>::TangentVector>;
-      using CompositeGradient = TupleVector<std::vector<typename Factors::TangentVector>... >;
-    };
-
-  }  // namespace Impl
-
-
   /** \brief Base class for problems that have an energy and a first derivative
    */
   template<class Basis, class TargetSpace>
@@ -42,8 +15,8 @@ namespace Dune::GFE
 
     /** \brief Assemble the element gradient of the energy functional */
     virtual void assembleGradient(const typename Basis::LocalView& localView,
-                                  const typename Impl::LocalFirstOrderModelTypes<TargetSpace>::Coefficients& coefficients,
-                                  typename Impl::LocalFirstOrderModelTypes<TargetSpace>::Gradient& gradient) const = 0;
+                                  const typename Impl::LocalEnergyTypes<TargetSpace>::Coefficients& coefficients,
+                                  std::vector<double>& gradient) const = 0;
 
   };
 
diff --git a/dune/gfe/assemblers/localgeodesicfeadolcstiffness.hh b/dune/gfe/assemblers/localgeodesicfeadolcstiffness.hh
index 25eea316..9220b8d1 100644
--- a/dune/gfe/assemblers/localgeodesicfeadolcstiffness.hh
+++ b/dune/gfe/assemblers/localgeodesicfeadolcstiffness.hh
@@ -54,7 +54,7 @@ public:
    */
   virtual void assembleGradient(const typename Basis::LocalView& localView,
                                 const typename Dune::GFE::Impl::LocalStiffnessTypes<TargetSpace>::Coefficients& coefficients,
-                                typename Dune::GFE::Impl::LocalStiffnessTypes<TargetSpace>::Gradient& gradient) const override;
+                                std::vector<double>& gradient) const override;
 
   /** \brief Assemble the local stiffness matrix at the current position
 
@@ -62,14 +62,14 @@ public:
    */
   virtual void assembleGradientAndHessian(const typename Basis::LocalView& localView,
                                           const typename Dune::GFE::Impl::LocalStiffnessTypes<TargetSpace>::Coefficients& coefficients,
-                                          typename Dune::GFE::Impl::LocalStiffnessTypes<TargetSpace>::Gradient& localGradient,
+                                          std::vector<double>& localGradient,
                                           typename Dune::GFE::Impl::LocalStiffnessTypes<TargetSpace>::Hessian& localHessian) const override;
 
   /** \brief Assemble the local stiffness matrix at the current position
    */
   virtual void assembleGradientAndHessian(const typename Basis::LocalView& localView,
                                           const typename Dune::GFE::Impl::LocalStiffnessTypes<TargetSpace>::CompositeCoefficients& coefficients,
-                                          typename Dune::GFE::Impl::LocalStiffnessTypes<TargetSpace>::CompositeGradient& localGradient,
+                                          std::vector<double>& localGradient,
                                           typename Dune::GFE::Impl::LocalStiffnessTypes<TargetSpace>::CompositeHessian& localHessian) const override;
 
   const Dune::GFE::LocalEnergy<Basis, ATargetSpace>* localEnergy_;
@@ -204,7 +204,7 @@ template <class Basis, class TargetSpace>
 void LocalGeodesicFEADOLCStiffness<Basis, TargetSpace>::
 assembleGradient(const typename Basis::LocalView& localView,
                  const typename Dune::GFE::Impl::LocalStiffnessTypes<TargetSpace>::Coefficients& localSolution,
-                 typename Dune::GFE::Impl::LocalStiffnessTypes<TargetSpace>::Gradient& localGradient) const
+                 std::vector<double>& localGradient) const
 {
   // Tape energy computation.  We may not have to do this every time, but it's comparatively cheap.
   energy(localView, localSolution);
@@ -250,7 +250,7 @@ template <class Basis, class TargetSpace>
 void LocalGeodesicFEADOLCStiffness<Basis, TargetSpace>::
 assembleGradientAndHessian(const typename Basis::LocalView& localView,
                            const typename Dune::GFE::Impl::LocalStiffnessTypes<TargetSpace>::Coefficients& localSolution,
-                           typename Dune::GFE::Impl::LocalStiffnessTypes<TargetSpace>::Gradient& localGradient,
+                           std::vector<double>& localGradient,
                            typename Dune::GFE::Impl::LocalStiffnessTypes<TargetSpace>::Hessian& localHessian) const
 {
   // Tape energy computation.  We may not have to do this every time, but it's comparatively cheap.
@@ -287,8 +287,10 @@ assembleGradientAndHessian(const typename Basis::LocalView& localView,
 
   // Express gradient in local coordinate system
   for (size_t i=0; i<nDofs; i++) {
-    Dune::FieldMatrix<RT,blocksize,embeddedBlocksize> orthonormalFrame = localSolution[i].orthonormalFrame();
-    orthonormalFrame.mv(localEmbeddedGradient[i],localGradient[i]);
+    typename TargetSpace::TangentVector tmp;
+    localSolution[i].orthonormalFrame().mv(localEmbeddedGradient[i],tmp);
+    for (size_t j=0; j<blocksize; j++)
+      localGradient[i*blocksize+j] = tmp[j];
   }
 
   /////////////////////////////////////////////////////////////////
@@ -445,7 +447,7 @@ template <class Basis, class TargetSpace>
 void LocalGeodesicFEADOLCStiffness<Basis, TargetSpace>::
 assembleGradientAndHessian(const typename Basis::LocalView& localView,
                            const typename Dune::GFE::Impl::LocalStiffnessTypes<TargetSpace>::CompositeCoefficients& localConfiguration,
-                           typename Dune::GFE::Impl::LocalStiffnessTypes<TargetSpace>::CompositeGradient& localGradient,
+                           std::vector<double>& localGradient,
                            typename Dune::GFE::Impl::LocalStiffnessTypes<TargetSpace>::CompositeHessian& localHessian) const
 {
   using namespace Dune::Indices;
@@ -456,7 +458,7 @@ assembleGradientAndHessian(const typename Basis::LocalView& localView,
     //static_assert(localConfiguration.size()==1);
     return assembleGradientAndHessian(localView,
                                       localConfiguration[_0],
-                                      localGradient[_0],
+                                      localGradient,
                                       localHessian[_0][_0]);
   }
   else
@@ -513,15 +515,25 @@ assembleGradientAndHessian(const typename Basis::LocalView& localView,
         localEmbeddedGradient0[i][j] = g[idx++];
 
       // Express gradient in local coordinate system
-      localConfiguration[_0][i].orthonormalFrame().mv(localEmbeddedGradient0[i],localGradient[_0][i]);
+      typename TargetSpace0::TangentVector tmp;
+      localConfiguration[_0][i].orthonormalFrame().mv(localEmbeddedGradient0[i],tmp);
+
+      for (size_t j=0; j<blocksize0; j++)
+        localGradient[i*blocksize0+j] = tmp[j];
     }
 
+    auto offset = localConfiguration[_0].size()*blocksize0;
+
     for (size_t i=0; i<localConfiguration[_1].size(); i++) {
       for (size_t j=0; j<embeddedBlocksize1; j++)
         localEmbeddedGradient1[i][j] = g[idx++];
 
       // Express gradient in local coordinate system
-      localConfiguration[_1][i].orthonormalFrame().mv(localEmbeddedGradient1[i],localGradient[_1][i]);
+      typename TargetSpace1::TangentVector tmp;
+      localConfiguration[_1][i].orthonormalFrame().mv(localEmbeddedGradient1[i],tmp);
+
+      for (size_t j=0; j<blocksize1; j++)
+        localGradient[offset + i*blocksize1 + j] = tmp[j];
     }
 
     /////////////////////////////////////////////////////////////////
diff --git a/dune/gfe/assemblers/localgeodesicfefdstiffness.hh b/dune/gfe/assemblers/localgeodesicfefdstiffness.hh
index 6f4fe03a..b8c50b4c 100644
--- a/dune/gfe/assemblers/localgeodesicfefdstiffness.hh
+++ b/dune/gfe/assemblers/localgeodesicfefdstiffness.hh
@@ -53,7 +53,7 @@ public:
      The default implementation in this class uses a finite difference approximation */
   virtual void assembleGradient(const typename Basis::LocalView& localView,
                                 const std::vector<TargetSpace>& solution,
-                                std::vector<typename TargetSpace::TangentVector>& gradient) const override;
+                                std::vector<field_type>& gradient) const override;
 
   /** \brief Assemble the local tangent matrix and gradient at the current position
 
@@ -61,7 +61,7 @@ public:
    */
   virtual void assembleGradientAndHessian(const typename Basis::LocalView& localView,
                                           const std::vector<TargetSpace>& localSolution,
-                                          std::vector<typename TargetSpace::TangentVector>& localGradient,
+                                          std::vector<field_type>& localGradient,
                                           typename Dune::GFE::Impl::LocalStiffnessTypes<TargetSpace>::Hessian& localHessian) const override;
 
   /** \brief Assemble the local tangent matrix and gradient at the current position
@@ -70,7 +70,7 @@ public:
    */
   virtual void assembleGradientAndHessian(const typename Basis::LocalView& localView,
                                           const typename Dune::GFE::Impl::LocalStiffnessTypes<TargetSpace>::CompositeCoefficients& localSolution,
-                                          typename Dune::GFE::Impl::LocalStiffnessTypes<TargetSpace>::CompositeGradient& localGradient,
+                                          std::vector<field_type>& localGradient,
                                           typename Dune::GFE::Impl::LocalStiffnessTypes<TargetSpace>::CompositeHessian& localHessian) const override
   {
     DUNE_THROW(Dune::NotImplemented, "!");
@@ -84,7 +84,7 @@ template <class Basis, class TargetSpace, class field_type>
 void LocalGeodesicFEFDStiffness<Basis, TargetSpace, field_type>::
 assembleGradient(const typename Basis::LocalView& localView,
                  const std::vector<TargetSpace>& localSolution,
-                 std::vector<typename TargetSpace::TangentVector>& localGradient) const
+                 std::vector<field_type>& localGradient) const
 {
 
   // ///////////////////////////////////////////////////////////
@@ -125,9 +125,9 @@ assembleGradient(const typename Basis::LocalView& localView,
 
       field_type foo = (localEnergy_->energy(localView,forwardSolution) - localEnergy_->energy(localView, backwardSolution)) / (2*eps);
 #ifdef MULTIPRECISION
-      localGradient[i][j] = foo.template convert_to<double>();
+      localGradient[i*blocksize+j] = foo.template convert_to<double>();
 #else
-      localGradient[i][j] = foo;
+      localGradient[i*blocksize+j] = foo;
 #endif
 
     }
@@ -149,7 +149,7 @@ template <class Basis, class TargetSpace, class field_type>
 void LocalGeodesicFEFDStiffness<Basis, TargetSpace, field_type>::
 assembleGradientAndHessian(const typename Basis::LocalView& localView,
                            const std::vector<TargetSpace>& localSolution,
-                           std::vector<typename TargetSpace::TangentVector>& localGradient,
+                           std::vector<field_type>& localGradient,
                            typename Dune::GFE::Impl::LocalStiffnessTypes<TargetSpace>::Hessian& localHessian) const
 {
   // Number of degrees of freedom for this element
@@ -212,16 +212,16 @@ assembleGradientAndHessian(const typename Basis::LocalView& localView,
   //   Compute gradient by finite-difference approximation
   //////////////////////////////////////////////////////////////
 
-  localGradient.resize(localSolution.size());
+  localGradient.resize(nDofs*blocksize);
 
   for (size_t i=0; i<localSolution.size(); i++)
     for (int j=0; j<blocksize; j++)
     {
       field_type foo = (forwardEnergy[i][j] - backwardEnergy[i][j]) / (2*eps);
 #ifdef MULTIPRECISION
-      localGradient[i][j] = foo.template convert_to<double>();
+      localGradient[i*blocksize+j] = foo.template convert_to<double>();
 #else
-      localGradient[i][j] = foo;
+      localGradient[i*blocksize+j] = foo;
 #endif
     }
 
diff --git a/dune/gfe/assemblers/localgeodesicfestiffness.hh b/dune/gfe/assemblers/localgeodesicfestiffness.hh
index c32bf683..b7848210 100644
--- a/dune/gfe/assemblers/localgeodesicfestiffness.hh
+++ b/dune/gfe/assemblers/localgeodesicfestiffness.hh
@@ -17,7 +17,7 @@ namespace Dune::GFE
      */
     template<class TargetSpace>
     class LocalStiffnessTypes
-      : public LocalFirstOrderModelTypes<TargetSpace>
+      : public LocalEnergyTypes<TargetSpace>
     {
       // Number type
       typedef typename TargetSpace::ctype RT;
@@ -40,7 +40,7 @@ namespace Dune::GFE
      */
     template<class ... Factors>
     class LocalStiffnessTypes<ProductManifold<Factors...> >
-      : public LocalFirstOrderModelTypes<ProductManifold<Factors...> >
+      : public LocalEnergyTypes<ProductManifold<Factors...> >
     {
       using TargetSpace = ProductManifold<Factors...>;
 
@@ -84,14 +84,14 @@ public:
    */
   virtual void assembleGradientAndHessian(const typename Basis::LocalView& localView,
                                           const typename Dune::GFE::Impl::LocalStiffnessTypes<TargetSpace>::Coefficients& coefficients,
-                                          typename Dune::GFE::Impl::LocalStiffnessTypes<TargetSpace>::Gradient& localGradient,
+                                          std::vector<double>& localGradient,
                                           typename Dune::GFE::Impl::LocalStiffnessTypes<TargetSpace>::Hessian& localHessian) const = 0;
 
   /** \brief Assemble the local gradient and stiffness matrix at the current position -- Composite version
    */
   virtual void assembleGradientAndHessian(const typename Basis::LocalView& localView,
                                           const typename Dune::GFE::Impl::LocalStiffnessTypes<TargetSpace>::CompositeCoefficients& coefficients,
-                                          typename Dune::GFE::Impl::LocalStiffnessTypes<TargetSpace>::CompositeGradient& localGradient,
+                                          std::vector<double>& localGradient,
                                           typename Dune::GFE::Impl::LocalStiffnessTypes<TargetSpace>::CompositeHessian& localHessian) const = 0;
 };
 
diff --git a/dune/gfe/assemblers/mixedgfeassembler.hh b/dune/gfe/assemblers/mixedgfeassembler.hh
index 6b134d41..4df0b50a 100644
--- a/dune/gfe/assemblers/mixedgfeassembler.hh
+++ b/dune/gfe/assemblers/mixedgfeassembler.hh
@@ -192,10 +192,7 @@ assembleGradientAndHessian(const std::vector<TargetSpace0>& configuration0,
         localConfiguration[_1][i-nDofs0] = configuration1[multiIndex[1]];
     }
 
-    Dune::TupleVector<std::vector<Dune::FieldVector<double,blocksize0> >,
-        std::vector<Dune::FieldVector<double,blocksize1> > > localGradient;
-    localGradient[_0].resize(nDofs0);
-    localGradient[_1].resize(nDofs1);
+    std::vector<double> localGradient(nDofs0*blocksize0 + nDofs1*blocksize1);
 
     using Row0 = Dune::MultiTypeBlockVector<Dune::Matrix<Dune::FieldMatrix<double, blocksize0, blocksize0> >,
         Dune::Matrix<Dune::FieldMatrix<double, blocksize0, blocksize1> > >;
@@ -254,9 +251,11 @@ assembleGradientAndHessian(const std::vector<TargetSpace0>& configuration0,
 
       // Add local gradient to global gradient
       if (row[0] == 0)
-        gradient0[row[1]] += localGradient[_0][i];
+        for (std::size_t j=0; j<blocksize0; j++)
+          gradient0[row[1]][j] += localGradient[i*blocksize0 + j];
       else
-        gradient1[row[1]] += localGradient[_1][i-nDofs0];
+        for (std::size_t j=0; j<blocksize1; j++)
+          gradient1[row[1]][j] += localGradient[nDofs0*blocksize0 + (i-nDofs0)*blocksize1 + j];
     }
 
   }
diff --git a/test/adolctest.cc b/test/adolctest.cc
index 8b59ac4e..0dd4ec71 100644
--- a/test/adolctest.cc
+++ b/test/adolctest.cc
@@ -572,8 +572,8 @@ int main (int argc, char *argv[]) try
     compareMatrices(localADHessian, "AD scalar", localADVMHessian, "AD vector");
 
     // Assemble Riemannian derivatives
-    std::vector<Dune::FieldVector<double,blocksize> > localRiemannianADGradient(numOfBaseFct);
-    std::vector<Dune::FieldVector<double,blocksize> > localRiemannianFDGradient(numOfBaseFct);
+    std::vector<double> localRiemannianADGradient(numOfBaseFct*blocksize);
+    std::vector<double> localRiemannianFDGradient(numOfBaseFct*blocksize);
 
     Matrix<FieldMatrix<double,blocksize,blocksize> > localRiemannianADHessian;
     Matrix<FieldMatrix<double,blocksize,blocksize> > localRiemannianFDHessian;
-- 
GitLab