From 89afbd5a1cf80b558f810aeb01d045da937bc163 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Carsten=20Gr=C3=A4ser?= <graeser@mi.fu-berlin.de>
Date: Wed, 24 May 2023 10:58:46 +0200
Subject: [PATCH] Add exmaple with primal plasticity formulation

This shows how point-wise operators can be used to handle
matrix-valued unknowns.
---
 src/CMakeLists.txt       |   3 +
 src/primal-plasticity.cc | 219 +++++++++++++++++++++++++++++++++++++++
 2 files changed, 222 insertions(+)
 create mode 100644 src/primal-plasticity.cc

diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 789fb5d..31dbcd6 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -18,3 +18,6 @@ dune_target_enable_all_packages("benchmark")
 
 add_executable("showcase" showcase.cc)
 dune_target_enable_all_packages("showcase")
+
+add_executable("primal-plasticity" primal-plasticity.cc)
+dune_target_enable_all_packages("primal-plasticity")
diff --git a/src/primal-plasticity.cc b/src/primal-plasticity.cc
new file mode 100644
index 0000000..1bdfae1
--- /dev/null
+++ b/src/primal-plasticity.cc
@@ -0,0 +1,219 @@
+// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+// vi: set et ts=4 sw=2 sts=2:
+#include <config.h>
+
+#include <array>
+#include <vector>
+
+#include <dune/common/bitsetvector.hh>
+#include <dune/common/indices.hh>
+
+#include <dune/grid/yaspgrid.hh>
+#include <dune/grid/io/file/vtk/subsamplingvtkwriter.hh>
+
+#include <dune/istl/matrix.hh>
+#include <dune/istl/bcrsmatrix.hh>
+#include <dune/istl/matrixindexset.hh>
+#include <dune/istl/solvers.hh>
+#include <dune/istl/preconditioners.hh>
+#include <dune/istl/multitypeblockmatrix.hh>
+#include <dune/istl/multitypeblockvector.hh>
+
+#include <dune/functions/functionspacebases/interpolate.hh>
+#include <dune/functions/backends/istlvectorbackend.hh>
+#include <dune/functions/functionspacebases/powerbasis.hh>
+#include <dune/functions/functionspacebases/compositebasis.hh>
+#include <dune/functions/functionspacebases/lagrangebasis.hh>
+
+#include <dune/functions/gridfunctions/discreteglobalbasisfunction.hh>
+#include <dune/functions/gridfunctions/gridviewfunction.hh>
+
+#include <dune/fufem/parallel/elementcoloring.hh>
+#include <dune/fufem/assemblers/dunefunctionsoperatorassembler.hh>
+#include <dune/fufem/assemblers/dunefunctionsfunctionalassembler.hh>
+#include <dune/fufem/backends/istlmatrixbackend.hh>
+
+#include <dune/fufem-forms/forms.hh>
+
+
+
+int main (int argc, char *argv[]) try
+{
+  std::size_t threadCount = 4;
+  if (argc>1)
+    threadCount = std::stoul(std::string(argv[1]));
+
+  // Set up MPI, if available
+  Dune::MPIHelper::instance(argc, argv);
+
+  ///////////////////////////////////
+  //   Generate the grid
+  ///////////////////////////////////
+
+  const int dim = 2;
+  using GridType = Dune::YaspGrid<dim>;
+  Dune::FieldVector<double,dim> upperRight = {1, 1};
+  std::array<int,dim> elements = {{400, 400}};
+//  std::array<int,dim> elements = {{4, 4}};
+  GridType grid(upperRight,elements);
+
+
+  // Problem parameters
+  double lambda = 10;
+  double mu = 6.5;
+  double k1 = 3;
+  double k2 = 1; // ???
+
+  /////////////////////////////////////////////////////////
+  //   Choose a finite element space
+  /////////////////////////////////////////////////////////
+
+  using namespace Dune::Indices;
+  using namespace Dune::Functions::BasisBuilder;
+
+  // Dimension of symmetric trace-free matrix space
+  const int dp = dim*(dim+1)/2 - 1;
+
+  auto basis = makeBasis(
+    grid.leafGridView(),
+    composite(
+      power<dim>(lagrange<1>()),
+      power<dp>(lagrange<0>()),
+      lagrange<0>()
+    ));
+
+  /////////////////////////////////////////////////////////
+  //   Stiffness matrix and right hand side vector
+  /////////////////////////////////////////////////////////
+
+  using M00 = Dune::BCRSMatrix<Dune::FieldMatrix<double,dim,dim>>;
+  using M01 = Dune::BCRSMatrix<Dune::FieldMatrix<double,dim,dp>>;
+  using M02 = Dune::BCRSMatrix<Dune::Fufem::SingleColumnMatrix<Dune::FieldMatrix<double,dim,1>>>;
+
+  using M10 = Dune::BCRSMatrix<Dune::FieldMatrix<double,dp,dim>>;
+  using M11 = Dune::BCRSMatrix<Dune::FieldMatrix<double,dp,dp>>;
+  using M12 = Dune::BCRSMatrix<Dune::Fufem::SingleColumnMatrix<Dune::FieldMatrix<double,dp,1>>>;
+
+  using M20 = Dune::BCRSMatrix<Dune::Fufem::SingleRowMatrix<Dune::FieldMatrix<double,1,dim>>>;
+  using M21 = Dune::BCRSMatrix<Dune::Fufem::SingleRowMatrix<Dune::FieldMatrix<double,1,dp>>>;
+  using M22 = Dune::BCRSMatrix<double>;
+
+  using Matrix = Dune::MultiTypeBlockMatrix<
+                  Dune::MultiTypeBlockVector<M00, M01, M02>,
+                  Dune::MultiTypeBlockVector<M10, M11, M12>,
+                  Dune::MultiTypeBlockVector<M20, M21, M22>
+                  >;
+
+  using V0 = Dune::BlockVector<Dune::FieldVector<double,dim> >;
+  using V1 = Dune::BlockVector<Dune::FieldVector<double,dp> >;
+  using V2 = Dune::BlockVector<double>;
+
+  using Vector = Dune::MultiTypeBlockVector<V0, V1, V2>;
+
+  /////////////////////////////////////////////////////////
+  //  Assemble the system
+  /////////////////////////////////////////////////////////
+
+  Vector rhs;
+
+  auto rhsBackend = Dune::Functions::istlVectorBackend(rhs);
+
+  rhsBackend.resize(basis);
+  rhs = 0;
+
+  Matrix matrix;
+
+  // Compute colored partition of the grid view for parallel assembly
+  auto gridViewPartition = Dune::Fufem::coloredGridViewPartition(basis.gridView());
+
+  // Setup matrix pattern
+//  {
+//    Dune::Timer timer;
+//    auto matrixBackend = Dune::Fufem::istlMatrixBackend(matrix);
+//    auto operatorAssembler = Dune::Fufem::DuneFunctionsOperatorAssembler{basis, basis};
+//    auto patternBuilder = matrixBackend.patternBuilder();
+
+//    timer.reset();
+//    operatorAssembler.assembleBulkPattern(patternBuilder, gridViewPartition, threadCount);
+//    std::cout << "assembleBulkPattern took " << timer.elapsed() << "s." << std::endl;
+
+//    timer.reset();
+//    patternBuilder.setupMatrix();
+//    matrixBackend.assign(0);
+//    std::cout << "setupMatrix took " << timer.elapsed() << "s." << std::endl;
+//  }
+
+  // Assemble matrix
+  {
+    Dune::Timer timer;
+    using namespace Dune::Indices;
+    using namespace Dune::Fufem::Forms;
+
+    // Some point-wise linear operators used in the problem definition
+
+    // Symmetric part of a matrix
+    auto symmetricPart = RangeOperator([](const auto& M) {
+      return 0.5*(M + M.transposed());
+    });
+
+    // Trace of a matrix
+    auto trace = RangeOperator([&](const auto& M) {
+      double tr = 0;
+      for (auto k : Dune::range(dim))
+        tr += M[k][k];
+      return tr;
+    });
+
+    // Coordinate isometry for trace free symmetric matrices
+    // This can be used to convert coefficient vector into matrices
+    auto B = RangeOperator([](const auto& p) {
+      if constexpr (dim==2)
+        return 1.0/std::sqrt(2.0) * Dune::FieldMatrix<double,2,2>{{p[0], p[1]},{p[1], -p[0]}};
+    });
+
+    // Identity matrix (unfortunately, there's no operator+ for FieldMatrix and ScaledIdentityMatrix)
+    auto Id = Dune::FieldMatrix<double,dim,dim>(0);
+    for (auto k : Dune::range(dim))
+      Id[k][k] = 1;
+
+    // Elasticity tensor (for isotropic material)
+    auto C = RangeOperator([&](const auto& e) {
+      return 2*mu*e + lambda*Id*trace(e);
+    });
+
+    // Symmetric gradient
+    auto E = [&](const auto& v) {
+      return symmetricPart(grad(v));
+    };
+
+    // Ansatz functions
+    auto u = trialFunction(basis, _0);
+    auto p = trialFunction(basis, _1);
+    auto eta = trialFunction(basis, _2);
+    auto P = B(p);
+
+    // Test functions
+    auto v = testFunction(basis, _0);
+    auto q = testFunction(basis, _1);
+    auto nu = testFunction(basis, _2);
+    auto Q = B(q);
+
+    // Bilinear form for primal plasticity formulation with kinematic and isotropic hardening
+    auto A = integrate(dot(C(E(u)-P),E(v)-Q) + k1*dot(P,Q) + k2*dot(eta,nu));
+
+    // Alternatively we could e.g. use:
+//     auto sigma = C(E(u)-P);
+//     auto A = integrate(dot(sigma,E(v)-Q)  + k1*dot(P,Q) + k2*dot(eta,nu));
+
+    auto operatorAssembler = Dune::Fufem::DuneFunctionsOperatorAssembler{basis, basis};
+    auto matrixBackend = Dune::Fufem::istlMatrixBackend(matrix);
+    operatorAssembler.assembleBulk(matrixBackend, A, gridViewPartition, threadCount);
+
+    std::cout << "Assembling the problem took " << timer.elapsed() << "s" << std::endl;
+  }
+
+
+}
+catch (Dune::Exception& e) {
+  std::cout << e.what() << std::endl;
+}
-- 
GitLab