From dde70eb727a4cf5af07ca6c65d8c9ce65ebc397d Mon Sep 17 00:00:00 2001
From: Oliver Sander <oliver.sander@tu-dresden.de>
Date: Mon, 21 Oct 2019 17:18:56 +0200
Subject: [PATCH] New test for the RigidBodyMotion class

In particular, we move the test for the computeDR method from
cosseratenergytest.cc to here.  It is a method that does not
have anything to do with Cosserat mechanics directly.

The test still seems overly complicated.  Do I really need
a LocalGeodesicFEFunction?  Maybe I can simplify it later.
---
 test/CMakeLists.txt         |   1 +
 test/cosseratenergytest.cc  | 127 ----------------------------------
 test/rigidbodymotiontest.cc | 131 ++++++++++++++++++++++++++++++++++++
 3 files changed, 132 insertions(+), 127 deletions(-)
 create mode 100644 test/rigidbodymotiontest.cc

diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt
index 68a1dafe..5c737a11 100644
--- a/test/CMakeLists.txt
+++ b/test/CMakeLists.txt
@@ -9,6 +9,7 @@ set(TESTS
   localgfetestfunctiontest
   localprojectedfefunctiontest
   orthogonalmatrixtest
+  rigidbodymotiontest
   rodassemblertest
   rotationtest
   svdtest
diff --git a/test/cosseratenergytest.cc b/test/cosseratenergytest.cc
index 05dc2011..256fba6f 100644
--- a/test/cosseratenergytest.cc
+++ b/test/cosseratenergytest.cc
@@ -1,7 +1,6 @@
 #include "config.h"
 
 #include <dune/grid/uggrid.hh>
-#include <dune/grid/onedgrid.hh>
 
 #include <dune/geometry/type.hh>
 #include <dune/geometry/quadraturerules.hh>
@@ -23,19 +22,6 @@ typedef RigidBodyMotion<double,3> TargetSpace;
 using namespace Dune;
 
 
-/** \brief Computes the diameter of a set */
-template <class TargetSpace>
-double diameter(const std::vector<TargetSpace>& v)
-{
-    double d = 0;
-    for (size_t i=0; i<v.size(); i++)
-        for (size_t j=0; j<v.size(); j++)
-            d = std::max(d, Rotation<double,3>::distance(v[i].q,v[j].q));
-    return d;
-}
-
-
-
 // ////////////////////////////////////////////////////////
 //   Make a test grid consisting of a single simplex
 // ////////////////////////////////////////////////////////
@@ -64,83 +50,6 @@ std::unique_ptr<GridType> makeSingleSimplexGrid()
 }
 
 
-template <int domainDim,class LocalFiniteElement>
-Tensor3<double,3,3,domainDim> evaluateDerivativeFD(const LocalGeodesicFEFunction<domainDim,double,LocalFiniteElement,TargetSpace>& f,
-                                           const Dune::FieldVector<double,domainDim>& local)
-{
-    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]  += eps;
-        backward[i] -= eps;
-
-        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*eps);
-        
-        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
-    PQkLocalFiniteElementCache<double,double,domainDim,1> feCache;
-    typedef typename PQkLocalFiniteElementCache<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;
-        typedef Dune::Functions::LagrangeBasis<typename UGGrid<domainDim>::LeafGridView,1> FEBasis;
-        CosseratEnergyLocalStiffness<FEBasis,3>::computeDR(f.evaluate(quadPos),derivative, DR);
-
-        // 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);
-        }
-
-    }
-}
-
 //////////////////////////////////////////////////////////////////////////////////////
 //   Test invariance of the energy functional under rotations
 //////////////////////////////////////////////////////////////////////////////////////
@@ -256,42 +165,6 @@ int main(int argc, char** argv)
 
     const int domainDim = 2;
 
-    // ////////////////////////////////////////////////////////
-    //   Make a test grid consisting of a single simplex
-    // ////////////////////////////////////////////////////////
-
-    typedef UGGrid<domainDim> GridType;
-    const std::unique_ptr<GridType> grid = makeSingleSimplexGrid<GridType>();
-
-    ////////////////////////////////////////////////////////////////////////////
-    //  Create a local assembler object
-    ////////////////////////////////////////////////////////////////////////////
-
-    typedef Dune::Functions::LagrangeBasis<typename GridType::LeafGridView,1> Basis;
-    Basis basis(grid->leafGridView());
-
-    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);
-    }
-    
     //////////////////////////////////////////////////////////////////////////////////////
     //   Test invariance of the energy functional under rotations
     //////////////////////////////////////////////////////////////////////////////////////
diff --git a/test/rigidbodymotiontest.cc b/test/rigidbodymotiontest.cc
new file mode 100644
index 00000000..58d9f5c1
--- /dev/null
+++ b/test/rigidbodymotiontest.cc
@@ -0,0 +1,131 @@
+#include "config.h"
+
+#include <dune/geometry/type.hh>
+#include <dune/geometry/quadraturerules.hh>
+
+#include <dune/grid/uggrid.hh>
+
+#include <dune/functions/functionspacebases/lagrangebasis.hh>
+
+#include <dune/gfe/rigidbodymotion.hh>
+#include <dune/gfe/cosseratenergystiffness.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
+    PQkLocalFiniteElementCache<double,double,domainDim,1> feCache;
+    typedef typename PQkLocalFiniteElementCache<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;
+        typedef Dune::Functions::LagrangeBasis<typename UGGrid<domainDim>::LeafGridView,1> FEBasis;
+        CosseratEnergyLocalStiffness<FEBasis,3>::computeDR(f.evaluate(quadPos),derivative, DR);
+
+        // 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);
+  }
+}
-- 
GitLab