1 /*!
2  * \file  mfront/src/BehaviourDescription.cxx
3  * \brief
4  * \author Thomas Helfer
5  * \brief 07 mars 2014
6  * \copyright Copyright (C) 2006-2018 CEA/DEN, EDF R&D. All rights
7  * reserved.
8  * This project is publicly released under either the GNU GPL Licence
9  * or the CECILL-A licence. A copy of thoses licences are delivered
10  * with the sources of TFEL. CEA or EDF may also distribute this
11  * project under specific licensing conditions.
12  */
13 
14 #include <string>
15 #include <sstream>
16 #include <stdexcept>
17 #include <algorithm>
18 #include "TFEL/Raise.hxx"
19 #include "TFEL/Glossary/Glossary.hxx"
20 #include "TFEL/Glossary/GlossaryEntry.hxx"
21 #include "TFEL/Math/Evaluator.hxx"
22 #include "TFEL/Utilities/CxxTokenizer.hxx"
23 #include "MFront/PedanticMode.hxx"
24 #include "MFront/MFrontLogStream.hxx"
25 #include "MFront/LocalDataStructure.hxx"
26 #include "MFront/ModelDescription.hxx"
27 #include "MFront/MaterialPropertyDescription.hxx"
28 #include "MFront/BehaviourDescription.hxx"
29 
30 namespace mfront {
31 
buildMaterialPropertyDescription(const BehaviourDescription::ConstantMaterialProperty & mp,const BehaviourDescription & bd,const std::string & n)32   static MaterialPropertyDescription buildMaterialPropertyDescription(
33       const BehaviourDescription::ConstantMaterialProperty& mp,
34       const BehaviourDescription& bd,
35       const std::string& n) {
36     const auto prefix =
37         bd.isBehaviourNameDefined() ? bd.getBehaviourName() + "_" : "";
38     auto mpd = MaterialPropertyDescription{};
39     mpd.output = VariableDescription{"real", "res", 1u, 0u};
40     std::ostringstream body;
41     body << "res = " << mp.value << ";\n";
42     mpd.law = prefix + n;
43     mpd.className = prefix + n;
44     mpd.material = bd.getMaterialName();
45     mpd.f.modified = true;
46     mpd.f.body = body.str();
47     return mpd;
48   }  // end of buildMaterialPropertyDescription
49 
buildMaterialPropertyDescription(const BehaviourDescription::ExternalMFrontMaterialProperty & mp,const BehaviourDescription & bd,const std::string & n)50   static MaterialPropertyDescription buildMaterialPropertyDescription(
51       const BehaviourDescription::ExternalMFrontMaterialProperty& mp,
52       const BehaviourDescription& bd,
53       const std::string& n) {
54     const auto prefix =
55         bd.isBehaviourNameDefined() ? bd.getBehaviourName() + "_" : "";
56     auto mpd = *(mp.mpd);
57     mpd.law = prefix + n;
58     mpd.className = prefix + n;
59     mpd.material = bd.getMaterialName();
60     return mpd;
61   }  // end of buildMaterialPropertyDescription
62 
buildMaterialPropertyDescription(const BehaviourDescription::AnalyticMaterialProperty & mp,const BehaviourDescription & bd,const std::string & n)63   static MaterialPropertyDescription buildMaterialPropertyDescription(
64       const BehaviourDescription::AnalyticMaterialProperty& mp,
65       const BehaviourDescription& bd,
66       const std::string& n) {
67     const auto prefix =
68         bd.isBehaviourNameDefined() ? bd.getBehaviourName() + "_" : "";
69     auto mpd = MaterialPropertyDescription{};
70     mpd.output = VariableDescription{"real", "res", 1u, 0u};
71     mpd.law = prefix + n;
72     mpd.className = prefix + n;
73     mpd.material = bd.getMaterialName();
74     const auto h = *(bd.getDistinctModellingHypotheses().begin());
75     const auto& d = bd.getBehaviourData(h);
76     for (const auto& i : bd.getMaterialPropertyInputs(mp.getVariablesNames())) {
77       if (i.category ==
78           BehaviourDescription::MaterialPropertyInput::STATICVARIABLE) {
79         mpd.staticVars.push_back(d.getStaticVariables().get(i.name));
80       } else {
81         const auto& v = d.getVariableDescriptionByExternalName(i.ename);
82         mpd.inputs.push_back(v);
83       }
84     }
85     mpd.f.modified = true;
86     tfel::math::Evaluator e(mp.f);
87     mpd.f.body = "res = " + e.getCxxFormula() + ";\n";
88     return mpd;
89   }  // end of buildMaterialPropertyDescription
90 
buildMaterialPropertyDescription(const BehaviourDescription::MaterialProperty & mp,const BehaviourDescription & bd,const std::string & n)91   static MaterialPropertyDescription buildMaterialPropertyDescription(
92       const BehaviourDescription::MaterialProperty& mp,
93       const BehaviourDescription& bd,
94       const std::string& n) {
95     if (mp.is<BehaviourDescription::ConstantMaterialProperty>()) {
96       return buildMaterialPropertyDescription(
97           mp.get<BehaviourDescription::ConstantMaterialProperty>(), bd, n);
98     } else if (mp.is<BehaviourDescription::ExternalMFrontMaterialProperty>()) {
99       return buildMaterialPropertyDescription(
100           mp.get<BehaviourDescription::ExternalMFrontMaterialProperty>(), bd,
101           n);
102     } else if (mp.is<BehaviourDescription::AnalyticMaterialProperty>()) {
103       return buildMaterialPropertyDescription(
104           mp.get<BehaviourDescription::AnalyticMaterialProperty>(), bd, n);
105     } else {
106       tfel::raise(
107           "buildMaterialPropertyDescription: unsupported material property "
108           "type");
109     }
110   }  // end of buildMaterialPropertyDescription
111 
112   std::vector<std::string>
getVariablesNames() const113   BehaviourDescription::AnalyticMaterialProperty::getVariablesNames() const {
114     return tfel::math::Evaluator(this->f).getVariablesNames();
115   }  // end of AnalyticMaterialProperty::getVariablesNames
116 
117   template <typename Arg1>
callBehaviourData(const Hypothesis h,void (BehaviourData::* m)(const Arg1 &),const Arg1 & a,const bool b)118   void BehaviourDescription::callBehaviourData(
119       const Hypothesis h,
120       void (BehaviourData::*m)(const Arg1&),
121       const Arg1& a,
122       const bool b) {
123     if (h == ModellingHypothesis::UNDEFINEDHYPOTHESIS) {
124       (this->d.*m)(a);
125       if (b) {
126         for (auto md : this->sd) {
127           (md.second.get()->*m)(a);
128         }
129       }
130     } else {
131       (this->getBehaviourData2(h).*m)(a);
132     }
133   }  // end of BehaviourDescription::callBehaviourData
134 
135   template <typename Arg1>
callBehaviourData(const Hypothesis h,void (BehaviourData::* m)(const Arg1),const Arg1 a,const bool b)136   void BehaviourDescription::callBehaviourData(
137       const Hypothesis h,
138       void (BehaviourData::*m)(const Arg1),
139       const Arg1 a,
140       const bool b) {
141     if (h == ModellingHypothesis::UNDEFINEDHYPOTHESIS) {
142       (this->d.*m)(a);
143       if (b) {
144         for (const auto& ptr : this->sd) {
145           auto& bdata = *(ptr.second);
146           (bdata.*m)(a);
147         }
148       }
149     } else {
150       (this->getBehaviourData2(h).*m)(a);
151     }
152   }  // end of BehaviourDescription::callBehaviourData
153 
154   template <typename Arg1, typename Arg2>
callBehaviourData(const Hypothesis h,void (BehaviourData::* m)(const Arg1 &,const Arg2),const Arg1 & a1,const Arg2 a2,const bool b)155   void BehaviourDescription::callBehaviourData(
156       const Hypothesis h,
157       void (BehaviourData::*m)(const Arg1&, const Arg2),
158       const Arg1& a1,
159       const Arg2 a2,
160       const bool b) {
161     if (h == ModellingHypothesis::UNDEFINEDHYPOTHESIS) {
162       (this->d.*m)(a1, a2);
163       if (b) {
164         for (const auto& ptr : this->sd) {
165           auto& bdata = *(ptr.second);
166           (bdata.*m)(a1, a2);
167         }
168       }
169     } else {
170       (this->getBehaviourData2(h).*m)(a1, a2);
171     }
172   }  // end of BehaviourDescription::callBehaviourData
173 
174   template <typename Arg1, typename Arg2>
callBehaviourData(const Hypothesis h,void (BehaviourData::* m)(const Arg1 &,const Arg2 &),const Arg1 & a1,const Arg2 & a2,const bool b)175   void BehaviourDescription::callBehaviourData(
176       const Hypothesis h,
177       void (BehaviourData::*m)(const Arg1&, const Arg2&),
178       const Arg1& a1,
179       const Arg2& a2,
180       const bool b) {
181     if (h == ModellingHypothesis::UNDEFINEDHYPOTHESIS) {
182       (this->d.*m)(a1, a2);
183       if (b) {
184         for (const auto& ptr : this->sd) {
185           auto& bdata = *(ptr.second);
186           (bdata.*m)(a1, a2);
187         }
188       }
189     } else {
190       (this->getBehaviourData2(h).*m)(a1, a2);
191     }
192   }  // end of BehaviourDescription::callBehaviourData
193 
194   template <typename Arg1, typename Arg2, typename Arg3>
callBehaviourData(const Hypothesis h,void (BehaviourData::* m)(const Arg1 &,const Arg2 &,const Arg3 &),const Arg1 & a1,const Arg2 & a2,const Arg3 & a3,const bool b)195   void BehaviourDescription::callBehaviourData(
196       const Hypothesis h,
197       void (BehaviourData::*m)(const Arg1&, const Arg2&, const Arg3&),
198       const Arg1& a1,
199       const Arg2& a2,
200       const Arg3& a3,
201       const bool b) {
202     if (h == ModellingHypothesis::UNDEFINEDHYPOTHESIS) {
203       (this->d.*m)(a1, a2, a3);
204       if (b) {
205         for (const auto& ptr : this->sd) {
206           auto& bdata = *(ptr.second);
207           (bdata.*m)(a1, a2, a3);
208         }
209       }
210     } else {
211       (this->getBehaviourData2(h).*m)(a1, a2, a3);
212     }
213   }  // end of BehaviourDescription::callBehaviourData
214 
215   template <typename Res, typename Arg1>
216   Res BehaviourDescription::getData(const Hypothesis h,
217                                     Res (BehaviourData::*m)(const Arg1&) const,
218                                     const Arg1& a) const {
219     return (this->getBehaviourData(h).*m)(a);
220   }  // end of BehaviourDescription::getData
221 
declareParameter(BehaviourDescription & bd,BehaviourDescription::MaterialProperty & mp,const tfel::glossary::GlossaryEntry & e,const std::string & n)222   static void declareParameter(BehaviourDescription& bd,
223                                BehaviourDescription::MaterialProperty& mp,
224                                const tfel::glossary::GlossaryEntry& e,
225                                const std::string& n) {
226     const auto h = tfel::material::ModellingHypothesis::UNDEFINEDHYPOTHESIS;
227     if (mp.is<BehaviourDescription::ConstantMaterialProperty>()) {
228       auto& cmp = mp.get<BehaviourDescription::ConstantMaterialProperty>();
229       cmp.name = n;
230       // declare associated parameter
231       VariableDescription m("real", n, 1u, 0u);
232       bd.addParameter(h, m);
233       bd.setParameterDefaultValue(h, n, cmp.value);
234       bd.setGlossaryName(h, n, e.getKey());
235     }
236   }  // end of declareParameter
237 
checkElasticMaterialProperty(BehaviourDescription & bd,BehaviourDescription::MaterialProperty & emp,const tfel::glossary::GlossaryEntry & e,const std::string & n2)238   static void checkElasticMaterialProperty(
239       BehaviourDescription& bd,
240       BehaviourDescription::MaterialProperty& emp,
241       const tfel::glossary::GlossaryEntry& e,
242       const std::string& n2) {
243     if (emp.is<BehaviourDescription::ExternalMFrontMaterialProperty>()) {
244       const auto& mpd = *(
245           emp.get<BehaviourDescription::ExternalMFrontMaterialProperty>().mpd);
246       const auto& ename = mpd.output.getExternalName();
247       if (ename != e) {
248         getLogStream()
249             << "checkElasticMaterialProperty: inconsistent external name for "
250             << "material property '" + e.getKey() +
251                    "': external name of mfront file "
252             << "output  is '" << ename << "'\n";
253       }
254     }
255     declareParameter(bd, emp, e, n2);
256   }
257 
checkThermalExpansionCoefficientArgument(BehaviourDescription & bd,BehaviourDescription::MaterialProperty & a,const tfel::glossary::GlossaryEntry & e,const std::string & n)258   static void checkThermalExpansionCoefficientArgument(
259       BehaviourDescription& bd,
260       BehaviourDescription::MaterialProperty& a,
261       const tfel::glossary::GlossaryEntry& e,
262       const std::string& n) {
263     auto throw_if = [](const bool c, const std::string& m) {
264       tfel::raise_if(c, "checkThermalExpansionCoefficientArgument: " + m);
265     };
266     declareParameter(bd, a, e, n);
267     if (a.is<BehaviourDescription::ConstantMaterialProperty>()) {
268       return;
269     }
270     if (a.is<BehaviourDescription::ExternalMFrontMaterialProperty>()) {
271       const auto& mpd =
272           *(a.get<BehaviourDescription::ExternalMFrontMaterialProperty>().mpd);
273       for (const auto& i : bd.getMaterialPropertyInputs(mpd, false)) {
274         const auto c = i.category;
275         throw_if(
276             (c != BehaviourDescription::MaterialPropertyInput::TEMPERATURE) &&
277                 (c != BehaviourDescription::MaterialPropertyInput::
278                           MATERIALPROPERTY) &&
279                 (c != BehaviourDescription::MaterialPropertyInput::PARAMETER) &&
280                 (c !=
281                  BehaviourDescription::MaterialPropertyInput::STATICVARIABLE),
282             "invalid input '" + i.ename + "' (" + i.name +
283                 ") for thermal expansion");
284       }
285     } else if (a.is<BehaviourDescription::AnalyticMaterialProperty>()) {
286       const auto& vn = a.get<BehaviourDescription::AnalyticMaterialProperty>()
287                            .getVariablesNames();
288       for (const auto& i : bd.getMaterialPropertyInputs(vn, false)) {
289         const auto c = i.category;
290         throw_if(
291             (c != BehaviourDescription::MaterialPropertyInput::TEMPERATURE) &&
292                 (c != BehaviourDescription::MaterialPropertyInput::
293                           MATERIALPROPERTY) &&
294                 (c != BehaviourDescription::MaterialPropertyInput::PARAMETER) &&
295                 (c !=
296                  BehaviourDescription::MaterialPropertyInput::STATICVARIABLE),
297             "invalid input '" + i.ename + "' (" + i.name +
298                 ") for thermal expansion");
299       }
300     } else {
301       throw_if(true, "unsupported material property type");
302     }
303   }  // end of checkThermalExpansionCoefficientArgument
304 
305   static std::pair<VariableDescription, VariableDescription>
decomposeAdditionalTangentOperatorBlock(const BehaviourDescription & bd,const std::string & bn)306   decomposeAdditionalTangentOperatorBlock(const BehaviourDescription& bd,
307                                           const std::string& bn) {
308     const auto h = [&bd] {
309       if (bd.areModellingHypothesesDefined()) {
310         const auto mhs = bd.getModellingHypotheses();
311         if (mhs.size() == 1u) {
312           return *(mhs.begin());
313         }
314       }
315       return BehaviourDescription::ModellingHypothesis::UNDEFINEDHYPOTHESIS;
316     }();
317     auto a = VariableDescription{};
318     auto b = VariableDescription{};
319     auto found = false;
320     auto check = [&found, &bn] {
321       if (found) {
322         tfel::raise(
323             "decomposeAdditionalTangentOperatorBlock: "
324             "multiple match for block '" +
325             bn + "'");
326       }
327     };
328     auto assign_if = [&check, &a, &b, &found, &bn](
329         const VariableDescription& v1, const VariableDescription& v2,
330         const bool no_inc) {
331       const auto block_name = [&v1, &v2, &no_inc] {
332         if (no_inc) {
333           return "d" + v1.name + "_d" + v2.name + "1";
334         }
335         return "d" + v1.name + "_dd" + v2.name;
336       }();
337       const auto symbolic_block_name = [&v1, &v2, &no_inc] {
338         const auto tmp = "\u2202" + displayName(v1) + "\u2215\u2202";
339         if (no_inc) {
340           return tmp + displayName(v2) + "1";
341         }
342         return tmp + "\u0394" + displayName(v2);
343       }();
344       if ((bn == block_name) || (bn == symbolic_block_name)) {
345         check();
346         a = v1;
347         b = v2;
348         found = true;
349       }
350     };
351     const auto& d = bd.getBehaviourData(h);
352     for (const auto& mv : bd.getMainVariables()) {
353       for (const auto& mv2 : bd.getMainVariables()) {
354         assign_if(mv.second, mv2.first, !Gradient::isIncrementKnown(mv2.first));
355       }
356       for (const auto& e : d.getExternalStateVariables()) {
357         assign_if(mv.second, e, false);
358       }
359     }
360     for (const auto& s : d.getPersistentVariables()) {
361       for (const auto& mv : bd.getMainVariables()) {
362         assign_if(s, mv.first, !Gradient::isIncrementKnown(mv.first));
363       }
364       for (const auto& e : d.getExternalStateVariables()) {
365         assign_if(s, e, false);
366       }
367     }
368     if (!found) {
369       tfel::raise(
370           "decomposeAdditionalTangentOperatorBlock: "
371           "no match for '" +
372           bn + "'");
373     }
374     return {a, b};
375   }  // end of decomposeTangentOperatorBlock
376 
377   const char* const BehaviourDescription::requiresStiffnessTensor =
378       "requiresStiffnessTensor";
379 
380   const char* const BehaviourDescription::computesStiffnessTensor =
381       "computesStiffnessTensor";
382 
383   const char* const BehaviourDescription::requiresUnAlteredStiffnessTensor =
384       "requiresUnAlteredStiffnessTensor";
385 
386   const char* const
387       BehaviourDescription::requiresThermalExpansionCoefficientTensor =
388           "requiresThermalExpansionCoefficientTensor";
389 
390   BehaviourDescription::BehaviourDescription() = default;
391 
392   BehaviourDescription::BehaviourDescription(const BehaviourDescription&) =
393       default;
394 
allowsNewUserDefinedVariables() const395   bool BehaviourDescription::allowsNewUserDefinedVariables() const {
396     const auto h = ModellingHypothesis::UNDEFINEDHYPOTHESIS;
397     return this->getAttribute(h, BehaviourData::allowsNewUserDefinedVariables,
398                               true);
399   }  // end of BehaviourDescription::allowNewsUserDefinedVariables
400 
disallowNewUserDefinedVariables()401   void BehaviourDescription::disallowNewUserDefinedVariables() {
402     const auto uh = ModellingHypothesis::UNDEFINEDHYPOTHESIS;
403     this->setAttribute(uh, BehaviourData::allowsNewUserDefinedVariables, false);
404   }  // end of BehaviourDescription::disallowNewUserDefinedVariables
405 
throwUndefinedAttribute(const std::string & n)406   void BehaviourDescription::throwUndefinedAttribute(const std::string& n) {
407     tfel::raise(
408         "BehaviourDescription::getAttribute: "
409         "no attribute named '" +
410         n + "'");
411   }  // end of BehaviourDescription::throwUndefinedAttribute
412 
getBehaviourData(const Hypothesis h) const413   const BehaviourData& BehaviourDescription::getBehaviourData(
414       const Hypothesis h) const {
415     // check that the given hypothesis is supported
416     if (h == ModellingHypothesis::UNDEFINEDHYPOTHESIS) {
417       return this->d;
418     }
419     this->checkModellingHypothesis(h);
420     this->requestedHypotheses.insert(h);
421     // check if a specialised version of the behaviour
422     // description has been defined
423     const auto p = this->sd.find(h);
424     if (p != this->sd.end()) {
425       return *(p->second);
426     }
427     // return the default...
428     return this->d;
429   }  // end of BehaviourDescription::getBehaviourData
430 
specialize(const Hypothesis h)431   void BehaviourDescription::specialize(const Hypothesis h) {
432     if (this->areModellingHypothesesDefined()) {
433       this->checkModellingHypothesis(h);
434     }
435     auto p = this->sd.find(h);
436     if (p == this->sd.end()) {
437       // copy of the default description
438       this->sd.insert({h, std::make_shared<BehaviourData>(this->d)}).first;
439     }
440   }  // end of BehaviourDescription::specialize
441 
getBehaviourData2(const Hypothesis h)442   BehaviourData& BehaviourDescription::getBehaviourData2(const Hypothesis h) {
443     // check that the given hypothesis is supported
444     if (h == ModellingHypothesis::UNDEFINEDHYPOTHESIS) {
445       return this->d;
446     }
447     if (this->areModellingHypothesesDefined()) {
448       this->checkModellingHypothesis(h);
449     }
450     this->requestedHypotheses.insert(h);
451     auto p = this->sd.find(h);
452     if (p == this->sd.end()) {
453       // copy of the default description
454       p = this->sd.insert({h, std::make_shared<BehaviourData>(this->d)}).first;
455     }
456     return *(p->second);
457   }  // end of BehaviourDescription::getBehaviourData2
458 
isBehaviourNameDefined() const459   bool BehaviourDescription::isBehaviourNameDefined() const {
460     return !this->behaviour.empty();
461   }  // end of BehaviourDescription::isBehaviourNameDefined
462 
setBehaviourName(const std::string & m)463   void BehaviourDescription::setBehaviourName(const std::string& m) {
464     tfel::raise_if(!this->behaviour.empty(),
465                    "BehaviourDescription::setBehaviourName: "
466                    "behaviour name already defined");
467     this->behaviour = m;
468     this->updateClassName();
469   }  // end of BehaviourDescription::setBehaviourName
470 
getBehaviourName() const471   const std::string& BehaviourDescription::getBehaviourName() const {
472     tfel::raise_if(this->behaviour.empty(),
473                    "BehaviourDescription::getBehaviourName: "
474                    "behaviour name not defined");
475     return this->behaviour;
476   }  // end of BehaviourDescription::getBehaviourName
477 
setDSLName(const std::string & m)478   void BehaviourDescription::setDSLName(const std::string& m) {
479     tfel::raise_if(!this->dsl.empty(),
480                    "BehaviourDescription::setDSLName: "
481                    "dsl name already defined");
482     this->dsl = m;
483     this->updateClassName();
484   }  // end of BehaviourDescription::setDSLName
485 
getDSLName() const486   const std::string& BehaviourDescription::getDSLName() const {
487     tfel::raise_if(this->dsl.empty(),
488                    "BehaviourDescription::getDSLName: "
489                    "dsl name not defined");
490     return this->dsl;
491   }  // end of BehaviourDescription::getDSLName
492 
493   BehaviourDescription::MaterialPropertyInput::Category
getMaterialPropertyInputCategory(const Hypothesis h,const std::string & v) const494   BehaviourDescription::getMaterialPropertyInputCategory(
495       const Hypothesis h, const std::string& v) const {
496     auto throw_if = [](const bool c, const std::string& m) {
497       tfel::raise_if(
498           c, "BehaviourDescription::getMaterialPropertyInputCategory: " + m);
499     };
500     if (this->isStateVariableName(h, v)) {
501       return MaterialPropertyInput::STATEVARIABLE;
502     } else if (this->isExternalStateVariableName(h, v)) {
503       return MaterialPropertyInput::EXTERNALSTATEVARIABLE;
504     } else if (this->isAuxiliaryStateVariableName(h, v)) {
505       const auto& bd = this->getBehaviourData(h);
506       const auto& av = bd.getAuxiliaryStateVariableDescription(v);
507       throw_if(
508           !av.getAttribute<bool>("ComputedByExternalModel", false),
509           "only auxiliary state variable computed by a model are allowed here");
510       return MaterialPropertyInput::AUXILIARYSTATEVARIABLEFROMEXTERNALMODEL;
511     } else if (this->isMaterialPropertyName(h, v)) {
512       return MaterialPropertyInput::MATERIALPROPERTY;
513     } else if (this->isParameterName(h, v)) {
514       return MaterialPropertyInput::PARAMETER;
515     } else if (this->isStaticVariableName(h, v)) {
516       return MaterialPropertyInput::STATICVARIABLE;
517     }
518     throw_if(true, "unsupported variable: variable '" + v +
519                        "' is "
520                        "neither an external state variable, a material "
521                        "property nor a parameter nor an auxiliary "
522                        "state variable evaluated by an external model, "
523                        "nor a static variable");
524   }  // end of BehaviourDescription::getMaterialPropertyInputCategory
525 
526   std::vector<BehaviourDescription::MaterialPropertyInput>
getMaterialPropertyInputs(const std::vector<std::string> & i,const bool b) const527   BehaviourDescription::getMaterialPropertyInputs(
528       const std::vector<std::string>& i, const bool b) const {
529     auto throw_if = [](const bool c, const std::string& m) {
530       tfel::raise_if(c,
531                      "BehaviourDescription::getMaterialPropertyInputs: " + m);
532     };
533     auto inputs = std::vector<MaterialPropertyInput>{};
534     const auto hs = [this, b,
535                      throw_if]() -> std::set<BehaviourDescription::Hypothesis> {
536       if (this->hypotheses.empty()) {
537         // modelling hypotheses are not set yet
538         throw_if(b, "modelling hypothesis must be defined");
539         return {ModellingHypothesis::UNDEFINEDHYPOTHESIS};
540       }
541       return this->getDistinctModellingHypotheses();
542     }();
543     for (const auto& v : i) {
544       if (v == "T") {
545         inputs.push_back({"T", tfel::glossary::Glossary::Temperature,
546                           MaterialPropertyInput::TEMPERATURE});
547       } else {
548         const auto rh = *(hs.begin());
549         const auto t = this->getMaterialPropertyInputCategory(rh, v);
550         if (t == MaterialPropertyInput::STATICVARIABLE) {
551           for (const auto h : hs) {
552             throw_if(this->getMaterialPropertyInputCategory(h, v) != t,
553                      "the variable '" + v +
554                          "' belongs to two different "
555                          "categories in two distinct modelling hypotheses. "
556                          "This is not supported.");
557           }
558           inputs.push_back({v, v, t});
559         } else {
560           const auto vd = this->getBehaviourData(rh).getVariableDescription(v);
561           const auto en = vd.getExternalName();
562           for (const auto h : hs) {
563             const auto vd2 =
564                 this->getBehaviourData(h).getVariableDescription(v);
565             throw_if(vd2.getExternalName() != en,
566                      "the variable '" + v +
567                          "' has two different "
568                          "external names in two distinct modelling hypotheses."
569                          "This is not supported.");
570             throw_if(this->getMaterialPropertyInputCategory(h, v) != t,
571                      "the variable '" + v +
572                          "' belongs to two different "
573                          "categories in two distinct modelling hypotheses. "
574                          "This is not supported.");
575           }
576           inputs.push_back({v, en, t});
577         }
578       }
579     }
580     return inputs;
581   }  // end of BehaviourDescription::getMaterialPropertyInputs
582 
583   std::vector<BehaviourDescription::MaterialPropertyInput>
getMaterialPropertyInputs(const MaterialPropertyDescription & mpd,const bool b) const584   BehaviourDescription::getMaterialPropertyInputs(
585       const MaterialPropertyDescription& mpd, const bool b) const {
586     auto throw_if = [](const bool c, const std::string& m) {
587       tfel::raise_if(c,
588                      "BehaviourDescription::getMaterialPropertyInputs: " + m);
589     };
590     auto inputs = std::vector<MaterialPropertyInput>{};
591     const auto hs = [this, b,
592                      throw_if]() -> std::set<BehaviourDescription::Hypothesis> {
593       if (this->hypotheses.empty()) {
594         // modelling hypotheses are not set yet
595         throw_if(b, "modelling hypothesis must be defined");
596         return {ModellingHypothesis::UNDEFINEDHYPOTHESIS};
597       }
598       return this->getDistinctModellingHypotheses();
599     }();
600     for (const auto& v : mpd.inputs) {
601       if ((getPedanticMode()) &&
602           (!(v.hasGlossaryName()) && (!v.hasEntryName()))) {
603         getLogStream() << "BehaviourDescription::getMaterialPropertyInputs: "
604                           "no glossary nor entry name declared for variable "
605                           "'" +
606                               v.name + "' used by the material property '" +
607                               mpd.law + "'\n";
608       }
609       const auto& vn = v.getExternalName();
610       if (vn == tfel::glossary::Glossary::Temperature) {
611         inputs.push_back({"T", tfel::glossary::Glossary::Temperature,
612                           MaterialPropertyInput::TEMPERATURE});
613       } else {
614         const auto n =
615             this->getVariableDescriptionByExternalName(*(hs.begin()), vn).name;
616         const auto t = this->getMaterialPropertyInputCategory(*(hs.begin()), n);
617         for (const auto h : hs) {
618           throw_if(this->getVariableDescriptionByExternalName(h, vn).name != n,
619                    "the external name '" + vn +
620                        "' is associated with "
621                        "two differents variables in two distinct "
622                        "modelling hypotheses. This is not supported.");
623           throw_if(this->getMaterialPropertyInputCategory(h, n) != t,
624                    "the external name '" + vn +
625                        "' has two different "
626                        "types in two distinct modelling hypotheses. "
627                        "This is not supported.");
628         }
629         inputs.push_back({n, vn, t});
630       }
631     }
632     return inputs;
633   }  // end of BehaviourDescription::getMaterialPropertyInputs
634 
setIntegrationScheme(const BehaviourDescription::IntegrationScheme s)635   void BehaviourDescription::setIntegrationScheme(
636       const BehaviourDescription::IntegrationScheme s) {
637     tfel::raise_if(this->ischeme != UNDEFINEDINTEGRATIONSCHEME,
638                    "BehaviourDescription::setIntegrationScheme: "
639                    "integration scheme already defined");
640     this->ischeme = s;
641   }  // end of BehaviourDescription::setIntegrationScheme
642 
643   BehaviourDescription::IntegrationScheme
getIntegrationScheme() const644   BehaviourDescription::getIntegrationScheme() const {
645     tfel::raise_if(this->ischeme == UNDEFINEDINTEGRATIONSCHEME,
646                    "BehaviourDescription::getIntegrationScheme: "
647                    "the integration scheme is undefined");
648     return this->ischeme;
649   }  // end of BehaviourDescription::getIntegrationScheme
650 
setLibrary(const std::string & l)651   void BehaviourDescription::setLibrary(const std::string& l) {
652     tfel::raise_if(!this->library.empty(),
653                    "BehaviourDescription::setLibrary: "
654                    "library alreay defined");
655     this->library = l;
656   }  // end of BehaviourDescription::setLibrary
657 
getLibrary() const658   const std::string& BehaviourDescription::getLibrary() const {
659     return this->library;
660   }  // end of BehaviourDescription::getLibrary
661 
setMaterialName(const std::string & m)662   void BehaviourDescription::setMaterialName(const std::string& m) {
663     tfel::raise_if(!this->material.empty(),
664                    "BehaviourDescription::setMaterialName: "
665                    "material name alreay defined");
666     this->material = m;
667     this->updateClassName();
668   }  // end of BehaviourDescription::setMaterialName
669 
getMaterialName() const670   const std::string& BehaviourDescription::getMaterialName() const {
671     return this->material;
672   }  // end of BehaviourDescription::getMaterialName
673 
setClassName(const std::string & n)674   void BehaviourDescription::setClassName(const std::string& n) {
675     tfel::raise_if(!this->className.empty(),
676                    "BehaviourDescription::setClassName: "
677                    "class name alreay defined");
678     this->className = n;
679   }  // end of BehaviourDescription::setClassName
680 
getClassName() const681   const std::string& BehaviourDescription::getClassName() const {
682     tfel::raise_if(this->className.empty(),
683                    "BehaviourDescription::getClassName: "
684                    "class name not defined");
685     return this->className;
686   }  // end of BehaviourDescription::getClassName
687 
appendToIncludes(const std::string & c)688   void BehaviourDescription::appendToIncludes(const std::string& c) {
689     this->includes += c;
690     if (!this->includes.empty()) {
691       if (*(this->includes.rbegin()) != '\n') {
692         this->includes += '\n';
693       }
694     }
695   }  // end of BehaviourDescription::appendToIncludes
696 
getIncludes() const697   const std::string& BehaviourDescription::getIncludes() const {
698     return this->includes;
699   }  // end of BehaviourDescription::getIncludes
700 
appendToMembers(const Hypothesis h,const std::string & c,const bool b)701   void BehaviourDescription::appendToMembers(const Hypothesis h,
702                                              const std::string& c,
703                                              const bool b) {
704     this->callBehaviourData(h, &BehaviourData::appendToMembers, c, b);
705   }  // end of BehaviourDescription::appendToMembers
706 
getMembers(const Hypothesis h) const707   std::string BehaviourDescription::getMembers(const Hypothesis h) const {
708     return this->getBehaviourData(h).getMembers();
709   }  // end of BehaviourDescription::getMembers
710 
appendToPrivateCode(const Hypothesis h,const std::string & c,const bool b)711   void BehaviourDescription::appendToPrivateCode(const Hypothesis h,
712                                                  const std::string& c,
713                                                  const bool b) {
714     this->callBehaviourData(h, &BehaviourData::appendToPrivateCode, c, b);
715   }  // end of BehaviourDescription::appendToPrivateCode
716 
getPrivateCode(const Hypothesis h) const717   std::string BehaviourDescription::getPrivateCode(const Hypothesis h) const {
718     return this->getBehaviourData(h).getPrivateCode();
719   }  // end of BehaviourDescription::getPrivateCode
720 
appendToSources(const std::string & c)721   void BehaviourDescription::appendToSources(const std::string& c) {
722     this->sources += c;
723     if (!this->sources.empty()) {
724       if (*(this->sources.rbegin()) != '\n') {
725         this->sources += '\n';
726       }
727     }
728   }  // end of BehaviourDescription::appendToSources
729 
getSources() const730   const std::string& BehaviourDescription::getSources() const {
731     return this->sources;
732   }  // end of BehaviourDescription::getSources
733 
getBehaviourType() const734   BehaviourDescription::BehaviourType BehaviourDescription::getBehaviourType()
735       const {
736     if (this->type.empty()) {
737       tfel::raise(
738           "BehaviourDescription::getBehaviourType: "
739           "undefined behaviour type");
740     }
741     return this->type;
742   }  // end of BehaviourDescription::getBehaviourType
743 
getBehaviourTypeFlag() const744   std::string BehaviourDescription::getBehaviourTypeFlag() const {
745     std::string btype;
746     if (this->getBehaviourType() ==
747         BehaviourDescription::STANDARDSTRAINBASEDBEHAVIOUR) {
748       btype = "MechanicalBehaviourBase::STANDARDSTRAINBASEDBEHAVIOUR";
749     } else if (this->getBehaviourType() ==
750                BehaviourDescription::STANDARDFINITESTRAINBEHAVIOUR) {
751       btype = "MechanicalBehaviourBase::STANDARDFINITESTRAINBEHAVIOUR";
752     } else if (this->getBehaviourType() ==
753                BehaviourDescription::COHESIVEZONEMODEL) {
754       btype = "MechanicalBehaviourBase::COHESIVEZONEMODEL";
755     } else if (this->getBehaviourType() ==
756                BehaviourDescription::GENERALBEHAVIOUR) {
757       btype = "MechanicalBehaviourBase::GENERALBEHAVIOUR";
758     } else {
759       tfel::raise(
760           "BehaviourDescription::getBehaviourTypeFlag: "
761           "unsupported behaviour type");
762     }
763     return btype;
764   }  // end of BehaviourDescription::getBehaviourTypeFlag
765 
areElasticMaterialPropertiesDefined() const766   bool BehaviourDescription::areElasticMaterialPropertiesDefined() const {
767     return !this->elasticMaterialProperties.empty();
768   }  // end of BehaviourDescription::areElasticMaterialPropertiesDefined
769 
isMaterialPropertyConstantDuringTheTimeStep(const MaterialProperty & mp) const770   bool BehaviourDescription::isMaterialPropertyConstantDuringTheTimeStep(
771       const MaterialProperty& mp) const {
772     if (mp.is<ExternalMFrontMaterialProperty>()) {
773       const auto& cmp = mp.get<ExternalMFrontMaterialProperty>();
774       for (const auto& i : this->getMaterialPropertyInputs(*(cmp.mpd))) {
775         if (!((i.category ==
776                BehaviourDescription::MaterialPropertyInput::MATERIALPROPERTY) ||
777               (i.category ==
778                BehaviourDescription::MaterialPropertyInput::PARAMETER))) {
779           return false;
780         }
781       }
782       return true;
783     } else if (mp.is<AnalyticMaterialProperty>()) {
784       const auto& amp = mp.get<AnalyticMaterialProperty>();
785       for (const auto& i :
786            this->getMaterialPropertyInputs(amp.getVariablesNames())) {
787         if (!((i.category ==
788                BehaviourDescription::MaterialPropertyInput::MATERIALPROPERTY) ||
789               (i.category ==
790                BehaviourDescription::MaterialPropertyInput::PARAMETER))) {
791           return false;
792         }
793       }
794       return true;
795     }
796     return true;
797   }  // end of BehaviourDescription::isMaterialPropertyConstantDuringTheTimeStep
798 
799   bool
areElasticMaterialPropertiesConstantDuringTheTimeStep() const800   BehaviourDescription::areElasticMaterialPropertiesConstantDuringTheTimeStep()
801       const {
802     tfel::raise_if(!this->areElasticMaterialPropertiesDefined(),
803                    "BehaviourDescription::"
804                    "areElasticMaterialPropertiesConstantDuringTheTimeStep: "
805                    "no elastic material property defined");
806     return this->areMaterialPropertiesConstantDuringTheTimeStep(
807         this->elasticMaterialProperties);
808   }  // end of
809   // BehaviourDescription::areElasticMaterialPropertiesConstantDuringTheTimeStep
810 
areMaterialPropertiesConstantDuringTheTimeStep(const std::vector<MaterialProperty> & mps) const811   bool BehaviourDescription::areMaterialPropertiesConstantDuringTheTimeStep(
812       const std::vector<MaterialProperty>& mps) const {
813     for (const auto& mp : mps) {
814       if (!this->isMaterialPropertyConstantDuringTheTimeStep(mp)) {
815         return false;
816       }
817     }
818     return true;
819   }  // end of
820      // BehaviourDescription::areMaterialPropertiesConstantDuringTheTimeStep
821 
isMaterialPropertyDependantOnStateVariables(const MaterialProperty & mp) const822   bool BehaviourDescription::isMaterialPropertyDependantOnStateVariables(
823       const MaterialProperty& mp) const {
824     if (mp.is<ExternalMFrontMaterialProperty>()) {
825       const auto& cmp = mp.get<ExternalMFrontMaterialProperty>();
826       for (const auto& i : this->getMaterialPropertyInputs(*(cmp.mpd))) {
827         if (i.category ==
828             BehaviourDescription::MaterialPropertyInput::STATEVARIABLE) {
829           return true;
830         }
831       }
832       return false;
833     }
834     if (mp.is<AnalyticMaterialProperty>()) {
835       const auto& amp = mp.get<AnalyticMaterialProperty>();
836       for (const auto& i :
837            this->getMaterialPropertyInputs(amp.getVariablesNames())) {
838         if (i.category ==
839             BehaviourDescription::MaterialPropertyInput::STATEVARIABLE) {
840           return true;
841         }
842       }
843       return false;
844     }
845     tfel::raise_if(
846         !mp.is<ConstantMaterialProperty>(),
847         "BehaviourDescription::isMaterialPropertyDependantOnStateVariables: "
848         "unsupported material property");
849     return false;
850   }  // end of BehaviourDescription::isMaterialPropertyDependantOnStateVariables
851 
852   bool
areElasticMaterialPropertiesDependantOnStateVariables() const853   BehaviourDescription::areElasticMaterialPropertiesDependantOnStateVariables()
854       const {
855     tfel::raise_if(!this->areElasticMaterialPropertiesDefined(),
856                    "BehaviourDescription::"
857                    "areElasticMaterialPropertiesDependantOnStateVariables: "
858                    "no elastic material property defined");
859     return this->areMaterialPropertiesDependantOnStateVariables(
860         this->elasticMaterialProperties);
861   }  // end of
862   // BehaviourDescription::areElasticMaterialPropertiesDependantOnStateVariables
863 
areMaterialPropertiesDependantOnStateVariables(const std::vector<MaterialProperty> & mps) const864   bool BehaviourDescription::areMaterialPropertiesDependantOnStateVariables(
865       const std::vector<MaterialProperty>& mps) const {
866     for (const auto& mp : mps) {
867       if (this->isMaterialPropertyDependantOnStateVariables(mp)) {
868         return true;
869       }
870     }
871     return false;
872   }  // end of
873      // BehaviourDescription::areMaterialPropertiesDependantOnStateVariables
874 
875   const std::vector<BehaviourDescription::MaterialProperty>&
getElasticMaterialProperties() const876   BehaviourDescription::getElasticMaterialProperties() const {
877     tfel::raise_if(!this->areElasticMaterialPropertiesDefined(),
878                    "BehaviourDescription::getElasticMaterialProperties: "
879                    "no elastic material property defined");
880     return this->elasticMaterialProperties;
881   }
882 
setElasticMaterialProperties(const std::vector<MaterialProperty> & emps)883   void BehaviourDescription::setElasticMaterialProperties(
884       const std::vector<MaterialProperty>& emps) {
885     auto throw_if = [](const bool b, const std::string& m) {
886       tfel::raise_if(
887           b, "BehaviourDescription::setElasticMaterialProperties: " + m);
888     };
889     throw_if(!this->allowsNewUserDefinedVariables(),
890              "new variables are can't be defined after the first code block.");
891     throw_if((this->getBehaviourType() !=
892               BehaviourDescription::STANDARDFINITESTRAINBEHAVIOUR) &&
893                  (this->getBehaviourType() !=
894                   BehaviourDescription::STANDARDSTRAINBASEDBEHAVIOUR),
895              "only finite and strain behaviour are supported");
896     this->setAttribute(BehaviourDescription::requiresStiffnessTensor, false,
897                        false);
898     throw_if(!this->elasticMaterialProperties.empty(),
899              "elastic material property already declared");
900     auto lemps =
901         emps;  // local copy, swap to data member if no exceptions is thrown
902     if (emps.size() == 2u) {
903       if (this->isElasticSymmetryTypeDefined()) {
904         throw_if(this->getElasticSymmetryType() != mfront::ISOTROPIC,
905                  "inconsistent elastic symmetry type");
906       } else {
907         this->setElasticSymmetryType(mfront::ISOTROPIC);
908       }
909       checkElasticMaterialProperty(
910           *this, lemps[0], tfel::glossary::Glossary::YoungModulus, "young");
911       checkElasticMaterialProperty(
912           *this, lemps[1], tfel::glossary::Glossary::PoissonRatio, "nu");
913     } else if (emps.size() == 9u) {
914       throw_if(this->getSymmetryType() != mfront::ORTHOTROPIC,
915                "the behaviour is not orthotropic.");
916       if (this->isElasticSymmetryTypeDefined()) {
917         throw_if(this->getElasticSymmetryType() != mfront::ORTHOTROPIC,
918                  "inconsistent elastic symmetry type");
919       } else {
920         this->setElasticSymmetryType(mfront::ORTHOTROPIC);
921       }
922       checkElasticMaterialProperty(
923           *this, lemps[0], tfel::glossary::Glossary::YoungModulus1, "young1");
924       checkElasticMaterialProperty(
925           *this, lemps[1], tfel::glossary::Glossary::YoungModulus2, "young2");
926       checkElasticMaterialProperty(
927           *this, lemps[2], tfel::glossary::Glossary::YoungModulus3, "young3");
928       checkElasticMaterialProperty(
929           *this, lemps[3], tfel::glossary::Glossary::PoissonRatio12, "nu12");
930       checkElasticMaterialProperty(
931           *this, lemps[4], tfel::glossary::Glossary::PoissonRatio23, "nu23");
932       checkElasticMaterialProperty(
933           *this, lemps[5], tfel::glossary::Glossary::PoissonRatio13, "nu13");
934       checkElasticMaterialProperty(
935           *this, lemps[6], tfel::glossary::Glossary::ShearModulus12, "mu12");
936       checkElasticMaterialProperty(
937           *this, lemps[7], tfel::glossary::Glossary::ShearModulus23, "mu23");
938       checkElasticMaterialProperty(
939           *this, lemps[8], tfel::glossary::Glossary::ShearModulus13, "mu13");
940     } else {
941       throw_if(true, "unsupported behaviour type");
942     }
943     this->elasticMaterialProperties.swap(lemps);
944   }  // end of BehaviourDescription::setElasticMaterialProperties
945 
getElasticSymmetryType() const946   BehaviourSymmetryType BehaviourDescription::getElasticSymmetryType() const {
947     if (!this->estypeIsDefined) {
948       this->estype = this->getSymmetryType();
949       this->estypeIsDefined = true;
950     }
951     return this->estype;
952   }  // end of BehaviourDescription::getElasticSymmetryType
953 
setElasticSymmetryType(const BehaviourSymmetryType t)954   void BehaviourDescription::setElasticSymmetryType(
955       const BehaviourSymmetryType t) {
956     tfel::raise_if(this->estypeIsDefined,
957                    "BehaviourDescription::setElasticSymmetryType: "
958                    "elastic symmetry type already declared");
959     const auto s = this->getSymmetryType();
960     tfel::raise_if((s == mfront::ISOTROPIC) && (t == mfront::ORTHOTROPIC),
961                    "BehaviourDescription::setElasticSymmetryType: "
962                    "can't define an orthotropic elastic symmetry for "
963                    "an isotropic material");
964     this->estype = t;
965     this->estypeIsDefined = true;
966   }  // end of BehaviourDescription::setElasticSymmetryType
967 
isElasticSymmetryTypeDefined() const968   bool BehaviourDescription::isElasticSymmetryTypeDefined() const {
969     return this->estypeIsDefined;
970   }  // end of BehaviourDescription::isElasticSymmetryTypeDefined
971 
getSymmetryType() const972   BehaviourSymmetryType BehaviourDescription::getSymmetryType() const {
973     if (!this->stypeIsDefined) {
974       this->stype = mfront::ISOTROPIC;
975       this->stypeIsDefined = true;
976     }
977     return this->stype;
978   }  // end of BehaviourDescription::getSymmetryType
979 
setSymmetryType(const BehaviourSymmetryType t)980   void BehaviourDescription::setSymmetryType(const BehaviourSymmetryType t) {
981     tfel::raise_if(this->stypeIsDefined,
982                    "BehaviourDescription::setSymmetryType: "
983                    "symmetry type already declared");
984     this->stype = t;
985     this->stypeIsDefined = true;
986   }  // end of BehaviourDescription::setSymmetryType
987 
isSymmetryTypeDefined() const988   bool BehaviourDescription::isSymmetryTypeDefined() const {
989     return this->stypeIsDefined;
990   }  // end of BehaviourDescription::setSymmetryType
991 
setCrystalStructure(const CrystalStructure s)992   void BehaviourDescription::setCrystalStructure(const CrystalStructure s) {
993     tfel::raise_if(this->hasCrystalStructure(),
994                    "BehaviourDescription::setCrystalStructure: "
995                    "crystal structure already declared");
996     this->gs = SlipSystemsDescription(s);
997   }  // end of BehaviourDescription::setCrystalStructure
998 
hasCrystalStructure() const999   bool BehaviourDescription::hasCrystalStructure() const {
1000     return !this->gs.empty();
1001   }  // end of BehaviourDescription::hasCrystalStructure
1002 
1003   BehaviourDescription::CrystalStructure
getCrystalStructure() const1004   BehaviourDescription::getCrystalStructure() const {
1005     tfel::raise_if(!this->hasCrystalStructure(),
1006                    "BehaviourDescription::setCrystalStructure: "
1007                    "no crystal structure declared");
1008     return this->gs.get<SlipSystemsDescription>().getCrystalStructure();
1009   }  // end of BehaviourDescription::getCrystalStructure
1010 
addHillTensor(const VariableDescription & v,const std::vector<MaterialProperty> & hcs)1011   void BehaviourDescription::addHillTensor(
1012       const VariableDescription& v, const std::vector<MaterialProperty>& hcs) {
1013     auto throw_if = [](const bool c, const std::string& m) {
1014       tfel::raise_if(c, "BehaviourDescription::addHillTensor: " + m);
1015     };
1016     throw_if(
1017         (this->getBehaviourType() !=
1018          BehaviourDescription::STANDARDFINITESTRAINBEHAVIOUR) &&
1019             (this->getBehaviourType() !=
1020              BehaviourDescription::STANDARDSTRAINBASEDBEHAVIOUR),
1021         "this method is only valid for small and finite strain behaviours");
1022     throw_if(this->getSymmetryType() != mfront::ORTHOTROPIC,
1023              "the behaviour is not orthotropic.");
1024     throw_if(hcs.size() != 6u, "invalid number of Hill coefficients");
1025     throw_if(v.arraySize != 1u, "invalid array size");
1026     throw_if(v.type != "tfel::math::st2tost2<N,stress>", "invalid type");
1027     this->addLocalVariable(ModellingHypothesis::UNDEFINEDHYPOTHESIS, v);
1028     HillTensor h;
1029     h.name = v.name;
1030     h.symbolic_form = v.symbolic_form;
1031     std::copy(hcs.begin(), hcs.end(), std::back_inserter(h.c));
1032     this->hillTensors.push_back(std::move(h));
1033   }  // end of BehaviourDescription::addHillTensor
1034 
1035   const std::vector<BehaviourDescription::HillTensor>&
getHillTensors() const1036   BehaviourDescription::getHillTensors() const {
1037     return this->hillTensors;
1038   }  // end of BehaviourDescription::getHillTensors
1039 
declareAsGenericBehaviour()1040   void BehaviourDescription::declareAsGenericBehaviour() {
1041     tfel::raise_if(!this->type.empty(),
1042                    "BehaviourDescription::declareAsGenericBehaviour: "
1043                    "behaviour type has already been defined");
1044     this->type = GENERALBEHAVIOUR;
1045   }  // end of BehaviourDescription::declareAsGenericBehaviour
1046 
declareAsASmallStrainStandardBehaviour()1047   void BehaviourDescription::declareAsASmallStrainStandardBehaviour() {
1048     constexpr const auto h = ModellingHypothesis::UNDEFINEDHYPOTHESIS;
1049     tfel::raise_if(
1050         !this->type.empty(),
1051         "BehaviourDescription::declareAsASmallStrainStandardBehaviour: "
1052         "behaviour type has already been defined");
1053     tfel::raise_if(
1054         !this->mvariables.empty(),
1055         "BehaviourDescription::declareAsASmallStrainStandardBehaviour: "
1056         "some driving variables are already declared");
1057     Gradient eto("StrainStensor", "\u03B5\u1D57\u1D52", "eto");
1058     Gradient::setIsIncrementKnownAttribute(eto, true);
1059     eto.setGlossaryName("Strain");
1060     ThermodynamicForce sig("StressStensor", "\u03C3", "sig");
1061     sig.setGlossaryName("Stress");
1062     this->mvariables.push_back({eto, sig});
1063     this->type = BehaviourDescription::STANDARDSTRAINBASEDBEHAVIOUR;
1064     this->registerMemberName(h, "eto");
1065     this->registerMemberName(h, "deto");
1066     this->registerMemberName(h, "sig");
1067     this->registerGlossaryName(h, "eto", "Strain");
1068     this->registerGlossaryName(h, "sig", "Stress");
1069   }  // end of BehaviourDescription::declareAsASmallStrainStandardBehaviour
1070 
declareAsAFiniteStrainStandardBehaviour(const bool b)1071   void BehaviourDescription::declareAsAFiniteStrainStandardBehaviour(
1072       const bool b) {
1073     constexpr const auto h = ModellingHypothesis::UNDEFINEDHYPOTHESIS;
1074     tfel::raise_if(
1075         !this->type.empty(),
1076         "BehaviourDescription::declareAsAFiniteStrainStandardBehaviour: "
1077         "behaviour type has already been defined");
1078     tfel::raise_if(
1079         !this->mvariables.empty(),
1080         "BehaviourDescription::declareAsAFiniteStrainStandardBehaviour: "
1081         "some driving variables are already declared");
1082     Gradient F("DeformationGradientTensor", "F");
1083     F.setGlossaryName("DeformationGradient");
1084     Gradient::setIsIncrementKnownAttribute(F, false);
1085     ThermodynamicForce sig("StressStensor", "\u03C3", "sig");
1086     sig.setGlossaryName("Stress");
1087     this->mvariables.push_back({F, sig});
1088     this->type = BehaviourDescription::STANDARDFINITESTRAINBEHAVIOUR;
1089     if (b) {
1090       this->registerMemberName(h, "F");
1091       this->registerMemberName(h, "dF");
1092     }
1093     this->registerMemberName(h, "F0");
1094     this->registerMemberName(h, "F1");
1095     this->registerMemberName(h, "sig");
1096     this->registerGlossaryName(h, "F1", "DeformationGradient");
1097     this->registerGlossaryName(h, "sig", "Stress");
1098   }
1099 
declareAsACohesiveZoneModel()1100   void BehaviourDescription::declareAsACohesiveZoneModel() {
1101     constexpr const auto h = ModellingHypothesis::UNDEFINEDHYPOTHESIS;
1102     tfel::raise_if(!this->type.empty(),
1103                    "BehaviourDescription::declareAsACohesiveZoneModel: "
1104                    "behaviour type has already been defined");
1105     tfel::raise_if(!this->mvariables.empty(),
1106                    "BehaviourDescription::declareAsACohesiveZoneModel: "
1107                    "some driving variables are already declared");
1108     Gradient u("DisplacementTVector", "u");
1109     u.setGlossaryName("OpeningDisplacement");
1110     Gradient::setIsIncrementKnownAttribute(u, true);
1111     ThermodynamicForce t("ForceTVector", "t");
1112     t.setGlossaryName("CohesiveForce");
1113     this->mvariables.push_back({u, t});
1114     this->type = BehaviourDescription::COHESIVEZONEMODEL;
1115     this->registerMemberName(h, "u");
1116     this->registerMemberName(h, "du");
1117     this->registerMemberName(h, "t");
1118     this->registerGlossaryName(h, "u", "OpeningDisplacement");
1119     this->registerGlossaryName(h, "t", "CohesiveForce");
1120   }
1121 
addLocalDataStructure(const LocalDataStructure & lds,const BehaviourData::RegistrationStatus s)1122   void BehaviourDescription::addLocalDataStructure(
1123       const LocalDataStructure& lds,
1124       const BehaviourData::RegistrationStatus s) {
1125     auto structify = [](const std::vector<LocalDataStructure::Variable>& vars) {
1126       auto r = std::string("struct{\n");
1127       for (const auto& v : vars) {
1128         if (v.asize == 1u) {
1129           r += v.type + ' ' + v.name + ";\n";
1130         } else {
1131           r += v.type + ' ' + v.name + "[" + std::to_string(v.asize) + "];\n";
1132         }
1133       }
1134       r += "}";
1135       return r;
1136     };
1137     tfel::raise_if(
1138         !tfel::utilities::CxxTokenizer::isValidIdentifier(lds.name, true),
1139         "BehaviourDSLCommon::addLocalDataStructure: "
1140         "invalid local structure name '" +
1141             lds.name + "'");
1142     const auto mh = lds.getSpecialisedHypotheses();
1143     for (const auto h : mh) {
1144       if (!lds.get(h).empty()) {  // paranoiac checks, this can't occur
1145         this->addLocalVariable(h, {structify(lds.get(h)), lds.name, 1u, 0u}, s);
1146       }
1147     }
1148     const auto v = lds.get(ModellingHypothesis::UNDEFINEDHYPOTHESIS);
1149     if (v.empty()) {
1150       return;
1151     }
1152     auto vd = VariableDescription{structify(v), lds.name, 1u, 0u};
1153     if (!this->areAllMechanicalDataSpecialised()) {
1154       this->d.addLocalVariable(vd, s);
1155     }
1156     for (auto& ld : this->sd) {
1157       if (std::find(mh.begin(), mh.end(), ld.first) == mh.end()) {
1158         ld.second->addLocalVariable(vd, s);
1159       }
1160     }
1161   }
1162 
addMainVariable(const Gradient & g,const ThermodynamicForce & f)1163   void BehaviourDescription::addMainVariable(const Gradient& g,
1164                                              const ThermodynamicForce& f) {
1165     constexpr const auto h = ModellingHypothesis::UNDEFINEDHYPOTHESIS;
1166     tfel::raise_if(
1167         this->getBehaviourType() != BehaviourDescription::GENERALBEHAVIOUR,
1168         "BehaviourDescription::addMainVariables: "
1169         "one can not add a main variable if the behaviour "
1170         "don't have a general behaviour type");
1171     tfel::raise_if(
1172         !this->allowsNewUserDefinedVariables(),
1173         "BehaviourDescription::addMainVariables: "
1174         "new variables are can't be defined after the first code block.");
1175     for (const auto& v : this->mvariables) {
1176       tfel::raise_if(g.name == v.first.name,
1177                      "BehaviourDescription::addMainVariables: "
1178                      "a driving variable '" +
1179                          g.name +
1180                          "' has "
1181                          "already been declared");
1182       tfel::raise_if(f.name == v.second.name,
1183                      "BehaviourDescription::addMainVariables: "
1184                      "a driving variable '" +
1185                          f.name +
1186                          "' has "
1187                          "already been declared");
1188     }
1189     if (Gradient::isIncrementKnown(g)) {
1190       this->registerMemberName(h, g.name);
1191       this->registerMemberName(h, "d" + g.name);
1192     } else {
1193       this->registerMemberName(h, g.name + "0");
1194       this->registerMemberName(h, g.name + "1");
1195     }
1196     if (g.hasGlossaryName()) {
1197       this->registerGlossaryName(h, g.name, g.getExternalName());
1198     }
1199     if (g.hasEntryName()) {
1200       this->registerEntryName(h, g.name, g.getExternalName());
1201     }
1202     this->registerMemberName(h, f.name);
1203     if (f.hasGlossaryName()) {
1204       this->registerGlossaryName(h, f.name, f.getExternalName());
1205     }
1206     if (f.hasEntryName()) {
1207       this->registerEntryName(h, f.name, f.getExternalName());
1208     }
1209     this->registerMemberName(h, this->getTangentOperatorBlockName({f, g}));
1210     this->mvariables.push_back({g, f});
1211   }  // end of BehaviourDescription::addMainVariables
1212 
1213   const std::vector<std::pair<Gradient, ThermodynamicForce>>&
getMainVariables() const1214   BehaviourDescription::getMainVariables() const {
1215     return this->mvariables;
1216   }  // end of BehaviourDescription::getMainVariables
1217 
getGradient(const std::string & n)1218   Gradient& BehaviourDescription::getGradient(const std::string& n) {
1219     using value_type = std::pair<Gradient, ThermodynamicForce>;
1220     const auto p =
1221         std::find_if(this->mvariables.begin(), this->mvariables.end(),
1222                      [&n](const value_type& v) { return v.first.name == n; });
1223     tfel::raise_if(p == this->mvariables.end(),
1224                    "BehaviourDescription::getGradient: "
1225                    "unknown driving variable '" +
1226                        n + "'");
1227     return p->first;
1228   }  // end of BehaviourDescription::getGradient
1229 
getGradient(const std::string & n) const1230   const Gradient& BehaviourDescription::getGradient(
1231       const std::string& n) const {
1232     using value_type = std::pair<Gradient, ThermodynamicForce>;
1233     const auto p =
1234         std::find_if(this->mvariables.begin(), this->mvariables.end(),
1235                      [&n](const value_type& v) { return v.first.name == n; });
1236     tfel::raise_if(p == this->mvariables.end(),
1237                    "BehaviourDescription::getGradient: "
1238                    "unknown driving variable '" +
1239                        n + "'");
1240     return p->first;
1241   }  // end of BehaviourDescription::getGradient
1242 
getThermodynamicForce(const std::string & n)1243   ThermodynamicForce& BehaviourDescription::getThermodynamicForce(
1244       const std::string& n) {
1245     using value_type = std::pair<Gradient, ThermodynamicForce>;
1246     const auto p =
1247         std::find_if(this->mvariables.begin(), this->mvariables.end(),
1248                      [&n](const value_type& v) { return v.second.name == n; });
1249     tfel::raise_if(p == this->mvariables.end(),
1250                    "BehaviourDescription::getGradient: "
1251                    "unknown driving variable '" +
1252                        n + "'");
1253     return p->second;
1254   }  // end of BehaviourDescription::getThermodynamicForce
1255 
getThermodynamicForce(const std::string & n) const1256   const ThermodynamicForce& BehaviourDescription::getThermodynamicForce(
1257       const std::string& n) const {
1258     using value_type = std::pair<Gradient, ThermodynamicForce>;
1259     const auto p =
1260         std::find_if(this->mvariables.begin(), this->mvariables.end(),
1261                      [&n](const value_type& v) { return v.second.name == n; });
1262     tfel::raise_if(p == this->mvariables.end(),
1263                    "BehaviourDescription::getGradient: "
1264                    "unknown driving variable '" +
1265                        n + "'");
1266     return p->second;
1267   }  // end of BehaviourDescription::getThermodynamicForce
1268 
isGradientName(const std::string & n) const1269   bool BehaviourDescription::isGradientName(const std::string& n) const {
1270     for (const auto& v : this->getMainVariables()) {
1271       if (v.first.name == n) {
1272         return true;
1273       }
1274     }
1275     return false;
1276   }  // end of BehaviourDescription::isGradientName
1277 
isGradientIncrementName(const std::string & n) const1278   bool BehaviourDescription::isGradientIncrementName(
1279       const std::string& n) const {
1280     for (const auto& v : this->getMainVariables()) {
1281       const auto& g = v.first;
1282       if ((Gradient::isIncrementKnown(g)) && ("d" + g.name == n)) {
1283         return true;
1284       }
1285     }
1286     return false;
1287   }  // end of BehaviourDescription::isGradientIncrementName
1288 
isThermodynamicForceName(const std::string & n) const1289   bool BehaviourDescription::isThermodynamicForceName(
1290       const std::string& n) const {
1291     for (const auto& v : this->getMainVariables()) {
1292       const auto& tf = v.second;
1293       if (tf.name == n) {
1294         return true;
1295       }
1296     }
1297     return false;
1298   }  // end of BehaviourDescription::isThermodynamicForceName
1299 
1300   std::pair<SupportedTypes::TypeSize, SupportedTypes::TypeSize>
getMainVariablesSize() const1301   BehaviourDescription::getMainVariablesSize() const {
1302     auto ov = SupportedTypes::TypeSize{};
1303     auto of = SupportedTypes::TypeSize{};
1304     for (const auto& v : this->getMainVariables()) {
1305       ov += this->getTypeSize(v.first.type, 1u);
1306       of += this->getTypeSize(v.second.type, 1u);
1307     }
1308     return {ov, of};
1309   }  // end of BehaviourDescription::getMainVariablesSize
1310 
getTangentOperatorBlockName(const std::pair<VariableDescription,VariableDescription> & block) const1311   std::string BehaviourDescription::getTangentOperatorBlockName(
1312       const std::pair<VariableDescription, VariableDescription>& block) const {
1313     const auto& a = block.first;
1314     const auto& b = block.second;
1315     if (this->isGradientName(b.name)) {
1316       if (Gradient::isIncrementKnown(b)) {
1317         return "d" + a.name + "_dd" + b.name;
1318       } else {
1319         return "d" + a.name + "_d" + b.name + "1";
1320       }
1321     }
1322     return "d" + a.name + "_dd" + b.name;
1323   }  // end of BehaviourDescription::getTangentOperatorBlockName
1324 
getTangentOperatorBlockSymbolicName(const std::pair<VariableDescription,VariableDescription> & block) const1325   std::string BehaviourDescription::getTangentOperatorBlockSymbolicName(
1326       const std::pair<VariableDescription, VariableDescription>& block) const {
1327     const auto& a = block.first;
1328     const auto& b = block.second;
1329     const auto tmp = "\u2202" + displayName(a) + "\u2215\u2202";
1330     if ((this->isGradientName(b.name)) && (!Gradient::isIncrementKnown(b))) {
1331       return tmp + displayName(b) + "1";
1332     }
1333     return tmp + "\u0394" + displayName(b);
1334   }  // end of BehaviourDescription::getTangentOperatorBlockSymbolicName
1335 
addTangentOperatorBlock(const std::string & bn)1336   void BehaviourDescription::addTangentOperatorBlock(const std::string& bn) {
1337     tfel::raise_if(
1338         this->getBehaviourType() != BehaviourDescription::GENERALBEHAVIOUR,
1339         "BehaviourDescription::addTangentOperatorBlock: "
1340         "the behaviour must be generic "
1341         "to add a tangent operator block");
1342     // check that the operator blocks exists
1343     const auto b = decomposeAdditionalTangentOperatorBlock(*this, bn);
1344     const auto block_name = this->getTangentOperatorBlockName(b);
1345     for (const auto& eb : this->getTangentOperatorBlocks()) {
1346       if (block_name == this->getTangentOperatorBlockName(eb)) {
1347         tfel::raise(
1348             "BehaviourDescription::addTangentOperatorBlock: "
1349             "tangent operator block '" +
1350             bn + "' already defined");
1351       }
1352     }
1353     this->additionalTangentOperatorBlocks.push_back(b);
1354   }  // end of addTangentOperatorBlock
1355 
addTangentOperatorBlocks(const std::vector<std::string> & blocks)1356   void BehaviourDescription::addTangentOperatorBlocks(
1357       const std::vector<std::string>& blocks) {
1358     for (const auto& b : blocks) {
1359       this->addTangentOperatorBlock(b);
1360     }
1361   }  // end of BehaviourDescription::addTangentOperatorBlocks
1362 
setTangentOperatorBlocks(const std::vector<std::string> & blocks)1363   void BehaviourDescription::setTangentOperatorBlocks(
1364       const std::vector<std::string>& blocks) {
1365     if (!this->additionalTangentOperatorBlocks.empty()) {
1366       if (this->useDefaultTangentOperatorBlocks) {
1367         tfel::raise(
1368             "BehaviourDescription::setTangentOperatorBlocks: "
1369             "invalid call, must be called before adding tangent operator "
1370             "blocks");
1371       } else {
1372         tfel::raise(
1373             "BehaviourDescription::setTangentOperatorBlocks: "
1374             "invalid call, this method has already been called");
1375       }
1376     }
1377     if (blocks.empty()) {
1378       tfel::raise(
1379           "BehaviourDescription::setTangentOperatorBlocks: "
1380           "empty list of tangent operator blocks");
1381     }
1382     this->useDefaultTangentOperatorBlocks = false;
1383     for (const auto& b : blocks) {
1384       this->addTangentOperatorBlock(b);
1385     }
1386   }  // end of BehaviourDescription::setTangentOperatorBlocks
1387 
1388   std::vector<std::pair<VariableDescription, VariableDescription>>
getTangentOperatorBlocks() const1389   BehaviourDescription::getTangentOperatorBlocks() const {
1390     auto blocks =
1391         std::vector<std::pair<VariableDescription, VariableDescription>>{};
1392     if (this->useDefaultTangentOperatorBlocks) {
1393       for (const auto& f : this->getMainVariables()) {
1394         for (const auto& g : this->getMainVariables()) {
1395           blocks.push_back({f.second, g.first});
1396         }
1397       }
1398     }
1399     blocks.insert(blocks.end(), this->additionalTangentOperatorBlocks.begin(),
1400                   this->additionalTangentOperatorBlocks.end());
1401     return blocks;
1402   }  // end of BehaviourDescription::getTangentOperatorBlocks
1403 
setThermalExpansionCoefficient(MaterialProperty a)1404   void BehaviourDescription::setThermalExpansionCoefficient(
1405       MaterialProperty a) {
1406     using tfel::glossary::Glossary;
1407     auto throw_if = [](const bool c, const std::string& m) {
1408       tfel::raise_if(
1409           c, "BehaviourDescription::setThermalExpansionCoefficient: " + m);
1410     };
1411     throw_if(!this->allowsNewUserDefinedVariables(),
1412              "new variables are can't be defined after the first code block.");
1413     tfel::raise_if(this->areThermalExpansionCoefficientsDefined(),
1414                    "BehaviourDescription::setThermalExpansionCoefficient: "
1415                    "thermal expansion coefficient already defined");
1416     this->setAttribute(
1417         ModellingHypothesis::UNDEFINEDHYPOTHESIS,
1418         BehaviourDescription::requiresThermalExpansionCoefficientTensor, false);
1419     checkThermalExpansionCoefficientArgument(
1420         *this, a, Glossary::ThermalExpansion, "alpha");
1421     this->thermalExpansionCoefficients.push_back(a);
1422   }  // end of BehaviourDescription::setThermalExpansionCoefficient
1423 
setThermalExpansionCoefficients(MaterialProperty a1,MaterialProperty a2,MaterialProperty a3)1424   void BehaviourDescription::setThermalExpansionCoefficients(
1425       MaterialProperty a1, MaterialProperty a2, MaterialProperty a3) {
1426     using tfel::glossary::Glossary;
1427     auto throw_if = [](const bool c, const std::string& m) {
1428       tfel::raise_if(
1429           c, "BehaviourDescription::setThermalExpansionCoefficients: " + m);
1430     };
1431     throw_if(!this->allowsNewUserDefinedVariables(),
1432              "new variables are can't be defined after the first code block.");
1433     throw_if(this->areThermalExpansionCoefficientsDefined(),
1434              "thermal expansion coefficient already defined");
1435     throw_if(this->getSymmetryType() != mfront::ORTHOTROPIC,
1436              "the behaviour is not orthotropic.");
1437     this->setAttribute(
1438         ModellingHypothesis::UNDEFINEDHYPOTHESIS,
1439         BehaviourDescription::requiresThermalExpansionCoefficientTensor, false);
1440     checkThermalExpansionCoefficientArgument(
1441         *this, a1, Glossary::ThermalExpansion1, "alpha1");
1442     checkThermalExpansionCoefficientArgument(
1443         *this, a2, Glossary::ThermalExpansion2, "alpha2");
1444     checkThermalExpansionCoefficientArgument(
1445         *this, a3, Glossary::ThermalExpansion3, "alpha3");
1446     this->thermalExpansionCoefficients.push_back(a1);
1447     this->thermalExpansionCoefficients.push_back(a2);
1448     this->thermalExpansionCoefficients.push_back(a3);
1449   }  // end of BehaviourDescription::setThermalExpansionCoefficients
1450 
addStressFreeExpansion(const Hypothesis h,const StressFreeExpansionDescription & sfed)1451   void BehaviourDescription::addStressFreeExpansion(
1452       const Hypothesis h, const StressFreeExpansionDescription& sfed) {
1453     auto throw_if = [](const bool c, const std::string& m) {
1454       tfel::raise_if(c, "BehaviourDescription::addStressFreeExpansion: " + m);
1455     };
1456     throw_if(!this->allowsNewUserDefinedVariables(),
1457              "new variables are can't be defined after the first code block.");
1458     if ((sfed.is<BehaviourData::AxialGrowth>()) ||
1459         (sfed.is<BehaviourData::OrthotropicStressFreeExpansion>()) ||
1460         (sfed.is<BehaviourData::OrthotropicStressFreeExpansionII>())) {
1461       throw_if((this->getBehaviourType() !=
1462                 BehaviourDescription::STANDARDSTRAINBASEDBEHAVIOUR) &&
1463                    (this->getBehaviourType() !=
1464                     BehaviourDescription::STANDARDFINITESTRAINBEHAVIOUR),
1465                "AxialGrowth or OrthotropicStressFreeExpansion "
1466                "are only valid for small or "
1467                "finite strain behaviours");
1468       throw_if(this->getSymmetryType() != mfront::ORTHOTROPIC,
1469                "axial growth is only valid for orthotropic behaviour");
1470     } else {
1471       throw_if((!sfed.is<BehaviourData::VolumeSwellingStressFreeExpansion>()) &&
1472                    (!sfed.is<BehaviourData::Relocation>()) &&
1473                    (!sfed.is<BehaviourData::IsotropicStressFreeExpansion>()),
1474                "internal error, unsupported stress free expansion type");
1475       throw_if((this->getBehaviourType() !=
1476                 BehaviourDescription::STANDARDSTRAINBASEDBEHAVIOUR) &&
1477                    (this->getBehaviourType() !=
1478                     BehaviourDescription::STANDARDFINITESTRAINBEHAVIOUR),
1479                "Isotropic, Relocation or VolumeSwelling "
1480                "are only valid for small or "
1481                "finite strain behaviours");
1482     }
1483     if (h == ModellingHypothesis::UNDEFINEDHYPOTHESIS) {
1484       this->d.addStressFreeExpansion(sfed);
1485       for (auto& md : this->sd) {
1486         md.second->addStressFreeExpansion(sfed);
1487       }
1488     } else {
1489       this->getBehaviourData2(h).addStressFreeExpansion(sfed);
1490     }
1491   }  // end of BehaviourDescription::addStressFreeExpansion
1492 
requiresStressFreeExpansionTreatment(const Hypothesis h) const1493   bool BehaviourDescription::requiresStressFreeExpansionTreatment(
1494       const Hypothesis h) const {
1495     return ((this->areThermalExpansionCoefficientsDefined()) ||
1496             (!this->getBehaviourData(h)
1497                   .getStressFreeExpansionDescriptions()
1498                   .empty()) ||
1499             (this->hasCode(h, BehaviourData::ComputeStressFreeExpansion)));
1500   }  // end of BehaviourDescription::requiresStressFreeExpansionTreatment
1501 
areThermalExpansionCoefficientsDefined() const1502   bool BehaviourDescription::areThermalExpansionCoefficientsDefined() const {
1503     return !this->thermalExpansionCoefficients.empty();
1504   }  // end of BehaviourDescription::areThermalExpansionCoefficientsDefined
1505 
1506   const std::vector<BehaviourDescription::MaterialProperty>&
getThermalExpansionCoefficients() const1507   BehaviourDescription::getThermalExpansionCoefficients() const {
1508     tfel::raise_if(!this->areThermalExpansionCoefficientsDefined(),
1509                    "BehaviourDescription::getThermalExpansionCoefficients: "
1510                    "no thermal expansion coefficients defined");
1511     return this->thermalExpansionCoefficients;
1512   }
1513 
setSlipSystems(const std::vector<SlipSystem> & ss)1514   void BehaviourDescription::setSlipSystems(const std::vector<SlipSystem>& ss) {
1515     auto throw_if = [](const bool c, const std::string& m) {
1516       tfel::raise_if(c, "BehaviourDescription::setSlipSystems: " + m);
1517     };
1518     const auto uh = ModellingHypothesis::UNDEFINEDHYPOTHESIS;
1519     throw_if(!this->allowsNewUserDefinedVariables(),
1520              "new variables are can't be defined after the first code block.");
1521     throw_if(ss.empty(), "empty number of slip systems specified");
1522     throw_if(this->getSymmetryType() != mfront::ORTHOTROPIC,
1523              "the behaviour is not orthotropic");
1524     throw_if(this->getSymmetryType() != mfront::ORTHOTROPIC,
1525              "the behaviour is not orthotropic");
1526     throw_if(!this->hasCrystalStructure(),
1527              "crystal structure is not defined yet");
1528     for (const auto& s : ss) {
1529       auto& ssd = this->gs.get<SlipSystemsDescription>();
1530       const auto nb = ssd.getNumberOfSlipSystemsFamilies();
1531       if (s.is<SlipSystemsDescription::system3d>()) {
1532         const auto& s3d = s.get<SlipSystemsDescription::system3d>();
1533         ssd.addSlipSystemsFamily(s3d.burgers, s3d.plane);
1534       } else {
1535         throw_if(!s.is<SlipSystemsDescription::system4d>(),
1536                  "internal error (unsupported slip system definition)");
1537         const auto& s4d = s.get<SlipSystemsDescription::system4d>();
1538         ssd.addSlipSystemsFamily(s4d.burgers, s4d.plane);
1539       }
1540       const auto css = ssd.getSlipSystems(nb);
1541       StaticVariableDescription v("int", "Nss" + std::to_string(nb), 0u,
1542                                   static_cast<int>(css.size()));
1543       this->addStaticVariable(uh, v, BehaviourData::UNREGISTRED);
1544     }
1545     const auto& ssd = this->gs.get<SlipSystemsDescription>();
1546     auto n = int{};
1547     for (SlipSystemsDescription::size_type i = 0;
1548          i != ssd.getNumberOfSlipSystemsFamilies(); ++i) {
1549       const auto css = ssd.getSlipSystems(i);
1550       n += static_cast<int>(css.size());
1551     }
1552     StaticVariableDescription v("int", "Nss", 0u, n);
1553     this->addStaticVariable(uh, v, BehaviourData::UNREGISTRED);
1554   }
1555 
areSlipSystemsDefined() const1556   bool BehaviourDescription::areSlipSystemsDefined() const {
1557     if (this->gs.empty()) {
1558       return false;
1559     }
1560     auto& ssd = this->gs.get<SlipSystemsDescription>();
1561     return ssd.getNumberOfSlipSystemsFamilies() != 0;
1562   }  // end of BehaviourDescription::areSlipSystemsDefined
1563 
1564   const tfel::material::SlipSystemsDescription&
getSlipSystems() const1565   BehaviourDescription::getSlipSystems() const {
1566     tfel::raise_if(!this->areSlipSystemsDefined(),
1567                    "BehaviourDescription::getSlipSystems: "
1568                    "no slip systems defined");
1569     return this->gs;
1570   }  // end of BehaviourDescription::getSlipSystems
1571 
1572   BehaviourDescription::InteractionMatrixStructure
getInteractionMatrixStructure() const1573   BehaviourDescription::getInteractionMatrixStructure() const {
1574     tfel::raise_if(!this->areSlipSystemsDefined(),
1575                    "BehaviourDescription::getInteractionMatrixStructure: "
1576                    "no slip system defined");
1577     return this->gs.get<SlipSystemsDescription>()
1578         .getInteractionMatrixStructure();
1579   }  // end of BehaviourDescription::getInteractionMatrix
1580 
hasInteractionMatrix() const1581   bool BehaviourDescription::hasInteractionMatrix() const {
1582     if (!this->gs.is<SlipSystemsDescription>()) {
1583       return false;
1584     }
1585     return this->gs.get<SlipSystemsDescription>().hasInteractionMatrix();
1586   }  // end of BehaviourDescription::hasInteractionMatrix
1587 
setInteractionMatrix(const std::vector<long double> & m)1588   void BehaviourDescription::setInteractionMatrix(
1589       const std::vector<long double>& m) {
1590     auto throw_if = [](const bool c, const std::string& msg) {
1591       tfel::raise_if(c, "BehaviourDescription::setInteractionMatrix: " + msg);
1592     };
1593     throw_if(!this->allowsNewUserDefinedVariables(),
1594              "new variables are can't be defined after the first code block.");
1595     throw_if(!this->areSlipSystemsDefined(), "no slip system defined");
1596     this->gs.get<SlipSystemsDescription>().setInteractionMatrix(m);
1597   }  // end of BehaviourDescription::setInteractionMatrix
1598 
hasDislocationsMeanFreePathInteractionMatrix() const1599   bool BehaviourDescription::hasDislocationsMeanFreePathInteractionMatrix()
1600       const {
1601     if (!this->gs.is<SlipSystemsDescription>()) {
1602       return false;
1603     }
1604     return this->gs.get<SlipSystemsDescription>()
1605         .hasDislocationsMeanFreePathInteractionMatrix();
1606   }  // end of
1607      // BehaviourDescription::hasDislocationsMeanFreePathInteractionMatrix
1608 
setDislocationsMeanFreePathInteractionMatrix(const std::vector<long double> & m)1609   void BehaviourDescription::setDislocationsMeanFreePathInteractionMatrix(
1610       const std::vector<long double>& m) {
1611     auto throw_if = [](const bool c, const std::string& msg) {
1612       tfel::raise_if(c,
1613                      "BehaviourDescription::"
1614                      "setDislocationsMeanFreePathInteractionMatrix: " +
1615                          msg);
1616     };
1617     throw_if(!this->allowsNewUserDefinedVariables(),
1618              "new variables are can't be defined after the first code block.");
1619     throw_if(!this->areSlipSystemsDefined(), "no slip system defined");
1620     this->gs.get<SlipSystemsDescription>()
1621         .setDislocationsMeanFreePathInteractionMatrix(m);
1622   }  // end of
1623      // BehaviourDescription::setDislocationsMeanFreePathInteractionMatrix
1624 
setUseQt(const bool b)1625   void BehaviourDescription::setUseQt(const bool b) {
1626     tfel::raise_if(this->use_qt,
1627                    "BehaviourDescription::setUseQt: "
1628                    "setUseQt already called");
1629     this->use_qt = b;
1630   }  // end of BehaviourDescription::setUseQt
1631 
useQt() const1632   bool BehaviourDescription::useQt() const {
1633     return this->use_qt;
1634   }  // end of BehaviourDescription::useQt
1635 
hasTangentOperator() const1636   bool BehaviourDescription::hasTangentOperator() const {
1637     const auto& mvs = this->getMainVariables();
1638     return (!mvs.empty()) || (!this->additionalTangentOperatorBlocks.empty());
1639   }  // end of BehaviourDescription::hasTangentOperator
1640 
hasTrivialTangentOperatorStructure() const1641   bool BehaviourDescription::hasTrivialTangentOperatorStructure() const {
1642     const auto& mvs = this->getMainVariables();
1643     return (mvs.size() == 1) && (mvs.front().first.arraySize == 1u) &&
1644            (mvs.front().second.arraySize == 1u) &&
1645            (this->additionalTangentOperatorBlocks.empty());
1646   }  // end of BehaviourDescription::hasTrivialTangentOperatorStructure
1647 
computeTangentOperatorSize() const1648   std::string BehaviourDescription::computeTangentOperatorSize() const {
1649     const auto& blocks = this->getTangentOperatorBlocks();
1650     if (blocks.empty()) {
1651       return "0";
1652     }
1653     std::ostringstream t;
1654     auto p = blocks.begin();
1655     const auto pe = blocks.end();
1656     t << "(" << p->first.getTypeSize() << ")"
1657       << "*(" << p->second.getTypeSize() << ")";
1658     ++p;
1659     while (p != pe) {
1660       t << "+"
1661         << "(" << p->first.getTypeSize() << ")"
1662         << "*(" << p->second.getTypeSize() << ")";
1663       ++p;
1664     }
1665     return t.str();
1666   }  // end of BehaviourDescription::computeTangentOperatorSize
1667 
getTangentOperatorType() const1668   std::string BehaviourDescription::getTangentOperatorType() const {
1669     if (this->getBehaviourType() == GENERALBEHAVIOUR) {
1670       const auto& mvs = this->getMainVariables();
1671       if (this->hasTrivialTangentOperatorStructure()) {
1672         const auto& mv = mvs.front();
1673         const auto gflags = mv.first.getTypeFlag();
1674         const auto fflags = mv.second.getTypeFlag();
1675         auto throw_unmatch = [&mv] {
1676           tfel::raise(
1677               "BehaviourDescription::getTangentOperatorType: "
1678               "gradient '" +
1679               mv.first.name + "' is not conjugated with flux '" +
1680               mv.second.name + "'");
1681         };
1682         if (gflags == SupportedTypes::SCALAR) {
1683           if (fflags != SupportedTypes::SCALAR) {
1684             throw_unmatch();
1685           }
1686           return "real";
1687         } else if (gflags == SupportedTypes::TVECTOR) {
1688           if (fflags != SupportedTypes::TVECTOR) {
1689             throw_unmatch();
1690           }
1691           return "tfel::math::tmatrix<N,N,real>";
1692         } else if (gflags == SupportedTypes::STENSOR) {
1693           if (fflags != SupportedTypes::STENSOR) {
1694             throw_unmatch();
1695           }
1696           return "tfel::math::st2tost2<N,real>";
1697         } else if (gflags == SupportedTypes::TENSOR) {
1698           if (fflags == SupportedTypes::STENSOR) {
1699             return "tfel::math::t2tost2<N,real>";
1700           } else if (fflags == SupportedTypes::TENSOR) {
1701             return "tfel::math::t2tot2<N,real>";
1702           } else {
1703             throw_unmatch();
1704           }
1705         } else {
1706           tfel::raise(
1707               "BehaviourDescription::getTangentOperatorType: "
1708               "unsupported type for gradient '" +
1709               mv.first.name + "'");
1710         }
1711       }
1712       return "tfel::math::tvector<" + this->computeTangentOperatorSize() +
1713              ",real>";
1714     } else if (this->getBehaviourType() == STANDARDSTRAINBASEDBEHAVIOUR) {
1715       return "StiffnessTensor";
1716     } else if (this->getBehaviourType() == STANDARDFINITESTRAINBEHAVIOUR) {
1717       return "FiniteStrainBehaviourTangentOperator<N,stress>";
1718     } else if (this->getBehaviourType() == COHESIVEZONEMODEL) {
1719       return "tfel::math::tmatrix<N,N,stress>";
1720     }
1721     tfel::raise(
1722         "BehaviourDescription::getStiffnessOperatorType: "
1723         "internal error (unsupported behaviour type)");
1724   }  // end of BehaviourDescription::getStiffnessOperatorType
1725 
1726   const std::vector<BehaviourData::StressFreeExpansionDescription>&
getStressFreeExpansionDescriptions(const Hypothesis h) const1727   BehaviourDescription::getStressFreeExpansionDescriptions(
1728       const Hypothesis h) const {
1729     return this->getBehaviourData(h).getStressFreeExpansionDescriptions();
1730   }  // end of BehaviourDescription::getStressFreeExpansionDescriptions
1731 
getStressFreeExpansionType() const1732   std::string BehaviourDescription::getStressFreeExpansionType() const {
1733     if ((this->getBehaviourType() == STANDARDSTRAINBASEDBEHAVIOUR) ||
1734         (this->getBehaviourType() == STANDARDFINITESTRAINBEHAVIOUR)) {
1735       return "StrainStensor";
1736     }
1737     tfel::raise(
1738         "BehaviourDescription::getStressFreeExpansionType: "
1739         "internal error (unsupported behaviour type)");
1740   }  // end of BehaviourDescription::getStressFreeExpansionType
1741 
isStressFreeExansionAnisotropic(const Hypothesis h) const1742   bool BehaviourDescription::isStressFreeExansionAnisotropic(
1743       const Hypothesis h) const {
1744     return this->getBehaviourData(h).isStressFreeExansionAnisotropic();
1745   }  // end of BehaviourDescription::isStressFreeExansionAnisotropic
1746 
checkModellingHypothesis(const Hypothesis h) const1747   void BehaviourDescription::checkModellingHypothesis(
1748       const Hypothesis h) const {
1749     if (this->getModellingHypotheses().find(h) ==
1750         this->getModellingHypotheses().end()) {
1751       std::ostringstream msg;
1752       msg << "BehaviourDescription::checkModellingHypothesis: "
1753           << "modelling hypothesis '" << ModellingHypothesis::toString(h)
1754           << "' is not supported. Refer to the documentation of "
1755           << "the '@ModellingHypothesis' or "
1756           << "the '@ModellingHypotheses' keywords for details.\n";
1757       msg << "Supported modelling hypotheses are :";
1758       for (const auto& lh : this->hypotheses) {
1759         msg << "\n- '" << ModellingHypothesis::toString(lh) << "'";
1760       }
1761       tfel::raise(msg.str());
1762     }
1763   }  // end of BehaviourDescription::checkModellingHypothesis
1764 
areModellingHypothesesDefined() const1765   bool BehaviourDescription::areModellingHypothesesDefined() const {
1766     return !this->hypotheses.empty();
1767   }  // end of BehaviourDescription::areModellingHypothesesDefined
1768 
1769   const std::set<BehaviourDescription::Hypothesis>&
getModellingHypotheses() const1770   BehaviourDescription::getModellingHypotheses() const {
1771     tfel::raise_if(this->hypotheses.empty(),
1772                    "BehaviourDescription::getModellingHypotheses: "
1773                    "hypothesis undefined yet");
1774     return this->hypotheses;
1775   }  // end of BehaviourDescription::getModellingHypotheses
1776 
1777   std::set<BehaviourDescription::Hypothesis>
getDistinctModellingHypotheses() const1778   BehaviourDescription::getDistinctModellingHypotheses() const {
1779     const auto& mh = this->getModellingHypotheses();
1780     if (mh.size() == 1u) {
1781       // if only one modelling hypothesis is supported, it is not
1782       // considered as specialised, so we return it.
1783       return mh;
1784     }
1785     std::set<Hypothesis> dh;
1786     if (!this->areAllMechanicalDataSpecialised()) {
1787       // We return UNDEFINEDHYPOTHESIS to take into account all the
1788       // modelling hypotheses that were not specialised
1789       dh.insert(ModellingHypothesis::UNDEFINEDHYPOTHESIS);
1790     }
1791     for (const auto& h : mh) {
1792       if (this->hasSpecialisedMechanicalData(h)) {
1793         dh.insert(h);
1794       }
1795     }
1796     return dh;
1797   }  // end of BehaviourDescription::getDistinctModellingHypotheses
1798 
isModellingHypothesisSupported(const Hypothesis h) const1799   bool BehaviourDescription::isModellingHypothesisSupported(
1800       const Hypothesis h) const {
1801     return this->getModellingHypotheses().count(h) != 0u;
1802   }
1803 
setModellingHypotheses(const std::set<Hypothesis> & mh,const bool b)1804   void BehaviourDescription::setModellingHypotheses(
1805       const std::set<Hypothesis>& mh, const bool b) {
1806     constexpr const auto uh = ModellingHypothesis::UNDEFINEDHYPOTHESIS;
1807     auto throw_if = [](const bool c, const std::string& m) {
1808       tfel::raise_if(c, "BehaviourDescription::setHypotheses: " + m);
1809     };
1810     // never ever trust a user
1811     throw_if(mh.empty(), "empty set of modelling hypotheses specificied");
1812     // never ever trust a user
1813     throw_if(mh.find(uh) != mh.end(),
1814              "undefined modelling hypothesis specified");
1815     // check that the user did not already set the modelling hypotheses
1816     throw_if(!this->hypotheses.empty(),
1817              "supported modelling hypotheses have already been declared");
1818     // check that if a specialised version of the behaviour
1819     // is defined, it is present in the set of hypotheses defined here
1820     for (const auto& ld : this->sd) {
1821       throw_if(mh.find(ld.first) == mh.end(),
1822                "partial specialisation of the behaviour exists for "
1823                "the hypothesis '" +
1824                    ModellingHypothesis::toString(ld.first) +
1825                    "' "
1826                    "which is not in the set of hypotheses which have to be "
1827                    "supported by the behaviour.");
1828     }
1829     for (const auto h : this->requestedHypotheses) {
1830       throw_if(mh.find(h) == mh.end(),
1831                "a description of the behaviour for "
1832                "the hypothesis '" +
1833                    ModellingHypothesis::toString(h) +
1834                    "' "
1835                    "has been requested earlier, but this hypothesis is not "
1836                    "in the set of hypotheses which will to be "
1837                    "supported by the behaviour. This may lead to "
1838                    "inconsistencies. "
1839                    "Cowardly aborting.");
1840     }
1841     if (this->hypotheses.empty()) {
1842       if ((this->stypeIsDefined) &&
1843           (this->getSymmetryType() == mfront::ORTHOTROPIC) &&
1844           (this->oacIsDefined) && (this->getOrthotropicAxesConvention() ==
1845                                    OrthotropicAxesConvention::PLATE)) {
1846         for (const auto h : mh) {
1847           throw_if((h != ModellingHypothesis::TRIDIMENSIONAL) &&
1848                        (h != ModellingHypothesis::PLANESTRESS) &&
1849                        (h != ModellingHypothesis::PLANESTRAIN) &&
1850                        (h != ModellingHypothesis::GENERALISEDPLANESTRAIN),
1851                    "Modelling hypothesis '" + ModellingHypothesis::toString(h) +
1852                        "' is not compatible "
1853                        "with the `Plate` orthotropic axes convention");
1854         }
1855       }
1856       this->hypotheses.insert(mh.begin(), mh.end());
1857     } else {
1858       if (b) {
1859         // find the intersection of the given hypotheses and the
1860         // existing one
1861         std::set<Hypothesis> nh;
1862         for (const auto h : this->hypotheses) {
1863           if (mh.find(h) != mh.end()) {
1864             nh.insert(h);
1865           }
1866         }
1867         throw_if(nh.empty(),
1868                  "intersection of previously modelling hypotheses "
1869                  "with the new ones is empty");
1870         // as this is the intersection with previously defined
1871         // hyppotheses, restrictions related to the orthotropic axes
1872         // conditions does not have to be checked.
1873         this->hypotheses.swap(nh);
1874       } else {
1875         throw_if(true,
1876                  "supported modelling hypotheses have already been declared");
1877       }
1878     }
1879   }  // end of BehaviourDescription::setModellingHypotheses
1880 
1881   const std::vector<ModelDescription>&
getModelsDescriptions() const1882   BehaviourDescription::getModelsDescriptions() const {
1883     return this->models;
1884   }  // end of BehaviourDescription::getModelsDescriptions
1885 
addModelDescription(const ModelDescription & md)1886   void BehaviourDescription::addModelDescription(const ModelDescription& md) {
1887     constexpr const auto uh = ModellingHypothesis::UNDEFINEDHYPOTHESIS;
1888     for (auto ov : md.outputs) {
1889       VariableDescription dov{ov.type, "d" + ov.name, ov.arraySize,
1890                               ov.lineNumber};
1891       ov.setAttribute("ComputedByExternalModel", true, false);
1892       this->addAuxiliaryStateVariable(uh, ov, BehaviourData::UNREGISTRED);
1893       this->addLocalVariable(uh, dov, BehaviourData::UNREGISTRED);
1894     }
1895     this->models.push_back(md);
1896   }  // end of BehaviourDescription::addModelDescription
1897 
addMaterialProperties(const Hypothesis h,const VariableDescriptionContainer & v,const BehaviourData::RegistrationStatus s)1898   void BehaviourDescription::addMaterialProperties(
1899       const Hypothesis h,
1900       const VariableDescriptionContainer& v,
1901       const BehaviourData::RegistrationStatus s) {
1902     using mptr = void (mfront::BehaviourData::*)(
1903         const mfront::VariableDescription&,
1904         const BehaviourData::RegistrationStatus);
1905     mptr f = &BehaviourData::addMaterialProperty;
1906     this->addVariables(h, v, s, f);
1907   }  // end of BehaviourDescription::addMaterialProperties
1908 
addParameters(const Hypothesis h,const VariableDescriptionContainer & v,const BehaviourData::RegistrationStatus s)1909   void BehaviourDescription::addParameters(
1910       const Hypothesis h,
1911       const VariableDescriptionContainer& v,
1912       const BehaviourData::RegistrationStatus s) {
1913     using mptr = void (mfront::BehaviourData::*)(
1914         const mfront::VariableDescription&,
1915         const BehaviourData::RegistrationStatus);
1916     mptr f = &BehaviourData::addParameter;
1917     this->addVariables(h, v, s, f);
1918   }  // end of BehaviourDescription::addParameters
1919 
addMaterialProperty(const Hypothesis h,const VariableDescription & v,const BehaviourData::RegistrationStatus s)1920   void BehaviourDescription::addMaterialProperty(
1921       const Hypothesis h,
1922       const VariableDescription& v,
1923       const BehaviourData::RegistrationStatus s) {
1924     using mptr = void (mfront::BehaviourData::*)(
1925         const mfront::VariableDescription&,
1926         const BehaviourData::RegistrationStatus);
1927     mptr f = &BehaviourData::addMaterialProperty;
1928     this->addVariable(h, v, s, f);
1929   }
1930 
addIntegrationVariables(const Hypothesis h,const VariableDescriptionContainer & v,const BehaviourData::RegistrationStatus s)1931   void BehaviourDescription::addIntegrationVariables(
1932       const Hypothesis h,
1933       const VariableDescriptionContainer& v,
1934       const BehaviourData::RegistrationStatus s) {
1935     using mptr = void (mfront::BehaviourData::*)(
1936         const mfront::VariableDescription&,
1937         const BehaviourData::RegistrationStatus);
1938     mptr f = &BehaviourData::addIntegrationVariable;
1939     this->addVariables(h, v, s, f);
1940   }
1941 
addStateVariables(const Hypothesis h,const VariableDescriptionContainer & v,const BehaviourData::RegistrationStatus s)1942   void BehaviourDescription::addStateVariables(
1943       const Hypothesis h,
1944       const VariableDescriptionContainer& v,
1945       const BehaviourData::RegistrationStatus s) {
1946     using mptr = void (mfront::BehaviourData::*)(
1947         const mfront::VariableDescription&,
1948         const BehaviourData::RegistrationStatus);
1949     mptr f = &BehaviourData::addStateVariable;
1950     this->addVariables(h, v, s, f);
1951   }
1952 
addIntegrationVariable(const Hypothesis h,const VariableDescription & v,const BehaviourData::RegistrationStatus s)1953   void BehaviourDescription::addIntegrationVariable(
1954       const Hypothesis h,
1955       const VariableDescription& v,
1956       const BehaviourData::RegistrationStatus s) {
1957     using mptr = void (mfront::BehaviourData::*)(
1958         const mfront::VariableDescription&,
1959         const BehaviourData::RegistrationStatus);
1960     mptr f = &BehaviourData::addIntegrationVariable;
1961     this->addVariable(h, v, s, f);
1962   }
1963 
addStateVariable(const Hypothesis h,const VariableDescription & v,const BehaviourData::RegistrationStatus s)1964   void BehaviourDescription::addStateVariable(
1965       const Hypothesis h,
1966       const VariableDescription& v,
1967       const BehaviourData::RegistrationStatus s) {
1968     using mptr = void (mfront::BehaviourData::*)(
1969         const mfront::VariableDescription&,
1970         const BehaviourData::RegistrationStatus);
1971     mptr f = &BehaviourData::addStateVariable;
1972     this->addVariable(h, v, s, f);
1973   }
1974 
addAuxiliaryStateVariables(const Hypothesis h,const VariableDescriptionContainer & v,const BehaviourData::RegistrationStatus s)1975   void BehaviourDescription::addAuxiliaryStateVariables(
1976       const Hypothesis h,
1977       const VariableDescriptionContainer& v,
1978       const BehaviourData::RegistrationStatus s) {
1979     using mptr = void (mfront::BehaviourData::*)(
1980         const mfront::VariableDescription&,
1981         const BehaviourData::RegistrationStatus);
1982     mptr f = &BehaviourData::addAuxiliaryStateVariable;
1983     this->addVariables(h, v, s, f);
1984   }
1985 
addAuxiliaryStateVariable(const Hypothesis h,const VariableDescription & v,const BehaviourData::RegistrationStatus s)1986   void BehaviourDescription::addAuxiliaryStateVariable(
1987       const Hypothesis h,
1988       const VariableDescription& v,
1989       const BehaviourData::RegistrationStatus s) {
1990     using mptr = void (mfront::BehaviourData::*)(
1991         const mfront::VariableDescription&,
1992         const BehaviourData::RegistrationStatus);
1993     mptr f = &BehaviourData::addAuxiliaryStateVariable;
1994     this->addVariable(h, v, s, f);
1995   }
1996 
addExternalStateVariables(const Hypothesis h,const VariableDescriptionContainer & v,const BehaviourData::RegistrationStatus s)1997   void BehaviourDescription::addExternalStateVariables(
1998       const Hypothesis h,
1999       const VariableDescriptionContainer& v,
2000       const BehaviourData::RegistrationStatus s) {
2001     using mptr = void (mfront::BehaviourData::*)(
2002         const mfront::VariableDescription&,
2003         const BehaviourData::RegistrationStatus);
2004     mptr f = &BehaviourData::addExternalStateVariable;
2005     this->addVariables(h, v, s, f);
2006   }
2007 
addExternalStateVariable(const Hypothesis h,const VariableDescription & v,const BehaviourData::RegistrationStatus s)2008   void BehaviourDescription::addExternalStateVariable(
2009       const Hypothesis h,
2010       const VariableDescription& v,
2011       const BehaviourData::RegistrationStatus s) {
2012     using mptr = void (mfront::BehaviourData::*)(
2013         const mfront::VariableDescription&,
2014         const BehaviourData::RegistrationStatus);
2015     mptr f = &BehaviourData::addExternalStateVariable;
2016     this->addVariable(h, v, s, f);
2017   }
2018 
addLocalVariables(const Hypothesis h,const VariableDescriptionContainer & v,const BehaviourData::RegistrationStatus s)2019   void BehaviourDescription::addLocalVariables(
2020       const Hypothesis h,
2021       const VariableDescriptionContainer& v,
2022       const BehaviourData::RegistrationStatus s) {
2023     using mptr = void (mfront::BehaviourData::*)(
2024         const mfront::VariableDescription&,
2025         const BehaviourData::RegistrationStatus);
2026     mptr f = &BehaviourData::addLocalVariable;
2027     this->addVariables(h, v, s, f);
2028   }
2029 
addLocalVariable(const Hypothesis h,const VariableDescription & v,const BehaviourData::RegistrationStatus s)2030   void BehaviourDescription::addLocalVariable(
2031       const Hypothesis h,
2032       const VariableDescription& v,
2033       const BehaviourData::RegistrationStatus s) {
2034     using mptr = void (mfront::BehaviourData::*)(
2035         const mfront::VariableDescription&,
2036         const BehaviourData::RegistrationStatus);
2037     mptr f = &BehaviourData::addLocalVariable;
2038     this->addVariable(h, v, s, f);
2039   }
2040 
addParameter(const Hypothesis h,const VariableDescription & v,const BehaviourData::RegistrationStatus s)2041   void BehaviourDescription::addParameter(
2042       const Hypothesis h,
2043       const VariableDescription& v,
2044       const BehaviourData::RegistrationStatus s) {
2045     using mptr = void (mfront::BehaviourData::*)(
2046         const mfront::VariableDescription&,
2047         const BehaviourData::RegistrationStatus);
2048     mptr f = &BehaviourData::addParameter;
2049     this->addVariable(h, v, s, f);
2050   }
2051 
setVariableAttribute(const Hypothesis h,const std::string & v,const std::string & n,const VariableAttribute & a,const bool b)2052   void BehaviourDescription::setVariableAttribute(const Hypothesis h,
2053                                                   const std::string& v,
2054                                                   const std::string& n,
2055                                                   const VariableAttribute& a,
2056                                                   const bool b) {
2057     auto set = [&v, &n, &a, b](BehaviourData& bd) {
2058       bd.setVariableAttribute(v, n, a, b);
2059     };
2060     if (h == ModellingHypothesis::UNDEFINEDHYPOTHESIS) {
2061       set(this->d);
2062       for (auto md : this->sd) {
2063         set(*(md.second));
2064       }
2065     } else {
2066       set(this->getBehaviourData2(h));
2067     }
2068   }  // end of BehaviourDescription::setVariableAttribute
2069 
hasGlossaryName(const Hypothesis h,const std::string & v) const2070   bool BehaviourDescription::hasGlossaryName(const Hypothesis h,
2071                                              const std::string& v) const {
2072     return this->getData(h, &BehaviourData::hasGlossaryName, v);
2073   }  // end of BehaviourDescription::hasGlossaryName
2074 
hasEntryName(const Hypothesis h,const std::string & v) const2075   bool BehaviourDescription::hasEntryName(const Hypothesis h,
2076                                           const std::string& v) const {
2077     return this->getData(h, &BehaviourData::hasEntryName, v);
2078   }  // end of BehaviourDescription::hasEntryName
2079 
hasParameter(const Hypothesis h,const std::string & v) const2080   bool BehaviourDescription::hasParameter(const Hypothesis h,
2081                                           const std::string& v) const {
2082     return this->getData(h, &BehaviourData::hasParameter, v);
2083   }  // end of BehaviourDescription::hasParameter
2084 
hasParameters(const Hypothesis h) const2085   bool BehaviourDescription::hasParameters(const Hypothesis h) const {
2086     return this->getBehaviourData(h).hasParameters();
2087   }  // end of BehaviourDescription::hasParameters
2088 
hasParameters() const2089   bool BehaviourDescription::hasParameters() const {
2090     if (this->d.hasParameters()) {
2091       return true;
2092     }
2093     for (const auto& ld : this->sd) {
2094       if (ld.second->hasParameters()) {
2095         return true;
2096       }
2097     }
2098     return false;
2099   }  // end of BehaviourDescription::hasParameters
2100 
setParameterDefaultValue(const Hypothesis h,const std::string & n,const double v)2101   void BehaviourDescription::setParameterDefaultValue(const Hypothesis h,
2102                                                       const std::string& n,
2103                                                       const double v) {
2104     void (BehaviourData::*mptr)(const std::string&, const double);
2105     mptr = &BehaviourData::setParameterDefaultValue;
2106     this->callBehaviourData(h, mptr, n, v, true);
2107   }
2108 
setParameterDefaultValue(const Hypothesis h,const std::string & n,const unsigned short i,const double v)2109   void BehaviourDescription::setParameterDefaultValue(const Hypothesis h,
2110                                                       const std::string& n,
2111                                                       const unsigned short i,
2112                                                       const double v) {
2113     void (BehaviourData::*m)(const std::string&, const unsigned short,
2114                              const double) =
2115         &BehaviourData::setParameterDefaultValue;
2116     if (h == ModellingHypothesis::UNDEFINEDHYPOTHESIS) {
2117       (this->d.*m)(n, i, v);
2118       for (auto md : this->sd) {
2119         (md.second.get()->*m)(n, i, v);
2120       }
2121     } else {
2122       (this->getBehaviourData2(h).*m)(n, i, v);
2123     }
2124   }
2125 
setParameterDefaultValue(const Hypothesis h,const std::string & n,const int v)2126   void BehaviourDescription::setParameterDefaultValue(const Hypothesis h,
2127                                                       const std::string& n,
2128                                                       const int v) {
2129     void (BehaviourData::*mptr)(const std::string&, const int v);
2130     mptr = &BehaviourData::setParameterDefaultValue;
2131     this->callBehaviourData(h, mptr, n, v, true);
2132   }
2133 
setParameterDefaultValue(const Hypothesis h,const std::string & n,const unsigned short v)2134   void BehaviourDescription::setParameterDefaultValue(const Hypothesis h,
2135                                                       const std::string& n,
2136                                                       const unsigned short v) {
2137     void (BehaviourData::*mptr)(const std::string&, const unsigned short v);
2138     mptr = &BehaviourData::setParameterDefaultValue;
2139     this->callBehaviourData(h, mptr, n, v, true);
2140   }
2141 
getUnsignedShortParameterDefaultValue(const Hypothesis h,const std::string & n) const2142   unsigned short BehaviourDescription::getUnsignedShortParameterDefaultValue(
2143       const Hypothesis h, const std::string& n) const {
2144     return this->getData(
2145         h, &BehaviourData::getUnsignedShortParameterDefaultValue, n);
2146   }  // end of BehaviourDescription::getUnsignedShortParameterDefaultValue
2147 
getIntegerParameterDefaultValue(const Hypothesis h,const std::string & n) const2148   int BehaviourDescription::getIntegerParameterDefaultValue(
2149       const Hypothesis h, const std::string& n) const {
2150     return this->getData(h, &BehaviourData::getIntegerParameterDefaultValue, n);
2151   }  // end of BehaviourDescription::getIntegerParameterDefaultValue
2152 
getFloattingPointParameterDefaultValue(const Hypothesis h,const std::string & n) const2153   double BehaviourDescription::getFloattingPointParameterDefaultValue(
2154       const Hypothesis h, const std::string& n) const {
2155     return this->getData(
2156         h, &BehaviourData::getFloattingPointParameterDefaultValue, n);
2157   }  // end of BehaviourDescription::getFloattingPointParameterDefaultValue
2158 
getFloattingPointParameterDefaultValue(const Hypothesis h,const std::string & n,const unsigned short i) const2159   double BehaviourDescription::getFloattingPointParameterDefaultValue(
2160       const Hypothesis h, const std::string& n, const unsigned short i) const {
2161     return this->getBehaviourData(h).getFloattingPointParameterDefaultValue(n,
2162                                                                             i);
2163   }  // end of BehaviourDescription::getFloattingPointParameterDefaultValue
2164 
addStaticVariable(const Hypothesis h,const StaticVariableDescription & v,const BehaviourData::RegistrationStatus s)2165   void BehaviourDescription::addStaticVariable(
2166       const Hypothesis h,
2167       const StaticVariableDescription& v,
2168       const BehaviourData::RegistrationStatus s) {
2169     if (h == ModellingHypothesis::UNDEFINEDHYPOTHESIS) {
2170       this->d.addStaticVariable(v, s);
2171       for (const auto& md : this->sd) {
2172         md.second->addStaticVariable(v, s);
2173       }
2174     } else {
2175       this->getBehaviourData2(h).addStaticVariable(v, s);
2176     }
2177   }  // end of BehaviourDescription::addStaticVariable
2178 
getIntegerConstant(const Hypothesis h,const std::string & n) const2179   int BehaviourDescription::getIntegerConstant(const Hypothesis h,
2180                                                const std::string& n) const {
2181     return this->getData(h, &BehaviourData::getIntegerConstant, n);
2182   }  // end of BehaviourDescription::getIntegerConstant
2183 
addVariables(const Hypothesis h,const VariableDescriptionContainer & v,const BehaviourData::RegistrationStatus s,void (BehaviourData::* m)(const VariableDescription &,const BehaviourData::RegistrationStatus))2184   void BehaviourDescription::addVariables(
2185       const Hypothesis h,
2186       const VariableDescriptionContainer& v,
2187       const BehaviourData::RegistrationStatus s,
2188       void (BehaviourData::*m)(const VariableDescription&,
2189                                const BehaviourData::RegistrationStatus)) {
2190     if (h == ModellingHypothesis::UNDEFINEDHYPOTHESIS) {
2191       this->addVariables(this->d, v, s, m);
2192       for (auto& md : this->sd) {
2193         this->addVariables(*(md.second), v, s, m);
2194       }
2195     } else {
2196       this->addVariables(this->getBehaviourData2(h), v, s, m);
2197     }
2198   }  // end of BehaviourDescription::addVariables
2199 
addVariable(const Hypothesis h,const VariableDescription & v,const BehaviourData::RegistrationStatus s,void (BehaviourData::* m)(const VariableDescription &,const BehaviourData::RegistrationStatus))2200   void BehaviourDescription::addVariable(
2201       const Hypothesis h,
2202       const VariableDescription& v,
2203       const BehaviourData::RegistrationStatus s,
2204       void (BehaviourData::*m)(const VariableDescription&,
2205                                const BehaviourData::RegistrationStatus)) {
2206     if (h == ModellingHypothesis::UNDEFINEDHYPOTHESIS) {
2207       this->addVariable(this->d, v, s, m);
2208       for (auto& md : this->sd) {
2209         this->addVariable(*(md.second), v, s, m);
2210       }
2211     } else {
2212       this->addVariable(this->getBehaviourData2(h), v, s, m);
2213     }
2214   }  // end of BehaviourDescription::addVariable
2215 
addVariables(BehaviourData & b,const VariableDescriptionContainer & v,const BehaviourData::RegistrationStatus s,void (BehaviourData::* m)(const VariableDescription &,const BehaviourData::RegistrationStatus))2216   void BehaviourDescription::addVariables(
2217       BehaviourData& b,
2218       const VariableDescriptionContainer& v,
2219       const BehaviourData::RegistrationStatus s,
2220       void (BehaviourData::*m)(const VariableDescription&,
2221                                const BehaviourData::RegistrationStatus)) {
2222     for (const auto& e : v) {
2223       this->addVariable(b, e, s, m);
2224     }
2225   }  // end of BehaviourDescription::addVariables
2226 
addVariable(BehaviourData & b,const VariableDescription & v,const BehaviourData::RegistrationStatus s,void (BehaviourData::* m)(const VariableDescription &,const BehaviourData::RegistrationStatus))2227   void BehaviourDescription::addVariable(
2228       BehaviourData& b,
2229       const VariableDescription& v,
2230       const BehaviourData::RegistrationStatus s,
2231       void (BehaviourData::*m)(const VariableDescription&,
2232                                const BehaviourData::RegistrationStatus)) {
2233     (b.*m)(v, s);
2234   }
2235 
areAllMechanicalDataSpecialised() const2236   bool BehaviourDescription::areAllMechanicalDataSpecialised() const {
2237     return this->getModellingHypotheses().size() == this->sd.size();
2238   }  // end of BehaviourDescription::areAllMechanicalDataSpecialised
2239 
areAllMechanicalDataSpecialised(const std::set<Hypothesis> & h) const2240   bool BehaviourDescription::areAllMechanicalDataSpecialised(
2241       const std::set<Hypothesis>& h) const {
2242     for (const auto& mh : h) {
2243       if (!this->hasSpecialisedMechanicalData(mh)) {
2244         return false;
2245       }
2246     }
2247     return true;
2248   }  // end of BehaviourDescription::areAllMechanicalDataSpecialised
2249 
hasSpecialisedMechanicalData(const Hypothesis h) const2250   bool BehaviourDescription::hasSpecialisedMechanicalData(
2251       const Hypothesis h) const {
2252     tfel::raise_if(this->getModellingHypotheses().find(h) ==
2253                        this->getModellingHypotheses().end(),
2254                    "BehaviourDescription::areAllMechanicalDataSpecialised: "
2255                    "hypothesis '" +
2256                        ModellingHypothesis::toString(h) + "' is not supported");
2257     return this->sd.find(h) != this->sd.end();
2258   }
2259 
requiresTVectorOrVectorIncludes(bool & b1,bool & b2,const BehaviourData & bd) const2260   void BehaviourDescription::requiresTVectorOrVectorIncludes(
2261       bool& b1, bool& b2, const BehaviourData& bd) const {
2262     for (const auto& v : bd.getMaterialProperties()) {
2263       if (v.arraySize > 1) {
2264         if (this->useDynamicallyAllocatedVector(v.arraySize)) {
2265           b2 = true;
2266         } else {
2267           b1 = true;
2268         }
2269       }
2270       if (b1 && b2) {
2271         return;
2272       }
2273     }
2274     for (const auto& v : bd.getIntegrationVariables()) {
2275       if (v.arraySize > 1) {
2276         if (this->useDynamicallyAllocatedVector(v.arraySize)) {
2277           b2 = true;
2278         } else {
2279           b1 = true;
2280         }
2281       }
2282       if (b1 && b2) {
2283         return;
2284       }
2285     }
2286     for (const auto& v : bd.getStateVariables()) {
2287       if (v.arraySize > 1) {
2288         if (this->useDynamicallyAllocatedVector(v.arraySize)) {
2289           b2 = true;
2290         } else {
2291           b1 = true;
2292         }
2293       }
2294       if (b1 && b2) {
2295         return;
2296       }
2297     }
2298     for (const auto& v : bd.getAuxiliaryStateVariables()) {
2299       if (v.arraySize > 1) {
2300         if (this->useDynamicallyAllocatedVector(v.arraySize)) {
2301           b2 = true;
2302         } else {
2303           b1 = true;
2304         }
2305       }
2306       if (b1 && b2) {
2307         return;
2308       }
2309     }
2310     for (const auto& v : bd.getLocalVariables()) {
2311       if (v.arraySize > 1) {
2312         if (this->useDynamicallyAllocatedVector(v.arraySize)) {
2313           b2 = true;
2314         } else {
2315           b1 = true;
2316         }
2317       }
2318       if (b1 && b2) {
2319         return;
2320       }
2321     }
2322     for (const auto& v : bd.getExternalStateVariables()) {
2323       if (v.arraySize > 1) {
2324         if (this->useDynamicallyAllocatedVector(v.arraySize)) {
2325           b2 = true;
2326         } else {
2327           b1 = true;
2328         }
2329       }
2330       if (b1 && b2) {
2331         return;
2332       }
2333     }
2334   }  // end of BehaviourData::requiresTVectorOrVectorIncludes
2335 
requiresTVectorOrVectorIncludes(bool & b1,bool & b2) const2336   void BehaviourDescription::requiresTVectorOrVectorIncludes(bool& b1,
2337                                                              bool& b2) const {
2338     b1 = b2 = false;
2339     tfel::raise_if(this->hypotheses.empty(),
2340                    "BehaviourDescription::areAllMechanicalDataSpecialised: "
2341                    "no hypothesis defined");
2342     if (!this->areAllMechanicalDataSpecialised()) {
2343       this->requiresTVectorOrVectorIncludes(b1, b2, d);
2344     }
2345     for (const auto& md : this->sd) {
2346       this->requiresTVectorOrVectorIncludes(b1, b2, *(md.second));
2347     }
2348   }  // end of BehaviourDescription::requiresTVectorOrVectorIncludes
2349 
2350   void BehaviourDescription::
declareExternalStateVariableProbablyUnusableInPurelyImplicitResolution(const Hypothesis h,const std::string & n)2351       declareExternalStateVariableProbablyUnusableInPurelyImplicitResolution(
2352           const Hypothesis h, const std::string& n) {
2353     void (BehaviourData::*m)(const std::string&) =
2354         &BehaviourData::
2355             declareExternalStateVariableProbablyUnusableInPurelyImplicitResolution;
2356     this->callBehaviourData(h, m, n, true);
2357   }  // end of
2358      // BehaviourDescription::declareExternalStateVariableProbablyUnusableInPurelyImplicitResolution
2359 
setUsableInPurelyImplicitResolution(const Hypothesis h,const bool b)2360   void BehaviourDescription::setUsableInPurelyImplicitResolution(
2361       const Hypothesis h, const bool b) {
2362     void (BehaviourData::*m)(const bool) =
2363         &BehaviourData::setUsableInPurelyImplicitResolution;
2364     this->callBehaviourData(h, m, b, true);
2365   }  // end of
2366      // BehaviourDescription::declareExternalStateVariableProbablyUnusableInPurelyImplicitResolution
2367 
isMemberUsedInCodeBlocks(const Hypothesis h,const std::string & v) const2368   bool BehaviourDescription::isMemberUsedInCodeBlocks(
2369       const Hypothesis h, const std::string& v) const {
2370     return this->getData(h, &BehaviourData::isMemberUsedInCodeBlocks, v);
2371   }  // end of BehaviourDescription::isMaterialPropertyName
2372 
isMaterialPropertyName(const Hypothesis h,const std::string & v) const2373   bool BehaviourDescription::isMaterialPropertyName(
2374       const Hypothesis h, const std::string& v) const {
2375     return this->getData(h, &BehaviourData::isMaterialPropertyName, v);
2376   }  // end of BehaviourDescription::isMaterialPropertyName
2377 
isLocalVariableName(const Hypothesis h,const std::string & n) const2378   bool BehaviourDescription::isLocalVariableName(const Hypothesis h,
2379                                                  const std::string& n) const {
2380     return this->getData(h, &BehaviourData::isLocalVariableName, n);
2381   }  // end of BehaviourDescription::isLocalVariableName
2382 
isPersistentVariableName(const Hypothesis h,const std::string & n) const2383   bool BehaviourDescription::isPersistentVariableName(
2384       const Hypothesis h, const std::string& n) const {
2385     return this->getData(h, &BehaviourData::isPersistentVariableName, n);
2386   }  // end of BehaviourDescription::isPersistentVariableName
2387 
isIntegrationVariableName(const Hypothesis h,const std::string & n) const2388   bool BehaviourDescription::isIntegrationVariableName(
2389       const Hypothesis h, const std::string& n) const {
2390     return this->getData(h, &BehaviourData::isIntegrationVariableName, n);
2391   }  // end of BehaviourDescription::isIntegrationVariableName
2392 
isIntegrationVariableIncrementName(const Hypothesis h,const std::string & n) const2393   bool BehaviourDescription::isIntegrationVariableIncrementName(
2394       const Hypothesis h, const std::string& n) const {
2395     return this->getData(h, &BehaviourData::isIntegrationVariableIncrementName,
2396                          n);
2397   }  // end of BehaviourDescription::isIntegrationVariableIncrementName
2398 
isStateVariableName(const Hypothesis h,const std::string & n) const2399   bool BehaviourDescription::isStateVariableName(const Hypothesis h,
2400                                                  const std::string& n) const {
2401     return this->getData(h, &BehaviourData::isStateVariableName, n);
2402   }  // end of BehaviourDescription::isStateVariableName
2403 
isStateVariableIncrementName(const Hypothesis h,const std::string & n) const2404   bool BehaviourDescription::isStateVariableIncrementName(
2405       const Hypothesis h, const std::string& n) const {
2406     return this->getData(h, &BehaviourData::isStateVariableIncrementName, n);
2407   }  // end of BehaviourDescription::isStateVariableIncrementName
2408 
isAuxiliaryStateVariableName(const Hypothesis h,const std::string & n) const2409   bool BehaviourDescription::isAuxiliaryStateVariableName(
2410       const Hypothesis h, const std::string& n) const {
2411     return this->getData(h, &BehaviourData::isAuxiliaryStateVariableName, n);
2412   }  // end of BehaviourDescription::isAuxiliaryStateVariableName
2413 
isExternalStateVariableName(const Hypothesis h,const std::string & n) const2414   bool BehaviourDescription::isExternalStateVariableName(
2415       const Hypothesis h, const std::string& n) const {
2416     return this->getData(h, &BehaviourData::isExternalStateVariableName, n);
2417   }  // end of BehaviourDescription::isExternalStateVariableName
2418 
isExternalStateVariableIncrementName(const Hypothesis h,const std::string & n) const2419   bool BehaviourDescription::isExternalStateVariableIncrementName(
2420       const Hypothesis h, const std::string& n) const {
2421     return this->getData(
2422         h, &BehaviourData::isExternalStateVariableIncrementName, n);
2423   }  // end of BehaviourDescription::isExternalStateVariableIncrementName
2424 
isParameterName(const Hypothesis h,const std::string & v) const2425   bool BehaviourDescription::isParameterName(const Hypothesis h,
2426                                              const std::string& v) const {
2427     return this->getData(h, &BehaviourData::isParameterName, v);
2428   }  // end of BehaviourDescription::isParameterName
2429 
isStaticVariableName(const Hypothesis h,const std::string & n) const2430   bool BehaviourDescription::isStaticVariableName(const Hypothesis h,
2431                                                   const std::string& n) const {
2432     return this->getData(h, &BehaviourData::isStaticVariableName, n);
2433   }  // end of BehaviourDescription::isStaticVariableName
2434 
updateClassName()2435   void BehaviourDescription::updateClassName() {
2436     if ((!this->behaviour.empty()) || (!this->material.empty())) {
2437       this->className = this->material + this->behaviour;
2438     }
2439   }  // end of BehaviourDescription::updateClassName
2440 
setCode(const Hypothesis h,const std::string & n,const CodeBlock & c,const Mode m,const Position p,const bool b)2441   void BehaviourDescription::setCode(const Hypothesis h,
2442                                      const std::string& n,
2443                                      const CodeBlock& c,
2444                                      const Mode m,
2445                                      const Position p,
2446                                      const bool b) {
2447     if (h == ModellingHypothesis::UNDEFINEDHYPOTHESIS) {
2448       if (getVerboseMode() >= VERBOSE_DEBUG) {
2449         auto& log = getLogStream();
2450         log << "BehaviourDescription::setCode : setting '" << n
2451             << "' on default hypothesis" << std::endl;
2452       }
2453       this->d.setCode(n, c, m, p, b);
2454       for (const auto& pd : sd) {
2455         if (getVerboseMode() >= VERBOSE_DEBUG) {
2456           auto& log = getLogStream();
2457           log << "BehaviourDescription::setCode : setting '" << n
2458               << "' on hypothesis '" << ModellingHypothesis::toString(pd.first)
2459               << "'" << std::endl;
2460         }
2461         pd.second->setCode(n, c, m, p, b);
2462       }
2463     } else {
2464       if (getVerboseMode() >= VERBOSE_DEBUG) {
2465         auto& log = getLogStream();
2466         log << "BehaviourDescription::setCode : setting '" << n
2467             << "' on hypothesis '" << ModellingHypothesis::toString(h) << "'"
2468             << std::endl;
2469       }
2470       this->getBehaviourData2(h).setCode(n, c, m, p, b);
2471     }
2472   }  // end of BehaviourDescription::setCode
2473 
getCodeBlock(const Hypothesis h,const std::string & n) const2474   const CodeBlock& BehaviourDescription::getCodeBlock(
2475       const Hypothesis h, const std::string& n) const {
2476     return this->getBehaviourData(h).getCodeBlock(n);
2477   }  // end of BehaviourDescription::getCode
2478 
getCode(const Hypothesis h,const std::string & n) const2479   std::string BehaviourDescription::getCode(const Hypothesis h,
2480                                             const std::string& n) const {
2481     const auto b = this->getAttribute(BehaviourData::profiling, false);
2482     return this->getBehaviourData(h).getCode(n, this->getClassName(), b);
2483   }  // end of BehaviourDescription::getCode
2484 
hasCode(const Hypothesis h,const std::string & n) const2485   bool BehaviourDescription::hasCode(const Hypothesis h,
2486                                      const std::string& n) const {
2487     return this->getBehaviourData(h).hasCode(n);
2488   }  // end of BehaviourDescription::getCode
2489 
setAttribute(const Hypothesis h,const std::string & n,const BehaviourAttribute & a,const bool b)2490   void BehaviourDescription::setAttribute(const Hypothesis h,
2491                                           const std::string& n,
2492                                           const BehaviourAttribute& a,
2493                                           const bool b) {
2494     if (h == ModellingHypothesis::UNDEFINEDHYPOTHESIS) {
2495       this->d.setAttribute(n, a, b);
2496       for (const auto& md : this->sd) {
2497         BehaviourData& bdata = *(md.second);
2498         bdata.setAttribute(n, a, b);
2499       }
2500     } else {
2501       this->getBehaviourData2(h).setAttribute(n, a, b);
2502     }
2503   }  // end of BehaviourDescription::setAttribute
2504 
updateAttribute(const Hypothesis h,const std::string & n,const BehaviourAttribute & a)2505   void BehaviourDescription::updateAttribute(const Hypothesis h,
2506                                              const std::string& n,
2507                                              const BehaviourAttribute& a) {
2508     if (h == ModellingHypothesis::UNDEFINEDHYPOTHESIS) {
2509       this->d.updateAttribute(n, a);
2510       for (const auto& md : this->sd) {
2511         md.second->updateAttribute(n, a);
2512       }
2513     } else {
2514       this->getBehaviourData2(h).updateAttribute(n, a);
2515     }
2516   }  // end of BehaviourDescription::updateAttribute
2517 
hasAttribute(const Hypothesis h,const std::string & n) const2518   bool BehaviourDescription::hasAttribute(const Hypothesis h,
2519                                           const std::string& n) const {
2520     return this->getBehaviourData(h).hasAttribute(n);
2521   }  // end of BehaviourDescription::hasAttribute
2522 
getCodeBlockNames(const Hypothesis h) const2523   std::vector<std::string> BehaviourDescription::getCodeBlockNames(
2524       const Hypothesis h) const {
2525     return this->getBehaviourData(h).getCodeBlockNames();
2526   }
2527 
getExternalNames(const Hypothesis h,const VarContainer & v) const2528   std::vector<std::string> BehaviourDescription::getExternalNames(
2529       const Hypothesis h, const VarContainer& v) const {
2530     return this->getBehaviourData(h).getExternalNames(v);
2531   }
2532 
getExternalNames(std::vector<std::string> & n,const Hypothesis h,const VarContainer & v) const2533   void BehaviourDescription::getExternalNames(std::vector<std::string>& n,
2534                                               const Hypothesis h,
2535                                               const VarContainer& v) const {
2536     return this->getBehaviourData(h).getExternalNames(n, v);
2537   }  // end of BehaviourDescription::getExternalNames
2538 
appendExternalNames(std::vector<std::string> & n,const Hypothesis h,const VarContainer & v) const2539   void BehaviourDescription::appendExternalNames(std::vector<std::string>& n,
2540                                                  const Hypothesis h,
2541                                                  const VarContainer& v) const {
2542     return this->getBehaviourData(h).appendExternalNames(n, v);
2543   }  // end of BehaviourDescription::appendExternalNames
2544 
setGlossaryName(const std::string & n,const std::string & gn)2545   void BehaviourDescription::setGlossaryName(const std::string& n,
2546                                              const std::string& gn) {
2547     using tfel::glossary::Glossary;
2548     const auto& glossary = Glossary::getGlossary();
2549     tfel::raise_if(!glossary.contains(gn),
2550                    "BehaviourDescription::setGlossaryName: "
2551                    "'" +
2552                        gn + "' is not a glossary name");
2553     for (auto& v : this->mvariables) {
2554       constexpr const auto h = ModellingHypothesis::UNDEFINEDHYPOTHESIS;
2555       if (v.first.name == n) {
2556         v.first.setGlossaryName(gn);
2557         this->registerGlossaryName(h, n, gn);
2558       }
2559       if (v.second.name == n) {
2560         v.second.setGlossaryName(gn);
2561         this->registerGlossaryName(h, n, gn);
2562       }
2563     }
2564   }  // end of BehaviourDescription::setGlossaryName
2565 
setEntryName(const std::string & n,const std::string & e)2566   void BehaviourDescription::setEntryName(const std::string& n,
2567                                           const std::string& e) {
2568     using tfel::glossary::Glossary;
2569     using MainVariable = std::pair<Gradient, ThermodynamicForce>;
2570     const auto& glossary = Glossary::getGlossary();
2571     tfel::raise_if(glossary.contains(e),
2572                    "BehaviourDescription::setEntryName: "
2573                    "'" +
2574                        e + "' is a glossary name");
2575     std::for_each(this->mvariables.begin(), this->mvariables.end(),
2576                   [this, &n, &e](MainVariable& v) {
2577                     constexpr const auto h =
2578                         ModellingHypothesis::UNDEFINEDHYPOTHESIS;
2579                     if (v.first.name == n) {
2580                       v.first.setEntryName(e);
2581                       this->registerEntryName(h, n, e);
2582                     }
2583                     if (v.second.name == n) {
2584                       v.second.setEntryName(e);
2585                       this->registerEntryName(h, n, e);
2586                     }
2587                   });
2588   }  // end of BehaviourDescription::setEntryName
2589 
setGlossaryName(const Hypothesis h,const std::string & n,const std::string & g)2590   void BehaviourDescription::setGlossaryName(const Hypothesis h,
2591                                              const std::string& n,
2592                                              const std::string& g) {
2593     this->callBehaviourData(h, &BehaviourData::setGlossaryName, n, g, true);
2594   }  // end of BehaviourDescription::setGlossaryName
2595 
isGlossaryNameUsed(const Hypothesis h,const std::string & n) const2596   bool BehaviourDescription::isGlossaryNameUsed(const Hypothesis h,
2597                                                 const std::string& n) const {
2598     return this->getBehaviourData(h).isGlossaryNameUsed(n);
2599   }  // end of BehaviourDescription::isGlossaryName
2600 
setEntryName(const Hypothesis h,const std::string & n,const std::string & g)2601   void BehaviourDescription::setEntryName(const Hypothesis h,
2602                                           const std::string& n,
2603                                           const std::string& g) {
2604     this->callBehaviourData(h, &BehaviourData::setEntryName, n, g, true);
2605   }  // end of BehaviourDescription::setEntryName
2606 
isUsedAsEntryName(const Hypothesis h,const std::string & n) const2607   bool BehaviourDescription::isUsedAsEntryName(const Hypothesis h,
2608                                                const std::string& n) const {
2609     return this->getBehaviourData(h).isUsedAsEntryName(n);
2610   }  // end of BehaviourDescription::isEntryName
2611 
getExternalName(const Hypothesis h,const std::string & n) const2612   std::string BehaviourDescription::getExternalName(
2613       const Hypothesis h, const std::string& n) const {
2614     return this->getData(h, &BehaviourData::getExternalName, n);
2615   }  // end of BehaviourDescription::getGlossaryName
2616 
getVariableNameFromGlossaryNameOrEntryName(const Hypothesis h,const std::string & n) const2617   std::string BehaviourDescription::getVariableNameFromGlossaryNameOrEntryName(
2618       const Hypothesis h, const std::string& n) const {
2619     return this->getBehaviourData(h).getVariableNameFromGlossaryNameOrEntryName(
2620         n);
2621   }  // end of
2622      // BehaviourDescription::getVariableNameFromGlossaryNameOrEntryName
2623 
2624   const VariableDescription&
getVariableDescriptionByExternalName(const Hypothesis h,const std::string & n) const2625   BehaviourDescription::getVariableDescriptionByExternalName(
2626       const Hypothesis h, const std::string& n) const {
2627     return this->getBehaviourData(h).getVariableDescriptionByExternalName(n);
2628   }  // end of BehaviourDescription::getVariableDescriptionByExternalName
2629 
setBounds(const Hypothesis h,const std::string & n,const VariableBoundsDescription & b)2630   void BehaviourDescription::setBounds(const Hypothesis h,
2631                                        const std::string& n,
2632                                        const VariableBoundsDescription& b) {
2633     auto throw_if = [](const bool c, const std::string& m) {
2634       tfel::raise_if(c, "BehaviourDescription::setBounds: " + m);
2635     };
2636     if (this->isGradientName(n)) {
2637       throw_if(h != ModellingHypothesis::UNDEFINEDHYPOTHESIS,
2638                "invalid modelling hypothesis");
2639       this->getGradient(n).setBounds(b);
2640     } else if (this->isThermodynamicForceName(n)) {
2641       throw_if(h != ModellingHypothesis::UNDEFINEDHYPOTHESIS,
2642                "invalid modelling hypothesis");
2643       this->getThermodynamicForce(n).setBounds(b);
2644     } else {
2645       this->callBehaviourData(h, &BehaviourData::setBounds, n, b, true);
2646     }
2647   }  // end of BehaviourDescription::setBounds
2648 
setBounds(const Hypothesis h,const std::string & n,const unsigned short i,const VariableBoundsDescription & b)2649   void BehaviourDescription::setBounds(const Hypothesis h,
2650                                        const std::string& n,
2651                                        const unsigned short i,
2652                                        const VariableBoundsDescription& b) {
2653     auto throw_if = [](const bool c, const std::string& m) {
2654       tfel::raise_if(c, "BehaviourDescription::setBounds: " + m);
2655     };
2656     if (this->isGradientName(n)) {
2657       throw_if(h != ModellingHypothesis::UNDEFINEDHYPOTHESIS,
2658                "invalid modelling hypothesis");
2659       this->getGradient(n).setBounds(b, i);
2660     } else if (this->isThermodynamicForceName(n)) {
2661       throw_if(h != ModellingHypothesis::UNDEFINEDHYPOTHESIS,
2662                "invalid modelling hypothesis");
2663       this->getThermodynamicForce(n).setBounds(b, i);
2664     } else {
2665       if (h == ModellingHypothesis::UNDEFINEDHYPOTHESIS) {
2666         this->d.setBounds(n, i, b);
2667         for (auto md : this->sd) {
2668           md.second.get()->setBounds(n, i, b);
2669         }
2670       } else {
2671         this->getBehaviourData2(h).setBounds(n, i, b);
2672       }
2673     }
2674   }  // end of BehaviourDescription::setBounds
2675 
setPhysicalBounds(const Hypothesis h,const std::string & n,const VariableBoundsDescription & b)2676   void BehaviourDescription::setPhysicalBounds(
2677       const Hypothesis h,
2678       const std::string& n,
2679       const VariableBoundsDescription& b) {
2680     auto throw_if = [](const bool c, const std::string& m) {
2681       tfel::raise_if(c, "BehaviourDescription::setPhysicalBounds: " + m);
2682     };
2683     if (this->isGradientName(n)) {
2684       throw_if(h != ModellingHypothesis::UNDEFINEDHYPOTHESIS,
2685                "invalid modelling hypothesis");
2686       this->getGradient(n).setBounds(b);
2687     } else if (this->isThermodynamicForceName(n)) {
2688       throw_if(h != ModellingHypothesis::UNDEFINEDHYPOTHESIS,
2689                "invalid modelling hypothesis");
2690       this->getThermodynamicForce(n).setBounds(b);
2691     } else {
2692       this->callBehaviourData(h, &BehaviourData::setPhysicalBounds, n, b, true);
2693     }
2694   }  // end of BehaviourDescription::setPhysicalBounds
2695 
setPhysicalBounds(const Hypothesis h,const std::string & n,const unsigned short i,const VariableBoundsDescription & b)2696   void BehaviourDescription::setPhysicalBounds(
2697       const Hypothesis h,
2698       const std::string& n,
2699       const unsigned short i,
2700       const VariableBoundsDescription& b) {
2701     auto throw_if = [](const bool c, const std::string& m) {
2702       tfel::raise_if(c, "BehaviourDescription::setPhysicalBounds: " + m);
2703     };
2704     if (this->isGradientName(n)) {
2705       throw_if(h != ModellingHypothesis::UNDEFINEDHYPOTHESIS,
2706                "invalid modelling hypothesis");
2707       this->getGradient(n).setBounds(b, i);
2708     } else if (this->isThermodynamicForceName(n)) {
2709       throw_if(h != ModellingHypothesis::UNDEFINEDHYPOTHESIS,
2710                "invalid modelling hypothesis");
2711       this->getThermodynamicForce(n).setBounds(b, i);
2712     } else {
2713       if (h == ModellingHypothesis::UNDEFINEDHYPOTHESIS) {
2714         this->d.setPhysicalBounds(n, i, b);
2715         for (auto md : this->sd) {
2716           md.second.get()->setPhysicalBounds(n, i, b);
2717         }
2718       } else {
2719         this->getBehaviourData2(h).setPhysicalBounds(n, i, b);
2720       }
2721     }
2722   }  // end of BehaviourDescription::setPhysicalBounds
2723 
setAttribute(const std::string & n,const BehaviourAttribute & a,const bool b)2724   void BehaviourDescription::setAttribute(const std::string& n,
2725                                           const BehaviourAttribute& a,
2726                                           const bool b) {
2727     if (b) {
2728       auto p = this->attributes.find(n);
2729       if (p != this->attributes.end()) {
2730         tfel::raise_if(a.getTypeIndex() != p->second.getTypeIndex(),
2731                        "BehaviourDescription::setAttribute: "
2732                        "attribute already exists with a different type");
2733         return;
2734       }
2735     }
2736     tfel::raise_if(!this->attributes.insert({n, a}).second,
2737                    "BehaviourDescription::setAttribute: "
2738                    "attribute '" +
2739                        n + "' already declared");
2740   }  // end of BehaviourDescription::setAttribute
2741 
hasAttribute(const std::string & n) const2742   bool BehaviourDescription::hasAttribute(const std::string& n) const {
2743     return this->attributes.count(n) != 0u;
2744   }  // end of BehaviourDescription::hasAttribute
2745 
2746   const std::map<std::string, BehaviourAttribute>&
getAttributes() const2747   BehaviourDescription::getAttributes() const {
2748     return this->attributes;
2749   }  // end of BehaviourDescription::getAttributes
2750 
reserveName(const Hypothesis h,const std::string & n)2751   void BehaviourDescription::reserveName(const Hypothesis h,
2752                                          const std::string& n) {
2753     this->callBehaviourData(h, &BehaviourData::reserveName, n, true);
2754   }
2755 
isNameReserved(const std::string & n) const2756   bool BehaviourDescription::isNameReserved(const std::string& n) const {
2757     if (this->d.isNameReserved(n)) {
2758       return true;
2759     }
2760     for (auto md : this->sd) {
2761       if (md.second->isNameReserved(n)) {
2762         return true;
2763       }
2764     }
2765     return false;
2766   }  // end of BehaviourDescription::isNameReserved
2767 
registerGlossaryName(const Hypothesis h,const std::string & n,const std::string & g)2768   void BehaviourDescription::registerGlossaryName(const Hypothesis h,
2769                                                   const std::string& n,
2770                                                   const std::string& g) {
2771     this->callBehaviourData(h, &BehaviourData::registerGlossaryName, n, g,
2772                             true);
2773   }  // end of BehaviourDescription::registerGlossaryName
2774 
registerEntryName(const Hypothesis h,const std::string & n,const std::string & e)2775   void BehaviourDescription::registerEntryName(const Hypothesis h,
2776                                                const std::string& n,
2777                                                const std::string& e) {
2778     this->callBehaviourData(h, &BehaviourData::registerEntryName, n, e, true);
2779   }  // end of BehaviourDescription::registerEntryName
2780 
registerMemberName(const Hypothesis h,const std::string & n)2781   void BehaviourDescription::registerMemberName(const Hypothesis h,
2782                                                 const std::string& n) {
2783     this->callBehaviourData(h, &BehaviourData::registerMemberName, n, true);
2784   }  // end of BehaviourDescription::registerMemberName
2785 
registerStaticMemberName(const Hypothesis h,const std::string & n)2786   void BehaviourDescription::registerStaticMemberName(const Hypothesis h,
2787                                                       const std::string& n) {
2788     this->callBehaviourData(h, &BehaviourData::registerStaticMemberName, n,
2789                             true);
2790   }  // end of BehaviourDescription::registerMemberName
2791 
addMaterialLaw(const std::string & m)2792   void BehaviourDescription::addMaterialLaw(const std::string& m) {
2793     if (std::find(this->materialLaws.begin(), this->materialLaws.end(), m) ==
2794         this->materialLaws.end()) {
2795       this->materialLaws.push_back(m);
2796     }
2797   }  // end of BehaviourDescription::getMaterialLaws
2798 
getMaterialLaws() const2799   const std::vector<std::string>& BehaviourDescription::getMaterialLaws()
2800       const {
2801     return this->materialLaws;
2802   }
2803 
checkVariableExistence(const std::string & v) const2804   std::pair<bool, bool> BehaviourDescription::checkVariableExistence(
2805       const std::string& v) const {
2806     const auto& mh = this->getDistinctModellingHypotheses();
2807     std::pair<bool, bool> r{true, false};
2808     for (const auto& h : mh) {
2809       const auto& bdata = this->getBehaviourData(h);
2810       const auto& vn = bdata.getVariablesNames();
2811       const bool b = vn.find(v) != vn.end();
2812       r.first = r.first && b;
2813       r.second = r.second || b;
2814     }
2815     if (!r.second) {
2816       r.first = false;
2817     }
2818     return r;
2819   }  // end of checkVariableExistence
2820 
checkVariableExistence(const std::string & n,const std::string & c,const bool b) const2821   std::pair<bool, bool> BehaviourDescription::checkVariableExistence(
2822       const std::string& n, const std::string& c, const bool b) const {
2823     const auto& mh = this->getDistinctModellingHypotheses();
2824     std::pair<bool, bool> r = {true, false};
2825     for (const auto h : mh) {
2826       const auto& bd = this->getBehaviourData(h);
2827       const auto f = bd.getVariables(c).contains(n);
2828       tfel::raise_if(!f && b,
2829                      "BehaviourDescription::checkVariableExistence: "
2830                      "no '" +
2831                          c + "' named '" + n +
2832                          "' found for at "
2833                          "least one modelling hypothesis");
2834       r.first = r.first && f;
2835       r.second = r.second || f;
2836     }
2837     if (!r.second) {
2838       r.first = false;
2839     }
2840     return r;
2841   }
2842 
checkVariableGlossaryName(const std::string & n,const std::string & g) const2843   void BehaviourDescription::checkVariableGlossaryName(
2844       const std::string& n, const std::string& g) const {
2845     auto throw_if = [](const bool c, const std::string& m) {
2846       tfel::raise_if(c,
2847                      "BehaviourDescription::"
2848                      "checkVariableGlossaryName: " +
2849                          m);
2850     };
2851     for (const auto& h : this->getDistinctModellingHypotheses()) {
2852       const auto& bdata = this->getBehaviourData(h);
2853       throw_if(!bdata.hasGlossaryName(n),
2854                "no glossary name associated with variable '" + n + "'");
2855       const auto& en = bdata.getExternalName(n);
2856       throw_if(en != g,
2857                "the glossary name associated with "
2858                "variable '" +
2859                    n + "' is not '" + g + "', but '" + en + "'");
2860     }
2861   }  // end of BehaviourDescription::checkVariableGlossaryName
2862 
checkVariableEntryName(const std::string & n,const std::string & e) const2863   void BehaviourDescription::checkVariableEntryName(
2864       const std::string& n, const std::string& e) const {
2865     auto throw_if = [](const bool c, const std::string& m) {
2866       tfel::raise_if(c,
2867                      "BehaviourDescription::"
2868                      "checkVariableEntryName: " +
2869                          m);
2870     };
2871     for (const auto& h : this->getDistinctModellingHypotheses()) {
2872       const auto& bdata = this->getBehaviourData(h);
2873       throw_if(!bdata.hasEntryName(n),
2874                "no entry name associated with variable '" + n + "'");
2875       const auto& en = bdata.getExternalName(n);
2876       throw_if(en != e,
2877                "the entry name associated with "
2878                "variable '" +
2879                    n + "' is not '" + e + "', but '" + en + "'");
2880     }
2881   }  // end of BehaviourDescription::checkVariableEntryName
2882 
checkVariablePosition(const std::string & n,const std::string & c,const size_t p)2883   void BehaviourDescription::checkVariablePosition(const std::string& n,
2884                                                    const std::string& c,
2885                                                    const size_t p) {
2886     for (const auto& h : this->getDistinctModellingHypotheses()) {
2887       const auto& bdata = this->getBehaviourData(h);
2888       const auto& vc = bdata.getVariables(c);
2889       tfel::raise_if(p >= vc.size(),
2890                      "BehaviourDescription::checkVariablePosition: "
2891                      "position given is greater than the number "
2892                      "of variables of category '" +
2893                          c + "'");
2894       const auto& v = vc[p];
2895       tfel::raise_if(v.name != n,
2896                      "BehaviourDescription::checkVariablePosition: "
2897                      "variable at the given position is not named '" +
2898                          n + "' but '" + v.name + "'");
2899     }
2900   }  // end of BehaviourDescription::checkVariablePosition
2901 
setOrthotropicAxesConvention(const OrthotropicAxesConvention c)2902   void BehaviourDescription::setOrthotropicAxesConvention(
2903       const OrthotropicAxesConvention c) {
2904     tfel::raise_if(this->oacIsDefined,
2905                    "BehaviourDescription::setOrthotropicAxesConvention: "
2906                    "orthotropic axes convention already defined");
2907     tfel::raise_if(this->getSymmetryType() != mfront::ORTHOTROPIC,
2908                    "BehaviourDescription::setOrthotropicAxesConvention: "
2909                    "the behaviour is not orthotropic.");
2910     if (c == OrthotropicAxesConvention::PLATE) {
2911       if (this->areModellingHypothesesDefined()) {
2912         for (const auto h : this->getModellingHypotheses()) {
2913           tfel::raise_if((h != ModellingHypothesis::TRIDIMENSIONAL) &&
2914                              (h != ModellingHypothesis::PLANESTRESS) &&
2915                              (h != ModellingHypothesis::PLANESTRAIN) &&
2916                              (h != ModellingHypothesis::GENERALISEDPLANESTRAIN),
2917                          "Modelling hypothesis '" +
2918                              ModellingHypothesis::toString(h) +
2919                              "' is not compatible "
2920                              "with the `Plate` orthotropic axes convention");
2921         }
2922       }
2923     }
2924     this->oacIsDefined = true;
2925     this->oac = c;
2926   }
2927 
2928   tfel::material::OrthotropicAxesConvention
getOrthotropicAxesConvention() const2929   BehaviourDescription::getOrthotropicAxesConvention() const {
2930     tfel::raise_if(this->getSymmetryType() != mfront::ORTHOTROPIC,
2931                    "BehaviourDescription::getOrthotropicAxesConvention: "
2932                    "the behaviour is not orthotropic.");
2933     if (!this->oacIsDefined) {
2934       this->oacIsDefined = true;
2935     }
2936     return this->oac;
2937   }
2938 
useDynamicallyAllocatedVector(const unsigned short s) const2939   bool BehaviourDescription::useDynamicallyAllocatedVector(
2940       const unsigned short s) const {
2941     return (s >= SupportedTypes::ArraySizeLimit) &&
2942            (this->areDynamicallyAllocatedVectorsAllowed());
2943   }  // end of SupportedTypes::useDynamicallyAllocatedVector
2944 
areDynamicallyAllocatedVectorsAllowed() const2945   bool BehaviourDescription::areDynamicallyAllocatedVectorsAllowed() const {
2946     if (this->areDynamicallyAllocatedVectorsAllowed_.is<bool>()) {
2947       return this->areDynamicallyAllocatedVectorsAllowed_.get<bool>();
2948     }
2949     return true;
2950   }  // end of SupportedTypes::areDynamicallyAllocatedVectorsAllowed
2951 
areDynamicallyAllocatedVectorsAllowed(const bool b)2952   void BehaviourDescription::areDynamicallyAllocatedVectorsAllowed(
2953       const bool b) {
2954     if (this->areDynamicallyAllocatedVectorsAllowed_.is<bool>()) {
2955       tfel::raise_if(
2956           this->areDynamicallyAllocatedVectorsAllowed_.get<bool>() != b,
2957           "BehaviourDescription::areDynamicallyAllocatedVectorsAllowed: "
2958           "inconsistent policy for dynamically allocated vectors");
2959       return;
2960     }
2961     this->areDynamicallyAllocatedVectorsAllowed_ = b;
2962   }  // end of SupportedTypes::areDynamicallyAllocatedVectorsAllowed
2963 
setStrainMeasure(const StrainMeasure sm)2964   void BehaviourDescription::setStrainMeasure(const StrainMeasure sm) {
2965     tfel::raise_if(this->getBehaviourType() !=
2966                        BehaviourDescription::STANDARDSTRAINBASEDBEHAVIOUR,
2967                    "BehaviourDescription::setStrainMeasure: "
2968                    "invalid behaviour type");
2969     tfel::raise_if(this->isStrainMeasureDefined(),
2970                    "BehaviourDescription::setStrainMeasure: "
2971                    "strain measure already defined");
2972     this->strainMeasure = sm;
2973   }
2974 
getStrainMeasure() const2975   BehaviourDescription::StrainMeasure BehaviourDescription::getStrainMeasure()
2976       const {
2977     tfel::raise_if(!this->isStrainMeasureDefined(),
2978                    "BehaviourDescription::getStrainMeasure: "
2979                    "no strain measure defined");
2980     return this->strainMeasure.get<StrainMeasure>();
2981   }  // end of BehaviourDescription::setStrainMeasure()
2982 
isStrainMeasureDefined() const2983   bool BehaviourDescription::isStrainMeasureDefined() const {
2984     return this->strainMeasure.is<StrainMeasure>();
2985   }  // end of BehaviourDescription::isStrainMeasureDefined()
2986 
getSymbols(std::map<std::string,std::string> & symbols,const Hypothesis h) const2987   void BehaviourDescription::getSymbols(
2988       std::map<std::string, std::string>& symbols, const Hypothesis h) const {
2989     for (const auto& mv : this->mvariables) {
2990       getSymbol(symbols, mv.first);
2991       getSymbol(symbols, mv.second);
2992     }
2993     for (const auto& b : this->getTangentOperatorBlocks()) {
2994       if ((Gradient::isIncrementKnown(b.second)) ||
2995           (this->isExternalStateVariableName(h, b.second.name))) {
2996         symbols.insert({"\u2202" + displayName(b.first) + "\u2215\u2202\u0394" +
2997                             displayName(b.second),
2998                         "d" + b.first.name + "_dd" + b.second.name});
2999       } else {
3000         symbols.insert({"\u2202" + displayName(b.first) + "\u2215\u2202" +
3001                             displayName(b.second) + "\u2081",
3002                         "d" + b.first.name + "_d" + b.second.name + "1"});
3003       }
3004     }
3005     this->getBehaviourData(h).getSymbols(symbols);
3006   }  // end of BehaviourDescription::getSymbols
3007 
3008   std::vector<MaterialPropertyDescription>
getElasticMaterialPropertiesDescriptions() const3009   BehaviourDescription::getElasticMaterialPropertiesDescriptions() const {
3010     const auto& emps = this->getElasticMaterialProperties();
3011     auto empds = std::vector<MaterialPropertyDescription>{emps.size()};
3012     if (emps.size() == 2u) {
3013       empds[0] =
3014           buildMaterialPropertyDescription(emps[0], *this, "YoungModulus");
3015       empds[1] =
3016           buildMaterialPropertyDescription(emps[1], *this, "PoissonRatio");
3017     } else if (emps.size() == 9u) {
3018       empds[0] =
3019           buildMaterialPropertyDescription(emps[0], *this, "YoungModulus1");
3020       empds[1] =
3021           buildMaterialPropertyDescription(emps[1], *this, "YoungModulus2");
3022       empds[2] =
3023           buildMaterialPropertyDescription(emps[2], *this, "YoungModulus3");
3024       empds[3] =
3025           buildMaterialPropertyDescription(emps[3], *this, "PoissonRatio12");
3026       empds[4] =
3027           buildMaterialPropertyDescription(emps[4], *this, "PoissonRatio23");
3028       empds[5] =
3029           buildMaterialPropertyDescription(emps[5], *this, "PoissonRatio13");
3030       empds[6] =
3031           buildMaterialPropertyDescription(emps[6], *this, "ShearModulus12");
3032       empds[7] =
3033           buildMaterialPropertyDescription(emps[7], *this, "ShearModulus23");
3034       empds[8] =
3035           buildMaterialPropertyDescription(emps[8], *this, "ShearModulus13");
3036     } else {
3037       tfel::raise(
3038           "BehaviourDescription::getElasticMaterialPropertiesDescriptions: "
3039           "invalid number of material properties");
3040     }
3041     return empds;
3042   }  // end of BehaviourDescription::getElasticMaterialPropertiesDescriptions
3043 
overrideByAParameter(const std::string & n,const double v)3044   void BehaviourDescription::overrideByAParameter(const std::string& n,
3045                                                   const double v) {
3046     this->d.overrideByAParameter(n, v);
3047     for (auto& md : this->sd) {
3048       md.second->overrideByAParameter(n, v);
3049     }
3050   }  // end of BehaviourDescription::overrideByAParameter
3051 
3052   BehaviourDescription::~BehaviourDescription() = default;
3053 
setElasticSymmetryType(BehaviourDescription & bd,const BehaviourSymmetryType s)3054   void setElasticSymmetryType(BehaviourDescription& bd,
3055                               const BehaviourSymmetryType s) {
3056     if (bd.isElasticSymmetryTypeDefined()) {
3057       tfel::raise_if(bd.getElasticSymmetryType() != s,
3058                      "setElasticSymmetryType: "
3059                      "the elastic symmetry type defined for "
3060                      "the behaviour is inconsistent.");
3061     } else {
3062       bd.setElasticSymmetryType(s);
3063     }
3064   }  // end of setElasticSymmetryType
3065 
checkIsStrictlyPositive(const BehaviourDescription::MaterialProperty & mp)3066   void checkIsStrictlyPositive(
3067       const BehaviourDescription::MaterialProperty& mp) {
3068     if (mp.is<BehaviourDescription::ConstantMaterialProperty>()) {
3069       auto& cmp = mp.get<BehaviourDescription::ConstantMaterialProperty>();
3070       if (!(cmp.value > 0)) {
3071         tfel::raise("checkIsStrictlyPositive: material property '" + cmp.name +
3072                     "' is not strictly positive");
3073       }
3074     }
3075   }  // end of checkIsStrictlyPositive
3076 
checkIsStrictlyNegative(const BehaviourDescription::MaterialProperty & mp)3077   void checkIsStrictlyNegative(
3078       const BehaviourDescription::MaterialProperty& mp) {
3079     if (mp.is<BehaviourDescription::ConstantMaterialProperty>()) {
3080       auto& cmp = mp.get<BehaviourDescription::ConstantMaterialProperty>();
3081       if (!(cmp.value < 0)) {
3082         tfel::raise("checkIsStrictlyNegative: material property '" + cmp.name +
3083                     "' is not strictly negative");
3084       }
3085     }
3086   }  // end of checkIsStrictlyNegative
3087 
getParametersFileName(const BehaviourDescription & bd)3088   std::string getParametersFileName(const BehaviourDescription& bd){
3089     return bd.getClassName() + "-parameters.txt";
3090   }  // end of getParametersFileName
3091 
getParametersFileName(const BehaviourDescription & bd,const BehaviourDescription::Hypothesis h)3092   std::string getParametersFileName(const BehaviourDescription& bd,
3093                                    const BehaviourDescription::Hypothesis h) {
3094     const auto hn = BehaviourDescription::ModellingHypothesis::toString(h);
3095     return bd.getClassName() + hn + "-parameters.txt";
3096   }  // end of getParametersFileName
3097 
3098 }  // end of namespace mfront
3099