diff --git a/dune/gfe/surfacecosseratstressassembler.hh b/dune/gfe/surfacecosseratstressassembler.hh
new file mode 100644
index 0000000000000000000000000000000000000000..b8246b8fa47a2826bbc63a915bd21924a4fdb15c
--- /dev/null
+++ b/dune/gfe/surfacecosseratstressassembler.hh
@@ -0,0 +1,308 @@
+#ifndef DUNE_GFE_SURFACECOSSERATSTRESSASSEMBLER_HH
+#define DUNE_GFE_SURFACECOSSERATSTRESSASSEMBLER_HH
+
+#include <dune/fufem/boundarypatch.hh>
+
+#include <dune/gfe/linearalgebra.hh>
+#include <dune/gfe/rotation.hh>
+#include <dune/gfe/localgeodesicfefunction.hh>
+
+#include <dune/matrix-vector/transpose.hh>
+
+namespace Dune::GFE {
+  /** \brief An assembler that can calculate the norms of specific stress tensors for each element for an output by film-on-substrate
+
+    \tparam BasisOrderD Basis used for the displacement
+    \tparam BasisOrderR Basis used for the rotation
+    \tparam TargetSpaceD Target space for the Displacement
+    \tparam TargetSpaceR Target space for the Rotation
+  */
+  template <class BasisOrderD, class BasisOrderR, class TargetSpaceD, class TargetSpaceR>
+  class SurfaceCosseratStressAssembler
+  {
+    public:
+      const static int dim = TargetSpaceD::dimension;
+      using GridView = typename BasisOrderD::GridView;
+      using VectorD = std::vector<TargetSpaceD>;
+      using VectorR = std::vector<TargetSpaceR>;
+
+      BasisOrderD basisOrderD_;
+      BasisOrderR basisOrderR_;
+
+      SurfaceCosseratStressAssembler(const BasisOrderD basisOrderD,
+                                     const BasisOrderR basisOrderR)
+      : basisOrderD_(basisOrderD),
+        basisOrderR_(basisOrderR)
+      {}
+
+      /** \brief Calculate the norm of the 1st-Piola-Kirchhoff-Stress-Tensor and the Cauchy-Stress-Tensor for each element
+
+          The 1st-Piola-Kirchhoff-Stress-Tensor is the derivative of the energy density with respect to the deformation gradient
+          - Calculate the deformation gradient for each element using the basis functions and
+            their gradients; then add them up using the localConfiguration
+          - Evaluate the deformation gradient at each quadrature point using the respective quadrature rule with the given order
+          - Evaluate the density function and tape the evaluation - then use ADOLC to evaluate the derivative (∂/∂F) W(F)
+          - The derivative is then a dim x dim matrix
+          - Then calculate the final stressTensor of the element by averagin over the quadrature points using the quadrature
+            weights and the reference element volume
+        \param x Coefficient vector for the displacement
+        \param elasticDensity Energy density function
+        \param int Order of the quadrature rule
+        \param stressSubstrate1stPiolaKirchhoffTensor Vector containing the the 1st-Piola-Kirchhoff-Stress-Tensor for each element
+        \param stressSubstrateCauchyTensor Vector containing the Cauchy-Stress-Tensor for each element
+     */
+      template <class Density>
+      void assembleSubstrateStress(
+        const VectorD x,
+        const Density* elasticDensity,
+        const int quadOrder,
+        std::vector<FieldMatrix<double,dim,dim>>& stressSubstrate1stPiolaKirchhoffTensor,
+        std::vector<FieldMatrix<double,dim,dim>>& stressSubstrateCauchyTensor)
+      {
+
+        std::cout << "Calculating the Frobenius norm of the 1st-Piola-Kirchhoff-Stress-Tensor ( (∂/∂F) W(F) )" << std::endl
+                  << "and the Frobenius norm of the Cauchy-Stress-Tensor (1/det(F) * (∂/∂F) W(F) * F^T) of the substrate..." << std::endl;
+
+        auto xFlat = Functions::istlVectorBackend(x);
+        static constexpr auto partitionType = Partitions::interiorBorder;
+        MultipleCodimMultipleGeomTypeMapper<GridView> elementMapper(basisOrderD_.gridView(),mcmgElementLayout());
+        stressSubstrate1stPiolaKirchhoffTensor.resize(elementMapper.size());
+        stressSubstrateCauchyTensor.resize(elementMapper.size());
+
+        for (const auto& element : elements(basisOrderD_.gridView(), partitionType))
+        {
+          auto localViewOrderD = basisOrderD_.localView();
+          localViewOrderD.bind(element);
+          size_t nDofsOrderD = localViewOrderD.tree().size();
+
+          // Extract values at this element
+          std::vector<double> localConfiguration(nDofsOrderD);
+          for (int i=0; i<nDofsOrderD; i++)
+            localConfiguration[i] = xFlat[localViewOrderD.index(i)]; //localViewOrderD.index(i) is a multi-index
+
+          //Store the reference gradient and the gradients for this element
+          const auto& lFEOrderD = localViewOrderD.tree().child(0).finiteElement();
+          std::vector<FieldMatrix<double,1,dim> > referenceGradients(lFEOrderD.size());
+          std::vector<FieldMatrix<double,1,dim> > gradients(lFEOrderD.size());
+
+          auto evaluateAtPoint = [&](FieldVector<double,3> pointGlobal, FieldVector<double,3> pointLocal) -> std::vector<FieldMatrix<double,dim,dim>>{
+            std::vector<FieldMatrix<double,dim,dim>> stressTensors(2);
+
+            const auto jacobianInverseTransposed = element.geometry().jacobianInverseTransposed(pointLocal);
+
+            // Get gradients of shape functions
+            lFEOrderD.localBasis().evaluateJacobian(pointLocal, referenceGradients);
+
+            // Compute gradients of Base functions
+            for (size_t i=0; i<gradients.size(); ++i)
+              gradients[i] = referenceGradients[i] * transpose(jacobianInverseTransposed);
+              //jacobianInverseTransposed.mv(referenceGradients[i][0], gradients[i]);
+
+            // Deformation gradient in vector form
+            size_t nDoubles = dim*dim;
+            std::vector<double> deformationGradientFlat(nDoubles);
+            for (size_t i=0; i<nDoubles; i++)
+              deformationGradientFlat[i] = 0;
+            for (size_t i=0; i<gradients.size(); i++)
+              for (size_t j=0; j<dim; j++)
+                for (size_t k=0; k<dim; k++)
+                  deformationGradientFlat[dim*j + k] += localConfiguration[ localViewOrderD.tree().child(j).localIndex(i)]*gradients[i][0][k];
+
+            double pureDensity = 0;
+
+            trace_on(0);
+
+            FieldMatrix<adouble,dim,dim> deformationGradient(0);
+            for (size_t j=0; j<dim; j++)
+              for (size_t k=0; k<dim; k++)
+                deformationGradient[j][k] <<= deformationGradientFlat[dim*j + k];
+
+            // Tape the actual calculation
+            adouble density = 0;
+            try {
+              density = (*elasticDensity)(pointGlobal, deformationGradient);
+            } catch (Exception &e) {
+              trace_off(0);
+              throw e;
+            }
+            density >>= pureDensity;
+
+            trace_off(0);
+
+            // Compute the actual gradient
+            std::vector<double> localStressFlat(nDoubles);
+            gradient(0,nDoubles,deformationGradientFlat.data(),localStressFlat.data());
+
+            FieldMatrix<double,dim,dim> localStress(0);
+            for (size_t j=0; j<dim; j++)
+              for (size_t k=0; k<dim; k++)
+                localStress[j][k] = localStressFlat[dim*j + k];
+
+            stressTensors[0] = localStress; // 1st-Piola-Kirchhoff-Stress-Tensor
+
+            FieldMatrix<double,dim,dim> deformationGradientTransposed(0);
+            for (size_t j=0; j<dim; j++)
+              for (size_t k=0; k<dim; k++)
+                deformationGradient[j][k] >>= deformationGradientTransposed[k][j];
+
+            localStress /= deformationGradientTransposed.determinant();
+            localStress = localStress * deformationGradientTransposed;
+            stressTensors[1] = localStress; // Cauchy-Stress-Tensor
+
+            return stressTensors;
+          };
+
+          //Call evaluateAtPoint for all points in the quadrature rule
+          const auto& quad = Dune::QuadratureRules<double, dim>::rule(element.type(), quadOrder);
+          stressSubstrate1stPiolaKirchhoffTensor[elementMapper.index(element)] = 0;
+          stressSubstrateCauchyTensor[elementMapper.index(element)] = 0;
+
+          for (size_t pt=0; pt<quad.size(); pt++) {
+            auto pointLocal = quad[pt].position();
+            auto pointGlobal = element.geometry().global(pointLocal);
+            auto stressTensors = evaluateAtPoint(pointGlobal, pointLocal);
+            stressSubstrate1stPiolaKirchhoffTensor[elementMapper.index(element)] += stressTensors[0] * quad[pt].weight()/referenceElement(element).volume();
+            stressSubstrateCauchyTensor[elementMapper.index(element)] += stressTensors[1] * quad[pt].weight()/referenceElement(element).volume();
+          }
+        }
+      }
+      /** \brief  Calculate the norm of the Biot-Type-Stress-Tensor of the shell
+
+          The formula for Biot-Type-Stress-Tensor of the Cosserat shell given by (4.11) in 
+          Ghiba, Bîrsan, Lewintan, Neff, March 2020: "The isotropic Cosserat shell model including terms up to $O(h^5)$. Part I: Derivation in matrix notation"
+        \param rot Coefficient vector for the rotation
+        \param x Coefficient vector for the displacement
+        \param xInitial Coefficient vector for the stress-free configuration of the shell, used to calculate nablaTheta
+        \param lameF Function assinging the lamé parameters to a given point
+        \param mu_c Cosserat couple modulus
+        \param shellBoundary BoundaryPatch containing the elements that actually belong to the shell
+        \param order Order of the quadrature rule
+        \param stressShellBiotTensor Vector containing the Biot-Stress-Tensor for each element
+      */
+      void assembleShellStress(
+        const VectorR rot,
+        const VectorD x,
+        const VectorD xInitial,
+        const std::function<Dune::FieldVector<double,2>(Dune::FieldVector<double,dim>)> lameF,
+        const double mu_c,
+        const BoundaryPatch<GridView> shellBoundary,
+        const int quadOrder,
+        std::vector<FieldMatrix<double,dim,dim>>& stressShellBiotTensor)
+      {
+        std::cout << "Calculating the Frobenius norm of the Biot-Type-Stress-Tensor of the shell..." << std::endl;
+        auto xFlat = Functions::istlVectorBackend(x);
+        auto xInitialFlat = Functions::istlVectorBackend(xInitial);
+
+        MultipleCodimMultipleGeomTypeMapper<GridView> elementMapper(basisOrderD_.gridView(),mcmgElementLayout());
+        stressShellBiotTensor.resize(elementMapper.size());
+
+        static constexpr auto partitionType = Partitions::interiorBorder;
+        for (const auto& element : elements(basisOrderD_.gridView(), partitionType))
+        {
+          stressShellBiotTensor[elementMapper.index(element)] = 0;
+
+          int intersectionCounter = 0;
+          for (auto&& it : intersections(shellBoundary.gridView(), element)) {
+            FieldMatrix<double,dim,dim> stressTensorThisIntersection(0);
+
+            //Continue if the element does not intersect with the shell boundary
+            if (not shellBoundary.contains(it))
+              continue;
+
+            //LocalView for the basisOrderD_
+            auto localViewOrderD = basisOrderD_.localView();
+            localViewOrderD.bind(element);
+            size_t nDofsOrderD = localViewOrderD.tree().size();
+
+            // Extract local configuration at this element
+            std::vector<double> localConfiguration(nDofsOrderD);
+            std::vector<double> localConfigurationInitial(nDofsOrderD);
+            for (int i=0; i<nDofsOrderD; i++) {
+              localConfiguration[i] = xFlat[localViewOrderD.index(i)];
+              localConfigurationInitial[i] = xInitialFlat[localViewOrderD.index(i)];
+            }
+
+            const auto& lFEOrderD = localViewOrderD.tree().child(0).finiteElement();
+            //Store the reference gradient and the gradients for *this element*
+            std::vector<FieldMatrix<double,1,dim> > referenceGradients(lFEOrderD.size());
+            std::vector<FieldMatrix<double,1,dim> > gradients(lFEOrderD.size());
+
+            //LocalView for the basisOrderR_
+            auto localViewOrderR = basisOrderR_.localView();
+            localViewOrderR.bind(element);
+            const auto& lFEOrderR = localViewOrderR.tree().child(0).finiteElement();
+            VectorR localConfigurationRot(lFEOrderR.size());
+            for (int i=0; i<localConfigurationRot.size(); i++)
+              localConfigurationRot[i] = rot[localViewOrderR.index(i)[0]];//localViewOrderR.index(i) is a multiindex, its first entry is the actual index
+            typedef LocalGeodesicFEFunction<dim, double, decltype(lFEOrderR), TargetSpaceR> LocalGFEFunctionType;
+            LocalGFEFunctionType localGeodesicFEFunction(lFEOrderR,localConfigurationRot);
+            
+            auto evaluateAtPoint = [&](FieldVector<double,3> pointGlobal, FieldVector<double,3> pointLocal3d) -> FieldMatrix<double,dim,dim>{
+              Dune::FieldMatrix<double,dim,dim> nablaTheta;
+
+              const auto jacobianInverseTransposed = element.geometry().jacobianInverseTransposed(pointLocal3d);
+
+              // Get gradients of shape functions
+              lFEOrderD.localBasis().evaluateJacobian(pointLocal3d, referenceGradients);
+
+              // Compute gradients of Base functions at this element
+              for (size_t i=0; i<gradients.size(); i++)
+                gradients[i] = referenceGradients[i] * transpose(jacobianInverseTransposed);
+
+                //jacobianInverseTransposed.mv(referenceGradients[i][0], gradients[i]);
+
+              // Deformation gradient - call this U_es_minus_Id already
+              FieldMatrix<double,dim,dim> U_es_minus_Id(0);
+              for (size_t i=0; i<gradients.size(); i++)
+                for (size_t j=0; j<dim; j++){
+                  U_es_minus_Id[j].axpy(localConfiguration[ localViewOrderD.tree().child(j).localIndex(i)],gradients[i][0]);
+                  nablaTheta[j].axpy(localConfigurationInitial[ localViewOrderD.tree().child(j).localIndex(i)],gradients[i][0]);
+                }
+
+              TargetSpaceR value = localGeodesicFEFunction.evaluate(pointLocal3d);
+              FieldMatrix<double,dim,dim> rotationMatrix(0);
+              FieldMatrix<double,dim,dim> rotationMatrixTransposed(0);
+              value.matrix(rotationMatrix);
+
+              MatrixVector::transpose(rotationMatrix, rotationMatrixTransposed);
+
+              U_es_minus_Id.leftmultiply(rotationMatrixTransposed); // Attention: The rotation here is already is Q_e, we don't have to multiply with Q_0!!!
+
+              nablaTheta.invert();
+              U_es_minus_Id.rightmultiply(nablaTheta);
+
+              for (size_t j = 0; j < dim; j++)
+                U_es_minus_Id[j][j] -= 1.0;
+
+              auto lameConstants = lameF(pointGlobal);
+              double mu = lameConstants[0];
+              double lambda = lameConstants[1];
+
+              FieldMatrix<double,dim,dim> localStressShell(0);
+              localStressShell = 2*mu*GFE::sym(U_es_minus_Id) + 2*mu_c*GFE::skew(U_es_minus_Id);
+              for (size_t j = 0; j < dim; j++)
+                localStressShell[j][j] += lambda*GFE::trace(GFE::sym(U_es_minus_Id));
+              return localStressShell;
+            };
+
+            //Call evaluateAtPoint for all points in the quadrature rule
+            const auto& quad = Dune::QuadratureRules<double, dim-1>::rule(it.type(), quadOrder); //Quad rule on the boundary 
+
+            for (size_t pt=0; pt<quad.size(); pt++) {
+              auto pointLocal2d = quad[pt].position();
+              auto pointLocal3d = it.geometryInInside().global(pointLocal2d);
+              auto pointGlobal = it.geometry().global(pointLocal2d);
+
+              auto stressTensor = evaluateAtPoint(pointGlobal, pointLocal3d);
+              stressTensorThisIntersection += stressTensor * quad[pt].weight()/referenceElement(it.inside()).volume();
+            }
+            stressShellBiotTensor[elementMapper.index(element)] += stressTensorThisIntersection;
+            intersectionCounter++;
+          }
+          if (intersectionCounter >= 1)
+            stressShellBiotTensor[elementMapper.index(element)] /= intersectionCounter;
+        }
+      }
+  };
+}
+#endif
\ No newline at end of file
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index ada923056911e2df35c4ef47120577a3c080cd47..e3e958a6d9fccd3a32402361e945f88671491889 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -5,6 +5,9 @@ set(programs compute-disc-error
              rod3d)
 #            rodobstacle)
 
