From 256231c24a38730d307da19fdbc0a751a7a6e482 Mon Sep 17 00:00:00 2001
From: Klaus <klaus.boehnlein@tu-dresden.de>
Date: Fri, 29 Sep 2023 15:38:26 +0200
Subject: [PATCH] Increase feasible number of material phases to 4 and add
 parametrized_laminate

---
 dune/microstructure/prestrainedMaterial.hh | 198 +++++++++++++++------
 inputs/cellsolver.parset                   |  11 +-
 materials/parametrized_laminate.py         |  68 +++++++
 3 files changed, 216 insertions(+), 61 deletions(-)
 create mode 100644 materials/parametrized_laminate.py

diff --git a/dune/microstructure/prestrainedMaterial.hh b/dune/microstructure/prestrainedMaterial.hh
index 904b1e58..3634e4fe 100644
--- a/dune/microstructure/prestrainedMaterial.hh
+++ b/dune/microstructure/prestrainedMaterial.hh
@@ -113,12 +113,12 @@ protected:
   Dune::FieldMatrix<double,6,6> L1_;
   Dune::FieldMatrix<double,6,6> L2_;
   Dune::FieldMatrix<double,6,6> L3_;
-  Dune::FieldMatrix<double,6,6> L4_; //not used yet
+  Dune::FieldMatrix<double,6,6> L4_;
 
   Func2Tensor prestrain1_;
   Func2Tensor prestrain2_; 
   Func2Tensor prestrain3_;  
-  Func2Tensor prestrain4_;  //not used yet
+  Func2Tensor prestrain4_;
 
   Python::Module module_;
 
@@ -138,19 +138,19 @@ protected:
 
   //Transformation matrix for Voigt notation
   Dune::FieldMatrix<double,6,6> D_ = {{1.0, 0.0, 0.0, 0.0 , 0.0, 0.0},
-                              {0.0, 1.0, 0.0, 0.0 , 0.0, 0.0},
-                              {0.0, 0.0, 1.0, 0.0 , 0.0, 0.0},
-                              {0.0, 0.0, 0.0, sqrt(2.0) , 0.0, 0.0},
-                              {0.0, 0.0, 0.0, 0.0 , sqrt(2.0), 0.0},
-                              {0.0, 0.0, 0.0, 0.0 , 0.0, sqrt(2.0)}
-                            };
+                                      {0.0, 1.0, 0.0, 0.0 , 0.0, 0.0},
+                                      {0.0, 0.0, 1.0, 0.0 , 0.0, 0.0},
+                                      {0.0, 0.0, 0.0, sqrt(2.0) , 0.0, 0.0},
+                                      {0.0, 0.0, 0.0, 0.0 , sqrt(2.0), 0.0},
+                                      {0.0, 0.0, 0.0, 0.0 , 0.0, sqrt(2.0)}
+                                     };
   Dune::FieldMatrix<double,6,6> D_inv = {{1.0, 0.0, 0.0, 0.0 , 0.0, 0.0},
-                                  {0.0, 1.0, 0.0, 0.0 , 0.0, 0.0},
-                                  {0.0, 0.0, 1.0, 0.0 , 0.0, 0.0},
-                                  {0.0, 0.0, 0.0, 1.0/sqrt(2.0) , 0.0, 0.0},
-                                  {0.0, 0.0, 0.0, 0.0 , 1.0/sqrt(2.0), 0.0},
-                                  {0.0, 0.0, 0.0, 0.0 , 0.0, 1.0/sqrt(2.0)}
-                                };
+                                         {0.0, 1.0, 0.0, 0.0 , 0.0, 0.0},
+                                         {0.0, 0.0, 1.0, 0.0 , 0.0, 0.0},
+                                         {0.0, 0.0, 0.0, 1.0/sqrt(2.0) , 0.0, 0.0},
+                                         {0.0, 0.0, 0.0, 0.0 , 1.0/sqrt(2.0), 0.0},
+                                         {0.0, 0.0, 0.0, 0.0 , 0.0, 1.0/sqrt(2.0)}
+                                        };
 
 
 
