From 1409a3f07d92f022ea68f3ecbe44df4dd58ccc27 Mon Sep 17 00:00:00 2001
From: Oliver Sander <oliver.sander@tu-dresden.de>
Date: Wed, 21 Aug 2024 10:01:36 +0200
Subject: [PATCH] Use the DirichletValues Python class also for the initial
 iterate

That way, we can also set the initial microrotation -- previously
it was hard-wired to the identity matrix.

Being able to explicitly choose the initial microrotation allows
to start, in particular, from a twisted strip.
---
 problems/cosserat-continuum-cantilever.py     |  4 +--
 problems/cosserat-continuum-twisted-strip.py  |  4 +--
 ...rat-continuum-wong-pellegrino-wrinkling.py |  8 +++--
 .../cosserat-continuum-wriggers-l-shape.py    |  2 ++
 src/cosserat-continuum.cc                     | 30 ++++++++++++++-----
 5 files changed, 32 insertions(+), 16 deletions(-)

diff --git a/problems/cosserat-continuum-cantilever.py b/problems/cosserat-continuum-cantilever.py
index f99abbfe..0dfec2fe 100644
--- a/problems/cosserat-continuum-cantilever.py
+++ b/problems/cosserat-continuum-cantilever.py
@@ -112,6 +112,7 @@ parameterSet.dirichletVerticesPredicate = "[x[0] < 0.01, x[0] < 0.01, x[0] < 0.0
 parameterSet.dirichletRotationVerticesPredicate = "x[0] < 0.01"
 
 ### The actual Dirichlet values
+# With 'homotopyParameter==0', this class gives the initial iterate
 class DirichletValues:
     def __init__(self, homotopyParameter):
         self.homotopyParameter = homotopyParameter
@@ -134,8 +135,5 @@ parameterSet.neumannVerticesPredicate = "x[0] > 99.99"
 ###  Neumann values
 parameterSet.neumannValues = "0 0 3"
 
-# Initial deformation
-parameterSet.initialDeformation = "[x[0], x[1], 0]"
-
 #parameterSet.startFromFile = yes
 #parameterSet.initialIterateFilename = initial_iterate.vtu
diff --git a/problems/cosserat-continuum-twisted-strip.py b/problems/cosserat-continuum-twisted-strip.py
index d32cf33e..8439f111 100644
--- a/problems/cosserat-continuum-twisted-strip.py
+++ b/problems/cosserat-continuum-twisted-strip.py
@@ -109,6 +109,7 @@ parameterSet.dirichletVerticesPredicate = "[x[0] < 0.001 or x[0] > 0.0999, x[0]
 parameterSet.dirichletRotationVerticesPredicate = "x[0] < 0.001 or x[0] > 0.0999"
 
 ### The actual Dirichlet values
+# With 'homotopyParameter==0', this class gives the initial iterate
 class DirichletValues:
     def __init__(self, homotopyParameter):
         self.homotopyParameter = homotopyParameter
@@ -135,7 +136,4 @@ class DirichletValues:
         rotation = [[1,0,0], [0, math.cos(angle), -math.sin(angle)], [0, math.sin(angle), math.cos(angle)]]
         return rotation
 
-# Initial deformation
-parameterSet.initialDeformation = "[x[0], x[1], 0]"
-
 
diff --git a/problems/cosserat-continuum-wong-pellegrino-wrinkling.py b/problems/cosserat-continuum-wong-pellegrino-wrinkling.py
index 7b805648..8bce680b 100644
--- a/problems/cosserat-continuum-wong-pellegrino-wrinkling.py
+++ b/problems/cosserat-continuum-wong-pellegrino-wrinkling.py
@@ -108,12 +108,17 @@ parameterSet.dirichletVerticesPredicate = "[x[1] < 0.0001 or x[1] > 0.128 - 0.00
 parameterSet.dirichletRotationVerticesPredicate = "x[1] < 0.0001 or x[1] > 0.128 - 0.0001"
 
 ### The actual Dirichlet values
+# With 'homotopyParameter==0', this class gives the initial iterate
 class DirichletValues:
     def __init__(self, homotopyParameter):
         self.homotopyParameter = homotopyParameter
 
     def deformation(self, x):
-        out = [x[0], x[1], 0]
+        if self.homotopyParameter<0.01:
+            out = [x[0] + 0.003*x[1] / 0.128, x[1], 0.002*math.cos(1e4*x[0])]
+        else:
+            out = [x[0], x[1], 0]
+
         if x[1] >  0.128-1e-4 :
             out[0] += 0.003 * self.homotopyParameter
             out[1] += 0.0005
