version 0.4.1
material.hh
Go to the documentation of this file.
1// SPDX-FileCopyrightText: 2021-2024 The Ikarus Developers mueller@ibb.uni-stuttgart.de
2// SPDX-License-Identifier: LGPL-3.0-or-later
3
9#pragma once
10
11#include <dune/common/classname.hh>
12#include <dune/python/common/typeregistry.hh>
13#include <dune/python/pybind11/eigen.h>
14#include <dune/python/pybind11/pybind11.h>
15#include <dune/python/pybind11/stl.h>
16
19
20#define MAKE_MaterialFunction(clsName, materialName, functionname, vecSize) \
21 clsName.def( \
22 #functionname, \
23 [](materialName& self, StrainTags straintag, Eigen::Ref<const Eigen::Vector<double, vecSize>> eVoigt_) { \
24 if constexpr (not Concepts::IsMaterial<LinearElasticityT, materialName>) { \
25 Eigen::Vector<double, vecSize> eVoigt = eVoigt_; \
26 if (straintag == StrainTags::rightCauchyGreenTensor) \
27 return self.template functionname<StrainTags::rightCauchyGreenTensor>(eVoigt); \
28 else if (straintag == StrainTags::greenLagrangian) \
29 return self.template functionname<StrainTags::greenLagrangian>(eVoigt); \
30 else if (straintag == StrainTags::linear) \
31 DUNE_THROW(Dune::MathError, "Passing linear strain to " + std::string(#materialName) + \
32 " does not makes sense use LinearElastic class"); \
33 else if (straintag == StrainTags::displacementGradient) \
34 DUNE_THROW(Dune::MathError, \
35 "Passing displacementGradient strain in 6d Voigt notation does not make any sense!"); \
36 else if (straintag == StrainTags::deformationGradient) \
37 DUNE_THROW(Dune::MathError, \
38 "Passing deformationGradient strain in 6d Voigt notation does not make any sense!"); \
39 else \
40 DUNE_THROW(Dune::MathError, toString(straintag) + "is not a valid strain tag."); \
41 } else { \
42 Eigen::Vector<double, vecSize> eVoigt = eVoigt_; /* Linear elastic path */ \
43 if (straintag == StrainTags::linear) \
44 return self.template functionname<StrainTags::linear>(eVoigt); \
45 else \
46 DUNE_THROW(Dune::MathError, "Linear elastic material only accepts linear strains!"); \
47 } \
48 __builtin_unreachable(); \
49 }, \
50 "StrainName"_a, "strainVector"_a);
51
52namespace Ikarus::Python {
53
54namespace Impl {
55 // Function to extract and convert parameters using a conversion strategy
56 template <typename T>
57 LamesFirstParameterAndShearModulus convertMaterialParameters(const pybind11::kwargs& kwargs,
58 const std::string& param1, const std::string& param2) {
59 auto converter =
60 convertLameConstants(T{kwargs[param1.c_str()].cast<double>(), kwargs[param2.c_str()].cast<double>()});
61
62 // This is necessary as the converter can't convert to a parameter already present due to compile-time constraints
63 double lamesFirst = [&]() {
64 if constexpr (requires { converter.toLamesFirstParameter(); })
65 return converter.toLamesFirstParameter();
66 else
67 return kwargs["Lambda"].cast<double>();
68 }();
69 double shearModulus = [&]() {
70 if constexpr (requires { converter.toShearModulus(); })
71 return converter.toShearModulus();
72 else
73 return kwargs["mu"].cast<double>();
74 }();
75 return {lamesFirst, shearModulus};
76 }
77
78 Ikarus::LamesFirstParameterAndShearModulus extractMaterialParameters(const pybind11::kwargs& kwargs) {
79 // clang-format off
80 static const std::map<std::array<std::string, 2>, std::function<LamesFirstParameterAndShearModulus(const pybind11::kwargs&)>> conversionMap = {
81 {{"E", "nu"}, [](const auto& kw){ return convertMaterialParameters<YoungsModulusAndPoissonsRatio>(kw, "E", "nu"); }},
82 {{"E", "mu"}, [](const auto& kw){ return convertMaterialParameters<YoungsModulusAndShearModulus>(kw, "E", "mu"); }},
83 {{"E", "K"}, [](const auto& kw){ return convertMaterialParameters<YoungsModulusAndBulkModulus>(kw, "E", "K"); }},
84 {{"E", "Lambda"}, [](const auto& kw){ return convertMaterialParameters<YoungsModulusAndLamesFirstParameter>(kw, "E", "Lambda"); }},
85 {{"K", "Lambda"}, [](const auto& kw){ return convertMaterialParameters<BulkModulusAndLamesFirstParameter>(kw, "K", "Lambda"); }},
86 {{"Lambda", "mu"}, [](const auto& kw){ return LamesFirstParameterAndShearModulus{kw["Lambda"].template cast<double>(), kw["mu"].template cast<double>()}; }}
87 };
88 // clang-format on
89
90 if (kwargs.size() != 2)
91 DUNE_THROW(Dune::IOError, "The number of material parameters passed to the material should be 2");
92
93 for (const auto& [materialParameters, parameterConverter] : conversionMap) {
94 const auto [firstPar, secondPar] = materialParameters;
95 if (kwargs.contains(firstPar) && kwargs.contains(secondPar)) {
96 return parameterConverter(kwargs);
97 }
98 }
99
100 DUNE_THROW(Dune::IOError,
101 "No suitable combination of material parameters found, valid combinations are: (E, nu), (E, mu), (E, "
102 "K), (E, Lambda), (K, Lambda), (Lambda, nu)");
103 }
104} // namespace Impl
105template <class Material, size_t vecSize, class... options>
106void registerMaterial(pybind11::handle scope, pybind11::class_<Material, options...> cls) {
107 using pybind11::operator""_a;
108 namespace py = pybind11;
109
110 cls.def(pybind11::init([](const py::kwargs& kwargs) {
111 auto matParameter = Impl::extractMaterialParameters(kwargs);
112 return new Material(matParameter);
113 }));
114
115 std::string materialname = Material::name();
116
117 MAKE_MaterialFunction(cls, Material, storedEnergy, vecSize);
118 MAKE_MaterialFunction(cls, Material, stresses, vecSize);
119 MAKE_MaterialFunction(cls, Material, tangentModuli, vecSize);
120
121 using PlaneStressClass = decltype(planeStress(std::declval<Material>()));
122 auto includes = Dune::Python::IncludeFiles{"ikarus/finiteelements/mechanics/materials.hh"};
123 auto pS = Dune::Python::insertClass<PlaneStressClass>(
124 scope, std::string("PlaneStress_") + materialname,
125 Dune::Python::GenerateTypeName(
126 "Ikarus::VanishingStress<std::array<Ikarus::Impl::MatrixIndexPair, "
127 "3ul>{{Ikarus::Impl::MatrixIndexPair{2ul, 1ul}, Ikarus::Impl::MatrixIndexPair{2ul,0ul}, "
128 "Ikarus::Impl::MatrixIndexPair{2ul, 2ul}}}," +
129 Dune::className<Material>() + ">"),
130 includes)
131 .first;
132 MAKE_MaterialFunction(pS, PlaneStressClass, storedEnergy, 3);
133 MAKE_MaterialFunction(pS, PlaneStressClass, stresses, 3);
134 MAKE_MaterialFunction(pS, PlaneStressClass, tangentModuli, 3);
135 MAKE_MaterialFunction(pS, PlaneStressClass, storedEnergy, 6);
136 MAKE_MaterialFunction(pS, PlaneStressClass, stresses, 6);
137 MAKE_MaterialFunction(pS, PlaneStressClass, tangentModuli, 6);
138 cls.def("asPlaneStress",
139 [](Material& self) { return planeStress(self); }); /* no keep_alive since planeStress copies the material */
140
141 using PlaneStrainClass = decltype(planeStrain(std::declval<Material>()));
142 auto pStrain = Dune::Python::insertClass<PlaneStrainClass>(
143 scope, std::string("PlaneStrain_") + materialname,
144 Dune::Python::GenerateTypeName(
145 "Ikarus::VanishingStrain<std::array<Ikarus::Impl::MatrixIndexPair, "
146 "3ul>{{Ikarus::Impl::MatrixIndexPair{2ul, 1ul}, Ikarus::Impl::MatrixIndexPair{2ul,0ul}, "
147 "Ikarus::Impl::MatrixIndexPair{2ul, 2ul}}}," +
148 Dune::className<Material>() + ">"),
149 includes)
150 .first;
151 MAKE_MaterialFunction(pStrain, PlaneStrainClass, storedEnergy, 3);
152 MAKE_MaterialFunction(pStrain, PlaneStrainClass, stresses, 3);
153 MAKE_MaterialFunction(pStrain, PlaneStrainClass, tangentModuli, 3);
154 MAKE_MaterialFunction(pStrain, PlaneStrainClass, storedEnergy, 6);
155 MAKE_MaterialFunction(pStrain, PlaneStrainClass, stresses, 6);
156 MAKE_MaterialFunction(pStrain, PlaneStrainClass, tangentModuli, 6);
157
158 cls.def("asPlaneStrain",
159 [](Material& self) { return planeStrain(self); }); /* no keep_alive since planeStrain copies the material */
160 using ShellMaterialClass = decltype(shellMaterial(std::declval<Material>()));
161 auto shellmaterial =
162 Dune::Python::insertClass<ShellMaterialClass>(
163 scope, std::string("Shell_") + materialname,
164 Dune::Python::GenerateTypeName("Ikarus::VanishingStress<std::array<Ikarus::Impl::MatrixIndexPair, "
165 "1ul>{{Ikarus::Impl::MatrixIndexPair{2ul, 2ul}}}," +
166 Dune::className<Material>() + ">"),
167 includes)
168 .first;
169 MAKE_MaterialFunction(shellmaterial, ShellMaterialClass, storedEnergy, 5);
170 MAKE_MaterialFunction(shellmaterial, ShellMaterialClass, stresses, 5);
171 MAKE_MaterialFunction(shellmaterial, ShellMaterialClass, tangentModuli, 5);
172 MAKE_MaterialFunction(shellmaterial, ShellMaterialClass, storedEnergy, 6);
173 MAKE_MaterialFunction(shellmaterial, ShellMaterialClass, stresses, 6);
174 MAKE_MaterialFunction(shellmaterial, ShellMaterialClass, tangentModuli, 6);
175
176 cls.def("asShellMaterial", [](Material& self) {
177 return shellMaterial(self);
178 }); /* no keep_alive since shellMaterial copies the material */
179 using BeamMaterialClass = decltype(beamMaterial(std::declval<Material>()));
180 auto beammaterial = Dune::Python::insertClass<BeamMaterialClass>(
181 scope, std::string("Beam_") + materialname,
182 Dune::Python::GenerateTypeName(
183 "Ikarus::VanishingStress<std::array<Ikarus::Impl::MatrixIndexPair, "
184 "2ul>{{Impl::MatrixIndexPair{1, 1},Ikarus::Impl::MatrixIndexPair{2ul, 2ul}}}," +
185 Dune::className<Material>() + ">"),
186 includes)
187 .first;
188 MAKE_MaterialFunction(beammaterial, BeamMaterialClass, storedEnergy, 4);
189 MAKE_MaterialFunction(beammaterial, BeamMaterialClass, stresses, 4);
190 MAKE_MaterialFunction(beammaterial, BeamMaterialClass, tangentModuli, 4);
191 MAKE_MaterialFunction(beammaterial, BeamMaterialClass, storedEnergy, 6);
192 MAKE_MaterialFunction(beammaterial, BeamMaterialClass, stresses, 6);
193 MAKE_MaterialFunction(beammaterial, BeamMaterialClass, tangentModuli, 6);
194 cls.def("asBeamMaterial",
195 [](Material& self) { return beamMaterial(self); }); /* no keep_alive since beamMaterial copies the material */
196}
197
198#define MAKE_MATERIAL_REGISTERY_FUNCTION(name, vecSize) \
199 template <class Material, class... options> \
200 void register##name(pybind11::handle scope, pybind11::class_<Material, options...> cls) { \
201 Ikarus::Python::registerMaterial<Material, vecSize>(scope, cls); \
202 }
203
207} // namespace Ikarus::Python
Several concepts.
#define MAKE_MaterialFunction(clsName, materialName, functionname, vecSize)
Definition: material.hh:20
ConvertLameConstants< YoungsModulusAndPoissonsRatio > convertLameConstants(const YoungsModulusAndPoissonsRatio &valuePair)
Definition: physicshelper.hh:250
auto planeStrain(const MaterialImpl &mat)
Factory function to create a VanishingStrain material for plane strain conditions.
Definition: vanishingstrain.hh:188
auto shellMaterial(const MaterialImpl &mat, typename MaterialImpl::ScalarType tol=1e-8)
Factory function to create a VanishingStress material for a shell material with zero normal stress co...
Definition: vanishingstress.hh:247
auto beamMaterial(const MaterialImpl &mat, typename MaterialImpl::ScalarType tol=1e-8)
Factory function to create a VanishingStress material for a beam material with two zero normal stress...
Definition: vanishingstress.hh:260
void init(int argc, char **argv, bool enableFileLogger=true)
Initializes the Ikarus framework.
Definition: init.hh:82
auto planeStress(const MaterialImpl &mat, typename MaterialImpl::ScalarType tol=1e-8)
Factory function to create a VanishingStress material for plane stress conditions.
Definition: vanishingstress.hh:233
Definition: flatassembler.hh:21
MAKE_MATERIAL_REGISTERY_FUNCTION(LinearElasticity, 6)
void registerMaterial(pybind11::handle scope, pybind11::class_< Material, options... > cls)
Definition: material.hh:106
Interface classf or materials.
Definition: finiteelements/mechanics/materials/interface.hh:80
static constexpr std::string name()
Get the name of the implemented material.
Definition: finiteelements/mechanics/materials/interface.hh:108
Implementation of the Linear Elasticity material model.The energy is computed as.
Definition: linearelasticity.hh:36
Implementation of the Neo-Hookean material model.The energy is computed as.
Definition: neohooke.hh:37
Implementation of the Saint Venant-Kirchhoff material model.The energy is computed as.
Definition: svk.hh:37
Definition: physicshelper.hh:54
Header file for material models in Ikarus finite element mechanics.