@@ -287,6 +287,11 @@ Dune::FieldMatrix<double,6,6> setupPhase(const std::string phaseType, Python::Mo
       materialParameters_string= "materialParameters_phase3";
       break;
     }
+    case 4:
+    {
+      materialParameters_string= "materialParameters_phase4";
+      break;
+    }
     default:
     DUNE_THROW(Dune::Exception, "Phase number not implemented.");
         break;
@@ -296,6 +301,7 @@ Dune::FieldMatrix<double,6,6> setupPhase(const std::string phaseType, Python::Mo
   {
       Dune::FieldVector<double,2> materialParameters(0);
       module.get(materialParameters_string).toC<Dune::FieldVector<double,2>>(materialParameters);
+      std::cout << "Lame-Parameters (mu,lambda): (" << materialParameters[0] << "," << materialParameters[1] << ") " << std::endl;
       return isotropic(materialParameters[0],materialParameters[1]);
   }
   if(phaseType == "orthotropic")                           //TODO SetupPHASE (phase_type)
@@ -394,24 +400,29 @@ Dune::FieldMatrix<double,6,6> setupPhase(const std::string phaseType, Python::Mo
       prestrain2_ = Python::make_function<MatrixRT>(module.get("prestrain_phase2"));
       prestrain3_ = Python::make_function<MatrixRT>(module.get("prestrain_phase3"));
         
-      // if (phase1_type == "isotropic" )                           //TODO SetupPHASE (phase_type)
-      // {
-      //   FieldVector<double,2> materialParameters_phase1(0);
-      //   module.get("materialParameters_phase1").toC<FieldVector<double,2>>(materialParameters_phase1);
-      //   L1_ = isotropic(materialParameters_phase1[0],materialParameters_phase1[1]);
-      // }
-      // if (phase2_type == "isotropic" )                           //TODO SetupPHASE (phase_type)
-      // {
-      //   FieldVector<double,2> materialParameters_phase2(0);
-      //   module.get("materialParameters_phase2").toC<FieldVector<double,2>>(materialParameters_phase2);
-      //   L2_ = isotropic(materialParameters_phase2[0],materialParameters_phase2[1]);
-      // }
-      // if (phase3_type == "isotropic" )                           //TODO SetupPHASE (phase_type)
-      // {
-      //   FieldVector<double,2> materialParameters_phase3(0);
-      //   module.get("materialParameters_phase3").toC<FieldVector<double,2>>(materialParameters_phase3);
-      //   L3_ = isotropic(materialParameters_phase3[0],materialParameters_phase3[1]);
-      // }
+      break;
+    }
+    case 4:
+    {
+      std::string phase1_type;
+      module.get("phase1_type").toC<std::string>(phase1_type);
+      std::string phase2_type;
+      module.get("phase2_type").toC<std::string>(phase2_type);
+      std::string phase3_type;
+      module.get("phase3_type").toC<std::string>(phase3_type);
+      std::string phase4_type;
+      module.get("phase4_type").toC<std::string>(phase4_type);
+
+      L1_ = setupPhase(phase1_type, module,1);
+      L2_ = setupPhase(phase2_type, module,2);
+      L3_ = setupPhase(phase3_type, module,3);
+      L4_ = setupPhase(phase4_type, module,4);
+
+      prestrain1_ = Python::make_function<MatrixRT>(module.get("prestrain_phase1"));
+      prestrain2_ = Python::make_function<MatrixRT>(module.get("prestrain_phase2"));
+      prestrain3_ = Python::make_function<MatrixRT>(module.get("prestrain_phase3"));
+      prestrain4_ = Python::make_function<MatrixRT>(module.get("prestrain_phase4"));
+  
       break;
     }
     default:
@@ -507,7 +518,7 @@ Dune::FieldMatrix<double,6,6> setupPhase(const std::string phaseType, Python::Mo
                                        {  0.0        ,  0.0         , 0.0          , 0.0     , 0.0     , 1.0/G_12}
                                       };
 
-    
+      printmatrix(std::cout, C, "(Orthotropic) Compliance matrix used:", "--");
       // printmatrix(std::cout, C, "C", "--");
 
       //--- return elasticity tensor 
@@ -593,6 +604,32 @@ Dune::FieldMatrix<double,6,6> setupPhase(const std::string phaseType, Python::Mo
     return {{v[0], v[5]/2.0, v[4]/2.0}, {v[5]/2.0, v[1], v[3]/2.0}, {v[4]/2.0, v[3]/2.0, v[2]}};
   }
 
+  static Dune::FieldVector<double,6> strainToVoigt(const MatrixRT& G)
+  {
+    // return {G[0][0], G[1][1], G[2][2], G[1][2], G[0][2], G[0][1]};
+    return {G[0][0], G[1][1], G[2][2], 2.0*G[1][2], 2.0*G[0][2], 2.0*G[0][1]};
+
+  }
+
+  static Dune::FieldVector<double,6> stressToVoigt(const MatrixRT& G)
+  {
+    // return {G[0][0], G[1][1], G[2][2], G[1][2], G[0][2], G[0][1]};
+    return {G[0][0], G[1][1], G[2][2], G[1][2], G[0][2], G[0][1]};
+
+  }
+
+  static MatrixRT VoigtToStress(const Dune::FieldVector<double,6>& v)
+  {
+    // return {{v[0], v[5], v[4]}, {v[5], v[1], v[3]}, {v[4], v[3], v[2]}};
+    return {{v[0], v[5], v[4]}, {v[5], v[1], v[3]}, {v[4], v[3], v[2]}};
+  }
+
+  static MatrixRT VoigtToStrain(const Dune::FieldVector<double,6>& v)
+  {
+    // return {{v[0], v[5], v[4]}, {v[5], v[1], v[3]}, {v[4], v[3], v[2]}};
+    return {{v[0], v[5]/2.0, v[4]/2.0}, {v[5]/2.0, v[1], v[3]/2.0}, {v[4]/2.0, v[3]/2.0, v[2]}};
+  }
+
 
 
   MatrixRT applyElasticityTensor(const MatrixRT& G, const int& phase)  const  
@@ -603,25 +640,57 @@ Dune::FieldMatrix<double,6,6> setupPhase(const std::string phaseType, Python::Mo
     Dune::FieldVector<double,6> out(0);
     // printvector(std::cout, G_tmp, "G_tmp", "--");
 
-    if (phase == 1)
-    {
-      // printmatrix(std::cout, L1_, "L1_", "--");
-      L1_.mv(G_tmp,out);
-    }
-    else if (phase == 2)
+    // if (phase == 1)
+    // {
+    //   // printmatrix(std::cout, L1_, "L1_", "--");
+    //   L1_.mv(G_tmp,out);
+    // }
+    // else if (phase == 2)
+    // {
+    //   // printmatrix(std::cout, L2_, "L2_", "--");
+    //   L2_.mv(G_tmp,out);
+    // }
+    // else 
+    // {
+    //   // printmatrix(std::cout, L3_, "L3_", "--");
+    //   L3_.mv(G_tmp,out);
+    // }
+
+    switch (phase)
     {
-      // printmatrix(std::cout, L2_, "L2_", "--");
-      L2_.mv(G_tmp,out);
-    }
-    else 
-    {
-      // printmatrix(std::cout, L3_, "L3_", "--");
-      L3_.mv(G_tmp,out);
+      case 1:
+      {
+        // printmatrix(std::cout, L1_, "L1_", "--");
+        L1_.mv(G_tmp,out);
+        break;
+      }
+      case 2:
+      {
+        // printmatrix(std::cout, L2_, "L2_", "--");
+        L2_.mv(G_tmp,out);
+        break;
+      }
+      case 3:
+      {
+        // printmatrix(std::cout, L3_, "L3_", "--");
+        L3_.mv(G_tmp,out);
+        break;
+      }
+      case 4:
+      {
+        // printmatrix(std::cout, L3_, "L3_", "--");
+        L4_.mv(G_tmp,out);
+        break;
+      }
+      default:
+        DUNE_THROW(Dune::Exception, "Phase number not implemented.");
+        break;
     }
 
 
     // printvector(std::cout, out, "out", "--");
-    return VoigtToMatrix(out);
+    return VoigtToMatrix(out);          // Muss hier stress zurücktransformieren! 
+    // return VoigtToStress(out);
     // return image as Matrix again
     // return {{out[0], (1.0/sqrt(2.0))*out[5], (1.0/sqrt(2.0))*out[4]}, {(1.0/sqrt(2.0))*out[5], out[1], (1.0/sqrt(2.0))*out[3]}, {(1.0/sqrt(2.0))*out[4], (1.0/sqrt(2.0))*out[3], out[2]}};
     // return {{out[0], (1.0/2.0)*out[5], (1.0/2.0)*out[4]}, {(1.0/2.0)*out[5], out[1], (1.0/2.0)*out[3]}, {(1.0/2.0)*out[4], (1.0/2.0)*out[3], out[2]}};
@@ -632,15 +701,32 @@ Dune::FieldMatrix<double,6,6> setupPhase(const std::string phaseType, Python::Mo
   ////////////////////////////////////////////////////////////////////////////////////////
   MatrixRT prestrain(const int& phase,const Domain& x) const  
   {
-    if (phase == 1)
-      return prestrain1_(x);
-    else if (phase == 2)
-      return prestrain2_(x);
-    else if (phase ==3)
-      return prestrain3_(x);
-    else 
-      DUNE_THROW(Dune::Exception, "Phase number not implemented.");
-     
+    switch (phase)
+    {
+      case 1:
+      {
+        return prestrain1_(x);
+        break;
+      }
+      case 2:
+      {
+        return prestrain2_(x);
+        break;
+      }
+      case 3:
+      {
+        return prestrain3_(x);
+        break;
+      }
+      case 4:
+      {
+        return prestrain3_(x);
+        break;
+      }
+      default:
+        DUNE_THROW(Dune::Exception, "Phase number not implemented.");
+        break;
+    }
   }
 
 
diff --git a/inputs/cellsolver.parset b/inputs/cellsolver.parset
index 8ade7d03..e1ba37f5 100644
--- a/inputs/cellsolver.parset
+++ b/inputs/cellsolver.parset
@@ -9,7 +9,7 @@
 #############################################
 ### Remove/Comment this when running via Python-Script:
 #outputPath=/home/stefan/DUNE/dune-microstructure/outputs
-outputPath=/home/klaus/Desktop/Dune-Testing/dune-microstructure/outputs
+outputPath=/home/klaus/Desktop/Dune_release/dune-microstructure/outputs
 
 
 # --- DEBUG (Output) Option:
@@ -26,7 +26,7 @@ outputPath=/home/klaus/Desktop/Dune-Testing/dune-microstructure/outputs
 ## {start,finish} computes on all grid from 2^(start) to 2^finish refinement
 #----------------------------------------------------
 
-numLevels= 2 3      # computes all levels from first to second entry
+numLevels= 3 3      # computes all levels from first to second entry
 
 
 #############################################
@@ -35,12 +35,13 @@ numLevels= 2 3      # computes all levels from first to second entry
 
 # --- Choose material definition:
 #materialFunction  = "material_test"
-materialFunction  = "material_neukamm"
+#materialFunction  = "material_neukamm"
 #materialFunction = "two_phase_material_1"
 #materialFunction = "two_phase_material_2"
 #materialFunction = "two_phase_material_3"
 #materialFunction = "material_orthotropic"
 #materialFunction = "homogeneous"
+materialFunction = "parametrized_laminate"
 
 
 # --- Choose scale ratio gamma:
@@ -50,7 +51,7 @@ gamma=1.0
 
 
 #geometryFunctionPath = /home/stefan/DUNE/dune-microstructure/materials
-geometryFunctionPath = /home/klaus/Desktop/Dune-Testing/dune-microstructure/materials
+geometryFunctionPath = /home/klaus/Desktop/Dune_release/dune-microstructure/materials
 
 
 
@@ -69,7 +70,7 @@ geometryFunctionPath = /home/klaus/Desktop/Dune-Testing/dune-microstructure/mate
 #############################################
 #  Solver Type: #1: CG - SOLVER , #2: GMRES - SOLVER, #3: QR - SOLVER (default), #4: UMFPACK - SOLVER
 #############################################
-Solvertype = 2        # recommended to use iterative solver (e.g GMRES) for finer grid-levels
+Solvertype = 3        # recommended to use iterative solver (e.g GMRES) for finer grid-levels
 Solver_verbosity = 0  #(default = 2)  degree of information for solver output
 
 
diff --git a/materials/parametrized_laminate.py b/materials/parametrized_laminate.py
new file mode 100644
index 00000000..c05161f3
--- /dev/null
+++ b/materials/parametrized_laminate.py
@@ -0,0 +1,68 @@
+import math
+from python_matrix_operations import *
+import ctypes
+import os
+import sys
+#---------------------------------------------------------------
+
+
+#--- define indicator function
+def indicatorFunction(x):
+    theta=0.25
+    factor=1
+    if (abs(x[0]) < (theta/2) and x[2] < 0 ):
+        return 1    #Phase1
+    elif (abs(x[0]) > (theta/2) and x[2] > 0 ):
+        return 2    #Phase2
+    elif (abs(x[0]) < (theta/2) and x[2] > 0 ):
+        return 3    #Phase3
+    else :
+        return 4    #Phase4
+
+
+########### Options for material phases: #################################
+#     1. "isotropic"     2. "orthotropic"      3. "transversely_isotropic"   4. "general_anisotropic"
+#########################################################################
+## Notation - Parameter input :
+# isotropic (Lame parameters) : [mu , lambda]
+#         orthotropic         : [E1,E2,E3,G12,G23,G31,nu12,nu13,nu23]   # see https://en.wikipedia.org/wiki/Poisson%27s_ratio with x=1,y=2,z=3
+# transversely_isotropic      : [E1,E2,G12,nu12,nu23]
+# general_anisotropic         : full compliance matrix C
+######################################################################
+
+# --- Number of material phases
+Phases=4
+
+#--- Define different material phases:
+
+#- PHASE 1
+phase1_type="isotropic"
+materialParameters_phase1 = [2.0, 0]   
+
+#- PHASE 2
+phase2_type="isotropic"
+materialParameters_phase2 = [1.0, 0]   
+
+#- PHASE 3
+phase3_type="isotropic"
+materialParameters_phase3 = [2.0, 0]
+
+#- PHASE 4
+phase4_type="isotropic"
+materialParameters_phase4 = [1.0, 0]
+
+
+#--- define prestrain function for each phase
+# (also works with non-constant values)
+def prestrain_phase1(x):
+    return [[2, 0, 0], [0,2,0], [0,0,2]]
+
+def prestrain_phase2(x):
+    return [[1, 0, 0], [0,1,0], [0,0,1]]
+
+def prestrain_phase3(x):
+    return [[0, 0, 0], [0,0,0], [0,0,0]]
+
+def prestrain_phase4(x):
+    return [[0, 0, 0], [0,0,0], [0,0,0]]
+
-- 
GitLab