From c2ea2ebc8d56477e5dff3784f2b516dcebad43a4 Mon Sep 17 00:00:00 2001
From: Jonathan Youett <youett@math.fu-berlin.de>
Date: Thu, 15 Feb 2018 10:10:59 +0100
Subject: [PATCH] Class to compute and write von mises stress of given
 displacement or series

---
 dune/elasticity/CMakeLists.txt            |   1 +
 dune/elasticity/utilities/CMakeLists.txt  |   3 +
 dune/elasticity/utilities/stresswriter.hh | 146 ++++++++++++++++++++++
 3 files changed, 150 insertions(+)
 create mode 100644 dune/elasticity/utilities/CMakeLists.txt
 create mode 100644 dune/elasticity/utilities/stresswriter.hh

diff --git a/dune/elasticity/CMakeLists.txt b/dune/elasticity/CMakeLists.txt
index 0b3da84..a944e92 100644
--- a/dune/elasticity/CMakeLists.txt
+++ b/dune/elasticity/CMakeLists.txt
@@ -2,3 +2,4 @@ add_subdirectory(assemblers)
 add_subdirectory(common)
 add_subdirectory(estimators)
 add_subdirectory(materials)
+add_subdirectory(utilities)
diff --git a/dune/elasticity/utilities/CMakeLists.txt b/dune/elasticity/utilities/CMakeLists.txt
new file mode 100644
index 0000000..544b978
--- /dev/null
+++ b/dune/elasticity/utilities/CMakeLists.txt
@@ -0,0 +1,3 @@
+install(FILES
+    stresswriter.hh
+    DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/dune/elasticity/utilities)
diff --git a/dune/elasticity/utilities/stresswriter.hh b/dune/elasticity/utilities/stresswriter.hh
new file mode 100644
index 0000000..ec98cad
--- /dev/null
+++ b/dune/elasticity/utilities/stresswriter.hh
@@ -0,0 +1,146 @@
+// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+// vi: set ts=4 sw=2 et sts=2:
+#ifndef DUNE_ELASTICITY_UTILITIES_STRESS_WRITER_HH
+#define DUNE_ELASTICITY_UTILITIES_STRESS_WRITER_HH
+
+#include <string>
+#include <vector>
+#include <iomanip>
+#include <algorithm>
+
+#include <dune/common/parametertree.hh>
+#include <dune/grid/io/file/amirameshwriter.hh>
+#include <dune/grid/io/file/amirameshreader.hh>
+
+#include <dune/fufem/assemblers/localassemblers/vonmisesstressassembler.hh>
+#include <dune/fufem/assemblers/functionalassembler.hh>
+#include <dune/fufem/functionspacebases/p1nodalbasis.hh>
+#include <dune/fufem/functionspacebases/p0basis.hh>
+#include <dune/fufem/functions/basisgridfunction.hh>
+
+#include <dune/elasticity/materials/geomexactstvenantkirchhoffmaterial.hh>
+
+/** \brief Methods to compute von mises stresses and write them to the file system.
+ *
+ * The parameter set the user provides, needs to contain the following flags:
+ *  - "material"  The material type of the body, either "linear" for linear elasticity or
+ *                "geomExactLinear" for the geometrically exact St. Venant-Kirchhof material are supported yet.
+ *  - the material parameter for your material, like "E" and "nu"
+ *  - "format"    The format the stress should be written in. By now only "amira" is supported.
+ *  - "nodalStress" Determines whether the stress is computed as element data or vertex data.
+ *
+ * For writing the stress one additionally needs to specify
+ *  - "resultFile" The path + filename where the stress should be saved
+ *
+ * For computing and writing the stresses of a time series, previously written to the file system you need
+ *
+ * - "pathWithPrefix" The path where the stresses should be written to including the naming for the displacement fields
+ * - "numberTimeSteps" The number of time steps
+ * - "stressName" A name for the stresses to be written
+ *
+ */
+template <class DisplacementField, class Grid>
+struct StressWriter
+{
+  using field_type = typename Dune::FieldTraits<DisplacementField>::field_type;
+  using StressBasis = P0Basis<typename Grid::LeafGridView, field_type>;
+  using LocalStressAssembler = VonMisesStressAssembler<Grid, typename StressBasis::LocalFiniteElement>;
+  using StressFunction = typename LocalStressAssembler::StressFunction;
+
+  using P1Basis = P1NodalBasis<typename Grid::LeafGridView, field_type>;
+  using StressVector = typename LocalStressAssembler::LocalVector;
+
+  static auto getStress(const Dune::ParameterTree &config, const DisplacementField& displace, const Grid& grid);
+
+  static void writeStressToFile(const Dune::ParameterTree& config, const DisplacementField& displace, const Grid& grid);
+
+  static void writeTimeSeriesToFile(const Dune::ParameterTree& config, const Grid& grid);
+
+private:
+  static StressFunction getStressFunction(const Dune::ParameterTree& config) {
+
+    std::string material = config.get<std::string>("material");
+    if (material == "linear")
+      return LocalStressAssembler::linearElasticStressFunction(config.get<field_type>("E"), config.get<field_type>("nu"));
+    else if (material == "geomExactLinear")
+      return GeomExactStVenantMaterial<P1Basis>::stressFunction(config.get<field_type>("E"), config.get<field_type>("nu"));
+    else
+      DUNE_THROW(Dune::NotImplemented, "Stress function for " + material + " not implemented yet");
+  }
+};
+
+template <class DisplacementField, class Grid>
+auto StressWriter<DisplacementField, Grid>::getStress(const Dune::ParameterTree& config, const DisplacementField& displace, const Grid& grid)
+{
+  P1Basis basis(grid.leafGridView());
+  auto displacementFunction = std::make_shared<BasisGridFunction<P1Basis, DisplacementField> >(basis, displace);
+
+  LocalStressAssembler vonMisesAssembler(displacementFunction, getStressFunction(config));
+
+  StressBasis stressBasis(grid.leafGridView());
+  FunctionalAssembler<StressBasis> globalAssembler(stressBasis);
+
+  StressVector stress;
+  globalAssembler.assemble(vonMisesAssembler, stress);
+
+  if (config.get<bool>("nodalStress")) {
+    const auto& indexSet = grid.leafIndexSet();
+
+    StressVector nodalStress(basis.size());
+    nodalStress = 0;
+    std::vector<size_t> neighboringElementsPerVertex(nodalStress.size(), 0);
+
+    for (const auto& e : elements(grid.leafGridView()))
+      for (size_t j = 0; j < e.geometry().corners(); j++) {
+        auto vertexIndex = indexSet.subIndex(e, j, Grid::dimension);
+        neighboringElementsPerVertex[vertexIndex]++;
+        nodalStress[vertexIndex] += stress[indexSet.index(e)];
+      }
+
+    for (size_t i = 0; i < nodalStress.size(); i++)
+      nodalStress[i] /= neighboringElementsPerVertex[i];
+
+    return nodalStress;
+  } else
+    return stress;
+}
+
+template <class DisplacementField, class Grid>
+void StressWriter<DisplacementField, Grid>::writeStressToFile(const Dune::ParameterTree& config, const DisplacementField& displace,
+                                                        const Grid& grid)
+{
+  auto stress = getStress(config, displace, grid);
+
+  std::string format = config.get<std::string>("format");
+  std::transform(std::begin(format), std::end(format), std::begin(format), ::tolower);
+
+  if (format == "amira") {
+#if HAVE_AMIRAMESH
+      Dune::LeafAmiraMeshWriter<Grid>::writeBlockVector(grid, stress, config.get<std::string>("resultFile"));
+#endif
+  } else
+      DUNE_THROW(Dune::NotImplemented, "Format " + format + " is not yet implemented");
+}
+
+template <class DisplacementField, class Grid>
+void StressWriter<DisplacementField, Grid>::writeTimeSeriesToFile(const Dune::ParameterTree& config, const Grid& grid)
+{
+
+  std::string pathWithPrefix = config.get<std::string>("pathWithPrefix");
+  std::string stressName = config.get<std::string>("stressName");
+
+  size_t numberTimeSteps = config.get<size_t>("numberTimeSteps");
+  for (size_t i = 0; i < numberTimeSteps; i++) {
+    std::stringstream step;
+    step << std::setw(2) << std::setfill('0') << i;
+
+#if HAVE_AMIRAMESH
+    DisplacementField displace;
+    Dune::AmiraMeshReader<Grid>::readFunction(displace, pathWithPrefix + step.str());
+    auto stress = getStress(config, displace, grid);
+    Dune::LeafAmiraMeshWriter<Grid>::writeBlockVector(grid, stress, pathWithPrefix + stressName + step.str());
+#endif
+  }
+}
+
+#endif
-- 
GitLab