+if (${DUNE_ELASTICITY_VERSION} VERSION_GREATER_EQUAL 2.8)
+  set(programs film-on-substrate-stress-plot ${programs})
+endif()
 if (dune-parmg_FOUND AND dune-curvedgeometry_FOUND AND ${DUNE_ELASTICITY_VERSION} VERSION_GREATER_EQUAL 2.8)
 	set(programs film-on-substrate ${programs})
 endif()
diff --git a/src/film-on-substrate-stress-plot.cc b/src/film-on-substrate-stress-plot.cc
new file mode 100644
index 0000000000000000000000000000000000000000..a5a7c37add55d933f4a10eaf903be108e2fb27a7
--- /dev/null
+++ b/src/film-on-substrate-stress-plot.cc
@@ -0,0 +1,335 @@
+#include <iostream>
+#include <fstream>
+
+#include <config.h>
+
+// Includes for the ADOL-C automatic differentiation library
+// Need to come before (almost) all others.
+#include <adolc/adouble.h>
+#include <adolc/drivers/drivers.h>    // use of "Easy to Use" drivers
+#include <adolc/taping.h>
+
+#include <dune/fufem/utilities/adolcnamespaceinjections.hh>
+
+#include <dune/common/parametertree.hh>
+#include <dune/common/parametertreeparser.hh>
+#include <dune/common/version.hh>
+
+#include <dune/elasticity/materials/exphenckydensity.hh>
+#include <dune/elasticity/materials/henckydensity.hh>
+#include <dune/elasticity/materials/mooneyrivlindensity.hh>
+#include <dune/elasticity/materials/neohookedensity.hh>
+#include <dune/elasticity/materials/stvenantkirchhoffdensity.hh>
+
+#include <dune/functions/functionspacebases/interpolate.hh>
+#include <dune/functions/functionspacebases/lagrangebasis.hh>
+#include <dune/functions/functionspacebases/powerbasis.hh>
+#include <dune/functions/gridfunctions/discreteglobalbasisfunction.hh>
+
+#include <dune/fufem/dunepython.hh>
+
+#include <dune/grid/uggrid.hh>
+#include <dune/grid/utility/structuredgridfactory.hh>
+#include <dune/grid/io/file/gmshreader.hh>
+#include <dune/grid/io/file/vtk.hh>
+
+#include <dune/gfe/filereader.hh>
+#include <dune/gfe/rotation.hh>
+#include <dune/gfe/surfacecosseratstressassembler.hh>
+
+// grid dimension
+#ifndef WORLD_DIM
+#  define WORLD_DIM 3
+#endif
+const int dim = WORLD_DIM;
+
+const int displacementOrder = 2;
+const int rotationOrder = 2;
+
+using namespace Dune;
+using ValueType = adouble;
+
+int main (int argc, char *argv[]) try
+{
+  MPIHelper& mpiHelper = MPIHelper::instance(argc, argv);
+
+  // Start Python interpreter
+  Python::start();
+  Python::Reference main = Python::import("__main__");
+  Python::run("import math");
+
+  //feenableexcept(FE_INVALID);
+  Python::runStream()
+        << std::endl << "import sys"
+        << std::endl << "import os"
+        << std::endl << "sys.path.append(os.getcwd() + '/../../problems/')"
+        << std::endl;
+
+  // parse data file
+  ParameterTree parameterSet;
+
+  ParameterTreeParser::readINITree(argv[1], parameterSet);
+
+  ParameterTreeParser::readOptions(argc, argv, parameterSet);
+
+  /////////////////////////////////////////////////////////////
+  //                      CREATE THE GRID
+  /////////////////////////////////////////////////////////////
+  typedef UGGrid<dim> GridType;
+
+  std::shared_ptr<GridType> grid;
+
+  FieldVector<double,dim> lower(0), upper(1);
+
+
+  if (parameterSet.get<bool>("structuredGrid")) {
+
+    lower = parameterSet.get<FieldVector<double,dim> >("lower");
+    upper = parameterSet.get<FieldVector<double,dim> >("upper");
+
+    std::array<unsigned int,dim> elements = parameterSet.get<std::array<unsigned int,dim> >("elements");
+    grid = StructuredGridFactory<GridType>::createCubeGrid(lower, upper, elements);
+
+  } else {
+    std::string path                = parameterSet.get<std::string>("path");
+    std::string gridFile            = parameterSet.get<std::string>("gridFile");
+    grid = std::shared_ptr<GridType>(GmshReader<GridType>::read(path + "/" + gridFile));
+  }
+
+  grid->setRefinementType(GridType::RefinementType::COPY);
+
+  // Surface Shell Boundary
+  std::string lambda = std::string("lambda x: (") + parameterSet.get<std::string>("surfaceShellVerticesPredicate", "0") + std::string(")");
+  auto pythonSurfaceShellVertices = Python::make_function<bool>(Python::evaluate(lambda));
+
+  int numLevels = parameterSet.get<int>("numLevels");
+ 
+  while (numLevels > 0) {
+    for (auto&& e : elements(grid->leafGridView())){
+      bool isSurfaceShell = false;
+      for (int i = 0; i < e.geometry().corners(); i++) {
+          isSurfaceShell = isSurfaceShell || pythonSurfaceShellVertices(e.geometry().corner(i));
+      }
+      grid->mark(isSurfaceShell ? 1 : 0,e);
+    }
+
+    grid->adapt();
+
+    numLevels--;
+  }
+
+  grid->loadBalance();
+
+  if (grid->leafGridView().comm().size() > 1)
+    DUNE_THROW(Exception,
+      std::string("To create a stress plot, please use only one process, now there are ") + std::to_string(grid->leafGridView().comm().size()) + std::string(" procsses."));
+  
+  typedef GridType::LeafGridView GridView;
+  GridView gridView = grid->leafGridView();
+
+  /////////////////////////////////////////////////////////////
+  //                   SURFACE SHELL BOUNDARY
+  /////////////////////////////////////////////////////////////
+
+  const GridView::IndexSet& indexSet = gridView.indexSet();
+  BitSetVector<1> surfaceShellVertices(gridView.size(dim), false);
+  for (auto&& v : vertices(gridView))
+  {
+    bool isSurfaceShell = pythonSurfaceShellVertices(v.geometry().corner(0));
+    surfaceShellVertices[indexSet.index(v)] = isSurfaceShell;
+  }
+  BoundaryPatch<GridView> surfaceShellBoundary(gridView, surfaceShellVertices);
+
+  /////////////////////////////////////////////////////////////
+  //                      FUNCTION SPACE
+  /////////////////////////////////////////////////////////////
+
+  using namespace Functions::BasisFactory;
+  auto basisOrderD = makeBasis(
+    gridView,
+    power<dim>(
+        lagrange<displacementOrder>()
+  ));
+
+  auto basisOrderR = makeBasis(
+    gridView,
+    power<dim>(
+        lagrange<rotationOrder>()
+  ));
+
+  /////////////////////////////////////////////////////////////
+  //                      INITIAL DATA
+  /////////////////////////////////////////////////////////////
+
+  // Read grid deformation information from the file specified in the parameter set via pathToOutput, deformationOutput, rotationOutput and initial deformation
+  const std::string pathToOutput = parameterSet.get("pathToOutput", "");
+
+  std::cout << "Reading in deformation file ("  << "order is "  << displacementOrder  << "): " << pathToOutput + parameterSet.get<std::string>("deformationOutput") << std::endl;
+  auto deformationMap = Dune::GFE::transformFileToMap<dim>(pathToOutput + parameterSet.get<std::string>("deformationOutput"));
+  std::cout << "... done: The basis has " << basisOrderD.size() << " elements and the defomation file has " << deformationMap.size() << " entries." << std::endl;
+
+  const auto dimRotation = Rotation<double,dim>::embeddedDim;
+  std::unordered_map<std::string, FieldVector<double,dimRotation>> rotationMap;
+  if (parameterSet.hasKey("rotationOutput")) {
+    std::cout << "Reading in rotation file ("  << "order is "  << rotationOrder  << "): " << pathToOutput + parameterSet.get<std::string>("rotationOutput") << std::endl;
+    rotationMap = Dune::GFE::transformFileToMap<dimRotation>(pathToOutput + parameterSet.get<std::string>("rotationOutput"));
+  }
+  const bool startFromFile = parameterSet.get<bool>("startFromFile");
+  std::unordered_map<std::string, FieldVector<double,dim>> initialDeformationMap;
+  
+  auto gridDeformationLambda = std::string("lambda x: (") + parameterSet.get<std::string>("gridDeformation") + std::string(")");
+  auto gridDeformation = Python::make_function<FieldVector<double,dim> >(Python::evaluate(gridDeformationLambda));
+
+  if (startFromFile) {
+    std::cout << "Reading in file to the stress-free configuration of the shell ("  << "order is "  << displacementOrder  << "): " <<  parameterSet.get("pathToGridDeformationFile", "") + parameterSet.get<std::string>("gridDeformationFile") << std::endl;
+    initialDeformationMap = Dune::GFE::transformFileToMap<dim>(parameterSet.get("pathToGridDeformationFile", "") + parameterSet.get<std::string>("gridDeformationFile"));
+  }
+
+  using DisplacementVector = std::vector<FieldVector<double,dim> >;
+  DisplacementVector x;
+  x.resize(basisOrderD.size());
+  DisplacementVector xInitial;
+  xInitial.resize(basisOrderD.size());
+  DisplacementVector displacement;
+  displacement.resize(basisOrderD.size());
+  
+  Functions::interpolate(basisOrderD, x, [](FieldVector<double,dim> x){ return x; });
+  Functions::interpolate(basisOrderD, xInitial, [](FieldVector<double,dim> x){ return x; });
+
+  for (int i = 0; i < basisOrderD.size(); i++) {
+    std::stringstream stream;
+    stream << x[i];
+    //Look up the displacement for this vertex in the deformationMap
+    displacement[i] = deformationMap.at(stream.str());
+    x[i] += deformationMap.at(stream.str());
+    //In case an a stress-free file was provided: look up the displacement for this vertex in the initialDeformationMap
+    if (startFromFile) {
+      xInitial[i] += initialDeformationMap.at(stream.str());
+    } else {
+      xInitial[i] = gridDeformation(xInitial[i]);
+    }
+  }
+
+  using RotationVector = std::vector<Rotation<double,dim>>;
+  RotationVector rot;
+  rot.resize(basisOrderR.size());
+  DisplacementVector xOrderR;
+  xOrderR.resize(basisOrderR.size());
+  Functions::interpolate(basisOrderR, xOrderR, [](FieldVector<double,dim> x){ return x; });
+  
+  using DirectorVector = std::vector<Dune::FieldVector<double,dim>>;
+  std::array<DirectorVector,3> rot_director;
+  rot_director[0].resize(basisOrderR.size());
+  rot_director[1].resize(basisOrderR.size());
+  rot_director[2].resize(basisOrderR.size());
+
+  for (int i = 0; i < basisOrderR.size(); i++) {
+    std::stringstream stream;
+    stream << xOrderR[i];
+    Rotation<double,dim> rotation(rotationMap.at(stream.str()));
+    FieldMatrix<double,dim,dim> rotationMatrix(0);
+    rotation.matrix(rotationMatrix);
+    rot[i].set(rotationMatrix);
+    for (int j = 0; j < 3; j++)
+      rot_director[j][i] = rot[i].director(j);
+  }
+
+  /////////////////////////////////////////////////////////////
+  //                      STRESS ASSEMBLER
+  /////////////////////////////////////////////////////////////
+  int quadOrder = parameterSet.hasKey("quadOrder") ? parameterSet.get<int>("quadOrder") : 4;
+
+  auto stressAssembler = GFE::SurfaceCosseratStressAssembler<decltype(basisOrderD),decltype(basisOrderR), FieldVector<double,dim>, Rotation<double,dim>>
+        (basisOrderD, basisOrderR);
+  
+
+  std::cout << "Selected energy is: " << parameterSet.get<std::string>("energy") << std::endl;
+  std::shared_ptr<Elasticity::LocalDensity<dim,ValueType>> elasticDensity;
+
+  const ParameterTree& materialParameters = parameterSet.sub("materialParameters");
+
+  if (parameterSet.get<std::string>("energy") == "stvenantkirchhoff")
+    elasticDensity = std::make_shared<Elasticity::StVenantKirchhoffDensity<dim,ValueType>>(materialParameters);
+  if (parameterSet.get<std::string>("energy") == "neohooke")
+    elasticDensity = std::make_shared<Elasticity::NeoHookeDensity<dim,ValueType>>(materialParameters);
+  if (parameterSet.get<std::string>("energy") == "hencky")
+    elasticDensity = std::make_shared<Elasticity::HenckyDensity<dim,ValueType>>(materialParameters);
+  if (parameterSet.get<std::string>("energy") == "exphencky")
+    elasticDensity = std::make_shared<Elasticity::ExpHenckyDensity<dim,ValueType>>(materialParameters);
+  if (parameterSet.get<std::string>("energy") == "mooneyrivlin")
+    elasticDensity = std::make_shared<Elasticity::MooneyRivlinDensity<dim,ValueType>>(materialParameters);
+
+  if(!elasticDensity)
+    DUNE_THROW(Exception, "Error: Selected energy not available!");      
+
+  Python::Reference surfaceShellClass = Python::import(materialParameters.get<std::string>("surfaceShellParameters"));
+  Python::Callable surfaceShellCallable = surfaceShellClass.get("SurfaceShellParameters");
+  Python::Reference pythonObject = surfaceShellCallable();
+  auto fLame = Python::make_function<FieldVector<double, 2> >(pythonObject.get("lame"));
+
+  std::vector<FieldMatrix<double,dim,dim>> stressSubstrate1stPiolaKirchhoffTensor;
+  std::vector<FieldMatrix<double,dim,dim>> stressSubstrateCauchyTensor;
+  std::cout << "Assemble stress for the substrate.." << std::endl;
+  stressAssembler.assembleSubstrateStress<Elasticity::LocalDensity<dim,ValueType>>(x, elasticDensity.get(), quadOrder, stressSubstrate1stPiolaKirchhoffTensor, stressSubstrateCauchyTensor);
+
+  std::vector<FieldMatrix<double,dim,dim>> stressShellBiotTensor;
+  std::cout << "Assemble stress for the shell.." << std::endl;
+  stressAssembler.assembleShellStress(rot, x, xInitial, fLame,/*mu_c*/0, surfaceShellBoundary, quadOrder, stressShellBiotTensor);
+
+  std::vector<double> stressSubstrate1stPiolaKirchhoff(stressSubstrate1stPiolaKirchhoffTensor.size());
+  std::vector<double> stressSubstrateCauchy(stressSubstrate1stPiolaKirchhoffTensor.size());
+  std::vector<double> stressSubstrateVonMises(stressSubstrate1stPiolaKirchhoffTensor.size());
+  std::vector<double> stressShellBiot(stressSubstrate1stPiolaKirchhoffTensor.size());
+
+  for (size_t i = 0; i < stressSubstrate1stPiolaKirchhoffTensor.size(); i++) {
+    stressSubstrate1stPiolaKirchhoff[i] = stressSubstrate1stPiolaKirchhoffTensor[i].frobenius_norm();
+    stressSubstrateCauchy[i] = stressSubstrateCauchyTensor[i].frobenius_norm();
+
+    double vonMises = 0; //von-Mises-Stress
+    for(size_t j=0; j<dim; j++) {
+      int jplus1 = (j+1) % dim;
+      vonMises += 0.5*(stressSubstrate1stPiolaKirchhoffTensor[i][j][j] - stressSubstrate1stPiolaKirchhoffTensor[i][jplus1][jplus1])*(stressSubstrate1stPiolaKirchhoffTensor[i][j][j] - stressSubstrate1stPiolaKirchhoffTensor[i][jplus1][jplus1]);
+      vonMises += 3*stressSubstrate1stPiolaKirchhoffTensor[i][j][jplus1]*stressSubstrate1stPiolaKirchhoffTensor[i][j][jplus1];
+    }
+    stressSubstrateVonMises[i] = std::sqrt(vonMises);
+
+    stressShellBiot[i] = stressShellBiotTensor[i].frobenius_norm();
+  }
+
+  
+  auto displacementFunction = Functions::makeDiscreteGlobalBasisFunction<FieldVector<double,dim>>(basisOrderD, displacement);
+
+  auto director0Function = Functions::makeDiscreteGlobalBasisFunction<FieldVector<double,dim>>(basisOrderR, rot_director[0]);
+  auto director1Function = Functions::makeDiscreteGlobalBasisFunction<FieldVector<double,dim>>(basisOrderR, rot_director[1]);
+  auto director2Function = Functions::makeDiscreteGlobalBasisFunction<FieldVector<double,dim>>(basisOrderR, rot_director[2]);
+
+  SubsamplingVTKWriter<GridView> vtkWriter(gridView, refinementLevels(displacementOrder-1));
+  vtkWriter.addVertexData(displacementFunction, VTK::FieldInfo("displacement", VTK::FieldInfo::Type::scalar, dim));
+  vtkWriter.addVertexData(director0Function, VTK::FieldInfo("director0", VTK::FieldInfo::Type::vector, dim));
+  vtkWriter.addVertexData(director1Function, VTK::FieldInfo("director1", VTK::FieldInfo::Type::vector, dim));
+  vtkWriter.addVertexData(director2Function, VTK::FieldInfo("director2", VTK::FieldInfo::Type::vector, dim));
+  vtkWriter.write("stress_plot_" + parameterSet.get<std::string>("energy"));
+
+  VTKWriter<GridView> vtkWriterElement(gridView);
+  vtkWriterElement.addCellData(stressShellBiot, "stress-shell-element");
+  vtkWriterElement.addCellData(stressShellBiot, "stress-shell-biot");
+  vtkWriterElement.addCellData(stressSubstrate1stPiolaKirchhoff, "stress-substrate-1st-piola-kirchhoff");
+  vtkWriterElement.addCellData(stressSubstrateCauchy, "stress-substrate-cauchy");
+  vtkWriterElement.addCellData(stressSubstrateVonMises, "stress-substrate-von-mises");
+  vtkWriterElement.addVertexData(director0Function, VTK::FieldInfo("director0", VTK::FieldInfo::Type::vector, dim));
+  vtkWriterElement.addVertexData(director1Function, VTK::FieldInfo("director1", VTK::FieldInfo::Type::vector, dim));
+  vtkWriterElement.addVertexData(director2Function, VTK::FieldInfo("director2", VTK::FieldInfo::Type::vector, dim));
+  vtkWriterElement.addVertexData(displacementFunction, VTK::FieldInfo("displacement", VTK::FieldInfo::Type::scalar, dim));
+  vtkWriterElement.write("stress_plot_" + parameterSet.get<std::string>("energy") + "_element");
+
+  VTKWriter<GridView> vtkWriterElementOnly(gridView);
+  vtkWriterElementOnly.addCellData(stressShellBiot, "stress-shell-biot");
+  vtkWriterElementOnly.addCellData(stressSubstrate1stPiolaKirchhoff, "stress-substrate-1st-piola-kirchhoff");
+  vtkWriterElementOnly.addCellData(stressSubstrateCauchy, "stress-substrate-cauchy");
+  vtkWriterElementOnly.addCellData(stressSubstrateVonMises, "stress-substrate-von-mises");
+  vtkWriterElementOnly.addVertexData(displacementFunction, VTK::FieldInfo("displacement", VTK::FieldInfo::Type::scalar, dim));
+  vtkWriterElementOnly.write("stress_plot_" + parameterSet.get<std::string>("energy") + "_element_only");
+
+} catch (Exception& e) {
+    std::cout << e.what() << std::endl;
+}