From 543146ef8130ed4cf4707e59d9e9cfef5dfeaedb Mon Sep 17 00:00:00 2001
From: Oliver Sander <oliver.sander@tu-dresden.de>
Date: Tue, 26 Jan 2016 06:44:10 +0100
Subject: [PATCH] Implement general surface normal fields for shells with
 nonplanar reference geometry

Previously, the NonplanarCosseratShellEnergy had the normal field of the unit sphere
hard-wired in the code.  With this patch, using general triangulated surface as
reference geometries is possible.
---
 dune/gfe/nonplanarcosseratshellenergy.hh | 15 ++++---
 dune/gfe/vertexnormals.hh                | 53 ++++++++++++++++++++++++
 src/cosserat-continuum.cc                |  3 ++
 3 files changed, 65 insertions(+), 6 deletions(-)
 create mode 100644 dune/gfe/vertexnormals.hh

diff --git a/dune/gfe/nonplanarcosseratshellenergy.hh b/dune/gfe/nonplanarcosseratshellenergy.hh
index a0b80b63..b995ccaa 100644
--- a/dune/gfe/nonplanarcosseratshellenergy.hh
+++ b/dune/gfe/nonplanarcosseratshellenergy.hh
@@ -181,10 +181,12 @@ public:
    * \param parameters The material parameters
    */
   NonplanarCosseratShellEnergy(const Dune::ParameterTree& parameters,
+                               const std::vector<UnitVector<double,3> >& vertexNormals,
                                const BoundaryPatch<GridView>* neumannBoundary,
                                const std::shared_ptr<Dune::VirtualFunction<Dune::FieldVector<double,dimworld>, Dune::FieldVector<double,3> > > neumannFunction,
                                const std::shared_ptr<Dune::VirtualFunction<Dune::FieldVector<double,dimworld>, Dune::FieldVector<double,3> > > volumeLoad)
-  : neumannBoundary_(neumannBoundary),
+  : vertexNormals_(vertexNormals),
+    neumannBoundary_(neumannBoundary),
     neumannFunction_(neumannFunction),
     volumeLoad_(volumeLoad)
   {
@@ -248,6 +250,9 @@ public:
   /** \brief Curvature parameters */
   double b1_, b2_, b3_;
 
+  /** \brief The normal vectors at the grid vertices.  This are used to compute the reference surface curvature. */
+  std::vector<UnitVector<double,3> > vertexNormals_;
+
   /** \brief The Neumann boundary */
   const BoundaryPatch<GridView>* neumannBoundary_;
 
@@ -274,14 +279,12 @@ energy(const typename Basis::LocalView& localView,
   ////////////////////////////////////////////////////////////////////////////////////
   //  Construct a linear (i.e., non-constant!) normal field on the surface
   ////////////////////////////////////////////////////////////////////////////////////
+  auto gridView = localView.globalBasis().gridView();
 
+  assert(vertexNormals_.size() == gridView.indexSet().size(gridDim));
   std::vector<UnitVector<double,3> > cornerNormals(element.subEntities(gridDim));
   for (size_t i=0; i<cornerNormals.size(); i++)
-  {
-    // TODO: WARNING WARNING WARNING:  Shape is hard-coded here!
-    // The sphere:
-    cornerNormals[i] = geometry.corner(i) / geometry.corner(i).two_norm();
-  }
+    cornerNormals[i] = vertexNormals_[gridView.indexSet().subIndex(element,i,2)];
 
   typedef typename Dune::PQkLocalFiniteElementCache<DT, double, gridDim, 1> P1FiniteElementCache;
   typedef typename P1FiniteElementCache::FiniteElementType P1LocalFiniteElement;
diff --git a/dune/gfe/vertexnormals.hh b/dune/gfe/vertexnormals.hh
new file mode 100644
index 00000000..fb899e0e
--- /dev/null
+++ b/dune/gfe/vertexnormals.hh
@@ -0,0 +1,53 @@
+// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+// vi: set et ts=4 sw=2 sts=2:
+#ifndef DUNE_GFE_VERTEXNORMALS_HH
+#define DUNE_GFE_VERTEXNORMALS_HH
+
+#include <vector>
+
+#include <dune/common/fvector.hh>
+
+#include <dune/geometry/referenceelements.hh>
+
+#include <dune/gfe/unitvector.hh>
+
+/** \brief Compute averaged vertex normals for a 2d-in-3d grid
+ */
+template <class GridView>
+std::vector<UnitVector<typename GridView::ctype,3> > computeVertexNormals(const GridView& gridView)
+{
+  const auto& indexSet = gridView.indexSet();
+
+  assert(GridView::dimension == 2);
+
+  std::vector<Dune::FieldVector<typename GridView::ctype,3> > unscaledNormals(indexSet.size(2));
+  std::fill(unscaledNormals.begin(), unscaledNormals.end(), Dune::FieldVector<typename GridView::ctype,3>(0.0));
+
+  for (const auto& element : elements(gridView))
+  {
+    for (int i=0; i<element.subEntities(2); i++)
+    {
+      auto cornerPos = Dune::ReferenceElements<double,2>::general(element.type()).position(i,2);
+      auto tangent = element.geometry().jacobianTransposed(cornerPos);
+      auto cornerNormal = Arithmetic::crossProduct(tangent[0], tangent[1]);
+      cornerNormal /= cornerNormal.two_norm();
+
+      unscaledNormals[indexSet.subIndex(element,i,2)] += cornerNormal;
+    }
+  }
+
+  // Normalize
+  for (auto& normal : unscaledNormals)
+    normal /= normal.two_norm();
+
+  // Convert array of vectors to array of UnitVectors
+  std::vector<UnitVector<typename GridView::ctype,3> > result(indexSet.size(2));
+
+  for (std::size_t i=0; i<unscaledNormals.size(); i++)
+    result[i] = unscaledNormals[i];
+
+  return result;
+}
+
+
+#endif
\ No newline at end of file
diff --git a/src/cosserat-continuum.cc b/src/cosserat-continuum.cc
index 58aafbd8..ec7e405d 100644
--- a/src/cosserat-continuum.cc
+++ b/src/cosserat-continuum.cc
@@ -43,6 +43,7 @@
 #include <dune/gfe/vtkreader.hh>
 #include <dune/gfe/geodesicfeassembler.hh>
 #include <dune/gfe/riemanniantrsolver.hh>
+#include <dune/gfe/vertexnormals.hh>
 
 // grid dimension
 const int dim = 2;
@@ -311,7 +312,9 @@ int main (int argc, char *argv[]) try
     }
     else
     {
+      std::vector<UnitVector<double,3> > vertexNormals = computeVertexNormals(gridView);
       cosseratEnergyADOLCLocalStiffness = std::make_shared<NonplanarCosseratShellEnergy<FEBasis,3,adouble> >(materialParameters,
+                                                                                                             std::move(vertexNormals),
                                                                                                              &neumannBoundary,
                                                                                                              neumannFunction,
                                                                                                              volumeLoad);
-- 
GitLab