@@ -126,4 +131,3 @@ class DirichletValues:
 # Initial deformation
 #parameterSet.startFromFile = True
 parameterSet.initialIterateFilename = "cosserat_iterate_2.vtu"
-parameterSet.initialDeformation = "[x[0] + 0.003*x[1] / 0.128, x[1], 0.002*math.cos(1e4*x[0])]"
diff --git a/problems/cosserat-continuum-wriggers-l-shape.py b/problems/cosserat-continuum-wriggers-l-shape.py
index cecbc1ae..edd8a706 100644
--- a/problems/cosserat-continuum-wriggers-l-shape.py
+++ b/problems/cosserat-continuum-wriggers-l-shape.py
@@ -104,6 +104,7 @@ parameterSet.dirichletVerticesPredicate = "[x[0] < 1, x[0] < 1, x[0] < 1]"
 parameterSet.dirichletRotationVerticesPredicate = "x[0] < 1"
 
 ### The actual Dirichlet values
+# With 'homotopyParameter==0', this class gives the initial iterate
 class DirichletValues:
     def __init__(self, homotopyParameter):
         self.homotopyParameter = homotopyParameter
@@ -134,6 +135,7 @@ parameterSet.neumannValues =  "0.09 0 0"
 #parameterSet.initialDeformation = "[x[0], x[1], 0 if (x[0] < 225 or x[1] < -15) else 0.001*(x[0]-225)*(x[1]+15)]"
 ##parameterSet.initialDeformation = "[x[0], x[1], 0]"
 
+# Overrides the configuration given by the 'DirichletValues' class
 parameterSet.startFromFile = True
 parameterSet.initialIterateGridFilename = "wriggers-L-shape_99_mm.msh"
 parameterSet.initialIterateFilename = "initial-wriggers-l-shape.vtu"
diff --git a/src/cosserat-continuum.cc b/src/cosserat-continuum.cc
index a94d0a66..cdfe2623 100644
--- a/src/cosserat-continuum.cc
+++ b/src/cosserat-continuum.cc
@@ -356,19 +356,33 @@ int main (int argc, char *argv[]) try
   // //////////////////////////
 
   SolutionType x;
-
   x[_0].resize(compositeBasis.size({0}));
+  x[_1].resize(compositeBasis.size({1}));
 
-  lambda = std::string("lambda x: (") + parameterSet.get<std::string>("initialDeformation") + std::string(")");
-  auto pythonInitialDeformation = Python::make_function<FieldVector<double,3> >(Python::evaluate(lambda));
+  // Load the initial configuration from the Python options file
+  // Yes, the Python class really is called 'DirichletValues'.
+  // We use that class both for the initial iterate and the Dirichlet values
+  Python::Callable initialConfigurationPythonClass = pyModule.get("DirichletValues");
 
-  std::vector<FieldVector<double,3> > v;
-  Functions::interpolate(deformationPowerBasis, v, pythonInitialDeformation);
+  // Construct an object
+  Python::Reference initialConfigurationPythonObject = initialConfigurationPythonClass(0.0 /* homotopy parameter*/);
 
-  for (size_t i=0; i<x[_0].size(); i++)
-    x[_0][i] = v[i];
+  // Extract object member functions as Dune functions
+  auto initialDeformationFunction = Python::make_function<FieldVector<double,3> >   (initialConfigurationPythonObject.get("deformation"));
+  auto initialOrientationFunction = Python::make_function<FieldMatrix<double,3,3> > (initialConfigurationPythonObject.get("orientation"));
+
+  BlockVector<FieldVector<double,3> > ddV;
+  Functions::interpolate(deformationPowerBasis, ddV, initialDeformationFunction);
+
+  BlockVector<FieldMatrix<double,3,3> > dOV;
+  Functions::interpolate(orientationMatrixBasis, dOV, initialOrientationFunction);
+
+  for (std::size_t i = 0; i < compositeBasis.size({0}); i++)
+    x[_0][i] = ddV[i];
+
+  for (std::size_t i = 0; i < compositeBasis.size({1}); i++)
+    x[_1][i].set(dOV[i]);
 
-  x[_1].resize(compositeBasis.size({1}));
 #if !MIXED_SPACE
   if (parameterSet.hasKey("startFromFile"))
   {
-- 
GitLab