1 /*!
2  * \file   mfront/src/BehaviourDSLCommon.cxx
3  * \brief
4  *
5  * \author Thomas Helfer
6  * \date   05/05/2008
7  * \copyright Copyright (C) 2006-2018 CEA/DEN, EDF R&D. All rights
8  * reserved.
9  * This project is publicly released under either the GNU GPL Licence
10  * or the CECILL-A licence. A copy of thoses licences are delivered
11  * with the sources of TFEL. CEA or EDF may also distribute this
12  * project under specific licensing conditions.
13  */
14 
15 #include <algorithm>
16 #include <stdexcept>
17 #include <iterator>
18 #include <sstream>
19 #include <utility>
20 #include <vector>
21 #include <limits>
22 #include <cctype>
23 #include <cmath>
24 
25 #include "TFEL/Raise.hxx"
26 #include "TFEL/System/System.hxx"
27 #include "TFEL/UnicodeSupport/UnicodeSupport.hxx"
28 #include "TFEL/Glossary/Glossary.hxx"
29 #include "TFEL/Glossary/GlossaryEntry.hxx"
30 #include "TFEL/Math/General/IEEE754.hxx"
31 #include "TFEL/Material/FiniteStrainBehaviourTangentOperator.hxx"
32 #include "TFEL/Utilities/Data.hxx"
33 #include "TFEL/Utilities/StringAlgorithms.hxx"
34 #include "TFEL/Math/Evaluator.hxx"
35 
36 #include "MFront/MFront.hxx"
37 #include "MFront/MFrontHeader.hxx"
38 #include "MFront/DSLUtilities.hxx"
39 #include "MFront/MFrontUtilities.hxx"
40 #include "MFront/MFrontDebugMode.hxx"
41 #include "MFront/PedanticMode.hxx"
42 #include "MFront/MFrontLogStream.hxx"
43 #include "MFront/SearchPathsHandler.hxx"
44 #include "MFront/AbstractBehaviourInterface.hxx"
45 #include "MFront/MFrontMaterialPropertyInterface.hxx"
46 #include "MFront/PerformanceProfiling.hxx"
47 #include "MFront/BehaviourInterfaceFactory.hxx"
48 #include "MFront/FiniteStrainBehaviourTangentOperatorConversionPath.hxx"
49 #include "MFront/AbstractBehaviourBrick.hxx"
50 #include "MFront/BehaviourBrickFactory.hxx"
51 #include "MFront/TargetsDescription.hxx"
52 #include "MFront/MaterialPropertyDescription.hxx"
53 #include "MFront/ModelDSL.hxx"
54 #include "MFront/MFrontModelInterface.hxx"
55 #include "MFront/BehaviourDSLCommon.hxx"
56 #include "MFront/BehaviourBrick/Requirement.hxx"
57 #include "MFront/BehaviourBrick/RequirementManager.hxx"
58 
59 // fixing a bug on current glibc++ cygwin versions (19/08/2015)
60 #if defined __CYGWIN__ && (!defined _GLIBCXX_USE_C99)
61 #include <sstream>
62 namespace std {
63   template <typename T>
to_string(const T & v)64   std::string to_string(const T& v) {
65     std::ostringstream s;
66     s << v;
67     return s.str();
68   }
69 }
70 #endif /* defined __CYGWIN__ &&  (!defined _GLIBCXX_USE_C99) */
71 
72 #ifndef _MSC_VER
73 static const char* const constexpr_c = "constexpr";
74 #else
75 static const char* const constexpr_c = "const";
76 #endif
77 
78 namespace mfront {
79 
StandardVariableModifier(const Hypothesis h,const FunctionType f)80   BehaviourDSLCommon::StandardVariableModifier::StandardVariableModifier(
81       const Hypothesis h, const FunctionType f)
82       : hypothesis(h),
83         fct(f) {}  // end of StandardVariableModifier::StandardVariableModifier
84 
exe(const std::string & v,const bool b)85   std::string BehaviourDSLCommon::StandardVariableModifier::exe(
86       const std::string& v, const bool b) {
87     return (this->fct)(this->hypothesis, v, b);
88   }  // end of StandardVariableModifier::exe
89 
90   BehaviourDSLCommon::StandardVariableModifier::~StandardVariableModifier() =
91       default;
92 
StandardWordAnalyser(const Hypothesis h,const FunctionType f)93   BehaviourDSLCommon::StandardWordAnalyser::StandardWordAnalyser(
94       const Hypothesis h, const FunctionType f)
95       : hypothesis(h),
96         fct(f) {}  // end of StandardWordAnalyser::StandardWordAnalyser
97 
exe(CodeBlock & c,const std::string & v)98   void BehaviourDSLCommon::StandardWordAnalyser::exe(CodeBlock& c,
99                                                      const std::string& v) {
100     this->fct(c, this->hypothesis, v);
101   }  // end of StandardWordAnalyser::exe
102 
103   BehaviourDSLCommon::StandardWordAnalyser::~StandardWordAnalyser() = default;
104 
isValidBehaviourName(const std::string & n)105   bool isValidBehaviourName(const std::string& n) {
106     return tfel::utilities::CxxTokenizer::isValidIdentifier(n, false);
107   }
108 
BehaviourDSLCommon()109   BehaviourDSLCommon::BehaviourDSLCommon()
110       : useStateVarTimeDerivative(false), explicitlyDeclaredUsableInPurelyImplicitResolution(false) {
111     using MemberFunc = void (BehaviourDSLCommon::*)();
112     // By default disable use of quantities
113     this->mb.setUseQt(false);
114     // By default, a behaviour can be used in a purely implicit resolution
115     const auto h = ModellingHypothesis::UNDEFINEDHYPOTHESIS;
116     this->mb.setUsableInPurelyImplicitResolution(h, true);
117     // reserve names
118     for (const auto& v : DSLBase::getDefaultReservedNames()) {
119       this->mb.reserveName(h, v);
120     }
121     // register behaviours specific names
122     this->registerDefaultVarNames();
123     this->reserveName("minimal_time_step_scaling_factor");
124     this->reserveName("maximal_time_step_scaling_factor");
125     this->reserveName("current_time_step_scaling_factor");
126     // default call backs
127     auto add = [this](const std::string& k, const MemberFunc f) {
128       this->callBacks.insert({k, [this, f] { (this->*f)(); }});
129       this->registredKeyWords.insert(k);
130     };
131     add(";", &BehaviourDSLCommon::treatLonelySeparator);
132     add("@DSL", &BehaviourDSLCommon::treatParser);
133     add("@Parser", &BehaviourDSLCommon::treatParser);
134     add("@Model", &BehaviourDSLCommon::treatModel);
135     add("@Brick", &BehaviourDSLCommon::treatBrick);
136     add("@ModellingHypothesis", &BehaviourDSLCommon::treatModellingHypothesis);
137     add("@ModellingHypotheses", &BehaviourDSLCommon::treatModellingHypotheses);
138     add("@Import", &BehaviourDSLCommon::treatImport);
139     add("@Material", &BehaviourDSLCommon::treatMaterial);
140     add("@Library", &BehaviourDSLCommon::treatLibrary);
141     add("@Profiling", &BehaviourDSLCommon::treatProfiling);
142     add("@Behaviour", &BehaviourDSLCommon::treatBehaviour);
143     add("@StrainMeasure", &BehaviourDSLCommon::treatStrainMeasure);
144     add("@Author", &BehaviourDSLCommon::treatAuthor);
145     add("@Date", &BehaviourDSLCommon::treatDate);
146     add("@MFront", &BehaviourDSLCommon::treatMFront);
147     add("@Link", &BehaviourDSLCommon::treatLink);
148     add("@Includes", &BehaviourDSLCommon::treatIncludes);
149     add("@Members", &BehaviourDSLCommon::treatMembers);
150     add("@Coef", &BehaviourDSLCommon::treatCoef);
151     add("@MaterialProperty", &BehaviourDSLCommon::treatCoef);
152     add("@LocalVar", &BehaviourDSLCommon::treatLocalVar);
153     add("@LocalVariable", &BehaviourDSLCommon::treatLocalVar);
154     add("@Parameter", &BehaviourDSLCommon::treatParameter);
155     add("@StateVar", &BehaviourDSLCommon::treatStateVariable);
156     add("@StateVariable", &BehaviourDSLCommon::treatStateVariable);
157     add("@AuxiliaryStateVar", &BehaviourDSLCommon::treatAuxiliaryStateVariable);
158     add("@AuxiliaryStateVariable",
159         &BehaviourDSLCommon::treatAuxiliaryStateVariable);
160     add("@ExternalStateVar", &BehaviourDSLCommon::treatExternalStateVariable);
161     add("@ExternalStateVariable",
162         &BehaviourDSLCommon::treatExternalStateVariable);
163     add("@InitLocalVars", &BehaviourDSLCommon::treatInitLocalVariables);
164     add("@InitLocalVariables", &BehaviourDSLCommon::treatInitLocalVariables);
165     add("@InitializeLocalVariables",
166         &BehaviourDSLCommon::treatInitLocalVariables);
167     add("@MinimalTimeStepScalingFactor",
168         &BehaviourDSLCommon::treatMinimalTimeStepScalingFactor);
169     add("@MaximalTimeStepScalingFactor",
170         &BehaviourDSLCommon::treatMaximalTimeStepScalingFactor);
171     add("@APrioriTimeStepScalingFactor",
172         &BehaviourDSLCommon::treatAPrioriTimeStepScalingFactor);
173     add("@Integrator", &BehaviourDSLCommon::treatIntegrator);
174     add("@APosterioriTimeStepScalingFactor",
175         &BehaviourDSLCommon::treatAPosterioriTimeStepScalingFactor);
176     add("@Interface", &BehaviourDSLCommon::treatInterface);
177     add("@StaticVar", &BehaviourDSLCommon::treatStaticVar);
178     add("@StaticVariable", &BehaviourDSLCommon::treatStaticVar);
179     add("@IntegerConstant", &BehaviourDSLCommon::treatIntegerConstant);
180     add("@UseQt", &BehaviourDSLCommon::treatUseQt);
181     add("@Description", &BehaviourDSLCommon::treatDescription);
182     add("@Bounds", &BehaviourDSLCommon::treatBounds);
183     add("@PhysicalBounds", &BehaviourDSLCommon::treatPhysicalBounds);
184     add("@RequireStiffnessOperator",
185         &BehaviourDSLCommon::treatRequireStiffnessOperator);
186     add("@RequireStiffnessTensor",
187         &BehaviourDSLCommon::treatRequireStiffnessTensor);
188     add("@RequireThermalExpansionCoefficientTensor",
189         &BehaviourDSLCommon::treatRequireThermalExpansionCoefficientTensor);
190     add("@OrthotropicBehaviour",
191         &BehaviourDSLCommon::treatOrthotropicBehaviour);
192     add("@IsotropicElasticBehaviour",
193         &BehaviourDSLCommon::treatIsotropicElasticBehaviour);
194     add("@IsotropicBehaviour", &BehaviourDSLCommon::treatIsotropicBehaviour);
195     add("@PredictionOperator", &BehaviourDSLCommon::treatPredictionOperator);
196     add("@Private", &BehaviourDSLCommon::treatPrivate);
197     add("@Sources", &BehaviourDSLCommon::treatSources);
198     add("@UpdateAuxiliaryStateVars",
199         &BehaviourDSLCommon::treatUpdateAuxiliaryStateVariables);
200     add("@UpdateAuxiliaryStateVariables",
201         &BehaviourDSLCommon::treatUpdateAuxiliaryStateVariables);
202     add("@ComputeThermalExpansion",
203         &BehaviourDSLCommon::treatComputeThermalExpansion);
204     add("@ComputeStressFreeExpansion",
205         &BehaviourDSLCommon::treatComputeStressFreeExpansion);
206     add("@Swelling", &BehaviourDSLCommon::treatSwelling);
207     add("@AxialGrowth", &BehaviourDSLCommon::treatAxialGrowth);
208     add("@Relocation", &BehaviourDSLCommon::treatRelocation);
209     add("@InternalEnergy", &BehaviourDSLCommon::treatInternalEnergy);
210     add("@DissipatedEnergy", &BehaviourDSLCommon::treatDissipatedEnergy);
211     add("@CrystalStructure", &BehaviourDSLCommon::treatCrystalStructure);
212     add("@SlipSystem", &BehaviourDSLCommon::treatSlipSystem);
213     add("@GlidingSystem", &BehaviourDSLCommon::treatSlipSystem);
214     add("@SlidingSystem", &BehaviourDSLCommon::treatSlipSystem);
215     add("@SlipSystems", &BehaviourDSLCommon::treatSlipSystems);
216     add("@GlidingSystems", &BehaviourDSLCommon::treatSlipSystems);
217     add("@SlidingSystems", &BehaviourDSLCommon::treatSlipSystems);
218     add("@InteractionMatrix", &BehaviourDSLCommon::treatInteractionMatrix);
219     add("@DislocationsMeanFreePathInteractionMatrix",
220         &BehaviourDSLCommon::treatDislocationsMeanFreePathInteractionMatrix);
221   }  // end of BehaviourDSLCommon::BehaviourDSLCommon
222 
getMaterialKnowledgeIdentifier() const223   std::string BehaviourDSLCommon::getMaterialKnowledgeIdentifier() const {
224     if (this->mb.isBehaviourNameDefined()) {
225       return this->mb.getBehaviourName();
226     }
227     return {};
228   }  // end of BehaviourDSLCommon::getMaterialKnowledgeIdentifier
229 
getMaterialName() const230   std::string BehaviourDSLCommon::getMaterialName() const {
231     return this->mb.getMaterialName();
232   }  // end of BehaviourDSLCommon::getMaterialName(
233 
analyse()234   void BehaviourDSLCommon::analyse() {
235     const auto& mh = ModellingHypothesis::getModellingHypotheses();
236     std::vector<std::string> hn(mh.size());
237     std::vector<Hypothesis>::const_iterator pmh;
238     std::vector<std::string>::iterator phn;
239     for (pmh = mh.begin(), phn = hn.begin(); pmh != mh.end(); ++pmh, ++phn) {
240       *phn = ModellingHypothesis::toString(*pmh);
241     }
242     // strip comments from file
243     this->stripComments();
244     // begin treatement
245     this->current = this->tokens.begin();
246     while (this->current != this->tokens.end()) {
247       if (find(hn.begin(), hn.end(), this->current->value) != hn.end()) {
248         const auto h = ModellingHypothesis::fromString(this->current->value);
249         ++(this->current);
250         this->checkNotEndOfFile("BehaviourDSLCommon::analyse");
251         this->readSpecifiedToken("BehaviourDSLCommon::analyse", "::");
252         const auto v = tfel::unicode::getMangledString(this->current->value);
253         if (!this->isCallableVariable(h, v)) {
254           this->throwRuntimeError("BehaviourDSLCommon::analyse",
255                                   "no variable named '" + v +
256                                       "' for hypothesis '" +
257                                       ModellingHypothesis::toString(h) + "'");
258         }
259         if (this->mb.isParameterName(h, v)) {
260           this->treatParameterMethod(h);
261         } else {
262           this->treatVariableMethod(h);
263         }
264       } else {
265         const auto h = ModellingHypothesis::UNDEFINEDHYPOTHESIS;
266         const auto v = tfel::unicode::getMangledString(this->current->value);
267         if (this->isCallableVariable(h, v)) {
268           const auto isGradient = [this, &v] {
269             for (const auto& g : this->gradients) {
270               if (g.name == v) {
271                 return true;
272               }
273             }
274             return this->mb.isGradientName(v);
275           }();
276           const auto isThermodynamicForce = [this, &v] {
277             for (const auto& f : this->thermodynamic_forces) {
278               if (f.name == v) {
279                 return true;
280               }
281             }
282             return this->mb.isThermodynamicForceName(v);
283           }();
284           if (isGradient) {
285             this->treatGradientMethod();
286           } else if (isThermodynamicForce) {
287             this->treatThermodynamicForceMethod();
288           } else if (this->mb.isParameterName(h, v)) {
289             this->treatParameterMethod(h);
290           } else {
291             this->treatVariableMethod(h);
292           }
293         } else {
294           const auto k = this->current->value;
295           const auto l = this->current->line;
296           CallBack handler;
297           auto p = this->callBacks.find(k);
298           if (p == this->callBacks.end()) {
299             if (getVerboseMode() >= VERBOSE_DEBUG) {
300               auto& log = getLogStream();
301               log << "treating unknown keyword\n";
302             }
303             handler = [this] { this->treatUnknownKeyword(); };
304           } else {
305             if (getVerboseMode() >= VERBOSE_DEBUG) {
306               auto& log = getLogStream();
307               log << "treating keyword : " << this->current->value << '\n';
308             }
309             handler = p->second;
310           }
311           this->currentComment = this->current->comment;
312           ++(this->current);
313           try {
314             handler();
315             const auto ph = this->hooks.find(k);
316             if (ph != this->hooks.end()) {
317               for (auto& hook : ph->second) {
318                 hook();
319               }
320             }
321           } catch (std::exception& e) {
322             std::ostringstream msg;
323             msg << "BehaviourDSLCommon::analyse: "
324                 << "error while treating keyword '" << k << "' at line '" << l
325                 << "' of file '" << this->fd.fileName << "'.\n"
326                 << e.what();
327             tfel::raise(msg.str());
328           } catch (...) {
329             this->currentComment.clear();
330             throw;
331           }
332           this->currentComment.clear();
333         }
334       }
335     }
336   } // end of BehaviourDSLCommon::analyse
337 
importFile(const std::string & fn,const std::vector<std::string> & ecmds,const std::map<std::string,std::string> & s)338   void BehaviourDSLCommon::importFile(
339       const std::string& fn,
340       const std::vector<std::string>& ecmds,
341       const std::map<std::string, std::string>& s) {
342     this->fd.fileName = fn;
343     this->openFile(this->fd.fileName, ecmds, s);
344     this->analyse();
345   }  // end of BehaviourDSLCommon::importFile
346 
analyseString(const std::string & s)347   void BehaviourDSLCommon::analyseString(const std::string& s) {
348     this->fd.fileName = "user defined string";
349     this->parseString(s);
350     this->analyse();
351   }  // end of BehaviourDSLCommon::analyseString
352 
getKeywordsList(std::vector<std::string> & k) const353   void BehaviourDSLCommon::getKeywordsList(
354       std::vector<std::string>& k) const {
355     for (const auto& c : this->callBacks) {
356       k.push_back(c.first);
357     }
358   }  // end of BehaviourDSLCommon::getKeywordsList
359 
addCallBack(const std::string & k,const CallBack c)360   void BehaviourDSLCommon::addCallBack(const std::string& k, const CallBack c) {
361     this->callBacks.insert({k, c});
362     this->registredKeyWords.insert(k);
363   }  // end of BehaviourDSLCommon::addCallBack
364 
addHook(const std::string & k,const Hook h)365   void BehaviourDSLCommon::addHook(const std::string& k, const Hook h) {
366     if (this->callBacks.find(k) == this->callBacks.end()) {
367       this->throwRuntimeError("BehaviourDSLCommon::addHook",
368                               "no callback called '" + k + "'");
369     }
370     this->hooks[k].push_back(h);
371   }  // end of BehaviourDSLCommon::addHook
372 
setMaterial(const std::string & m)373   void BehaviourDSLCommon::setMaterial(const std::string& m) {
374     if (!isValidMaterialName(m)) {
375       this->throwRuntimeError("BehaviourDSLCommon::setMaterial",
376                               "invalid material name '" + m + "'");
377     }
378     this->mb.setMaterialName(m);
379     if (!isValidIdentifier(this->mb.getClassName())) {
380       this->throwRuntimeError("BehaviourDSLCommon::setMaterial",
381                               "resulting class name is not valid (read '" +
382                                   this->mb.getClassName() + "')");
383     }
384   }  // end of BehaviourDSLCommon::setMaterial
385 
386 
treatDisabledCallBack()387   void BehaviourDSLCommon::treatDisabledCallBack() {
388     --(this->current);
389     tfel::raise("The keyword: '" + this->current->value +
390                 "' has been disabled");
391   }  // end of treatDisabledCallBack
392 
disableCallBack(const std::string & k)393   void BehaviourDSLCommon::disableCallBack(const std::string& k) {
394     auto c = [this] { this->treatDisabledCallBack(); };
395     auto p = this->callBacks.find(k);
396     if (p == this->callBacks.end()) {
397       this->callBacks.insert({k, c});
398       this->registredKeyWords.insert(k);
399       return;
400     }
401     p->second = c;
402   }  // end of disableCallBack
403 
readCodeBlock(const std::string & n,std::function<std::string (const Hypothesis,const std::string &,const bool)> m,const bool b,const bool s)404   BehaviourDSLCommon::CodeBlockOptions BehaviourDSLCommon::readCodeBlock(
405       const std::string& n,
406       std::function<
407           std::string(const Hypothesis, const std::string&, const bool)> m,
408       const bool b,
409       const bool s) {
410     CodeBlockOptions o;
411     this->readCodeBlockOptions(o, s);
412     this->treatUnsupportedCodeBlockOptions(o);
413     this->readCodeBlock(o, n, m, b);
414     return o;
415   }
416 
readCodeBlock(const std::string & n,std::function<std::string (const Hypothesis,const std::string &,const bool)> m,std::function<void (CodeBlock &,const Hypothesis,const std::string &)> a,const bool b,const bool s)417   BehaviourDSLCommon::CodeBlockOptions BehaviourDSLCommon::readCodeBlock(
418       const std::string& n,
419       std::function<
420           std::string(const Hypothesis, const std::string&, const bool)> m,
421       std::function<void(CodeBlock&, const Hypothesis, const std::string&)> a,
422       const bool b,
423       const bool s) {
424     CodeBlockOptions o;
425     this->readCodeBlockOptions(o, s);
426     this->treatUnsupportedCodeBlockOptions(o);
427     this->readCodeBlock(o, n, m, a, b);
428     return o;
429   }  // end of BehaviourDSLCommon::readCodeBlock
430 
readCodeBlock(const BehaviourDSLCommon::CodeBlockOptions & o,const std::string & n,std::function<std::string (const Hypothesis,const std::string &,const bool)> m,std::function<void (CodeBlock &,const Hypothesis,const std::string &)> a,const bool b)431   void BehaviourDSLCommon::readCodeBlock(
432       const BehaviourDSLCommon::CodeBlockOptions& o,
433       const std::string& n,
434       std::function<
435           std::string(const Hypothesis, const std::string&, const bool)> m,
436       std::function<void(CodeBlock&, const Hypothesis, const std::string&)> a,
437       const bool b) {
438     const auto beg = this->current;
439     this->disableVariableDeclaration();
440     for (const auto h : o.hypotheses) {
441       this->current = beg;
442       const auto& md = this->mb.getBehaviourData(h);
443       auto vm = std::make_shared<StandardVariableModifier>(h, m);
444       auto wa = std::make_shared<StandardWordAnalyser>(h, a);
445       CodeBlockParserOptions option;
446       option.qualifyStaticVariables = b;
447       option.qualifyMemberVariables = b;
448       option.modifier = vm;
449       option.analyser = wa;
450       option.mn = md.getRegistredMembersNames();
451       option.smn = md.getRegistredStaticMembersNames();
452       this->getSymbols(option.symbols, h, n);
453       const auto& c = this->readNextBlock(option);
454       this->mb.setCode(h, n, c, o.m, o.p);
455     }
456   }  // end of BehaviourDSLCommon::readCodeBlock
457 
readCodeBlock(const BehaviourDSLCommon::CodeBlockOptions & o,const std::string & n,std::function<std::string (const Hypothesis,const std::string &,const bool)> m,const bool b)458   void BehaviourDSLCommon::readCodeBlock(
459       const BehaviourDSLCommon::CodeBlockOptions& o,
460       const std::string& n,
461       std::function<
462           std::string(const Hypothesis, const std::string&, const bool)> m,
463       const bool b) {
464     const auto beg = this->current;
465     this->disableVariableDeclaration();
466     for (const auto h : o.hypotheses) {
467       const auto& md = this->mb.getBehaviourData(h);
468       this->current = beg;
469       auto vm = std::make_shared<StandardVariableModifier>(h, m);
470       CodeBlockParserOptions option;
471       option.qualifyStaticVariables = b;
472       option.qualifyMemberVariables = b;
473       option.modifier = vm;
474       option.mn = md.getRegistredMembersNames();
475       option.smn = md.getRegistredStaticMembersNames();
476       this->getSymbols(option.symbols, h, n);
477       const auto& c = this->readNextBlock(option);
478       this->mb.setCode(h, n, c, o.m, o.p);
479     }
480   }  // end of BehaviourDSLCommon::readCodeBlock
481 
readCodeBlock(const std::string & n1,const std::string & n2,std::function<std::string (const Hypothesis,const std::string &,const bool)> m1,std::function<std::string (const Hypothesis,const std::string &,const bool)> m2,const bool b,const bool s)482   BehaviourDSLCommon::CodeBlockOptions BehaviourDSLCommon::readCodeBlock(
483       const std::string& n1,
484       const std::string& n2,
485       std::function<
486           std::string(const Hypothesis, const std::string&, const bool)> m1,
487       std::function<
488           std::string(const Hypothesis, const std::string&, const bool)> m2,
489       const bool b,
490       const bool s) {
491     using std::shared_ptr;
492     CodeBlockOptions o;
493     this->readCodeBlockOptions(o, s);
494     this->treatUnsupportedCodeBlockOptions(o);
495     this->readCodeBlock(o, n1, n2, m1, m2, b);
496     return o;
497   }  // end of BehaviourDSLCommon::readCodeBlock
498 
readCodeBlock(const BehaviourDSLCommon::CodeBlockOptions & o,const std::string & n1,const std::string & n2,std::function<std::string (const Hypothesis,const std::string &,const bool)> m1,std::function<std::string (const Hypothesis,const std::string &,const bool)> m2,const bool b)499   void BehaviourDSLCommon::readCodeBlock(
500       const BehaviourDSLCommon::CodeBlockOptions& o,
501       const std::string& n1,
502       const std::string& n2,
503       std::function<
504           std::string(const Hypothesis, const std::string&, const bool)> m1,
505       std::function<
506           std::string(const Hypothesis, const std::string&, const bool)> m2,
507       const bool b) {
508     const auto beg = this->current;
509     this->disableVariableDeclaration();
510     for (const auto& h : o.hypotheses) {
511       const auto& md = this->mb.getBehaviourData(h);
512       this->current = beg;
513       CodeBlock c1;
514       CodeBlock c2;
515       CodeBlockParserOptions o1;
516       o1.qualifyStaticVariables = b;
517       o1.qualifyMemberVariables = b;
518       o1.modifier = std::make_shared<StandardVariableModifier>(h, m1);
519       o1.mn = md.getRegistredMembersNames();
520       o1.smn = md.getRegistredStaticMembersNames();
521       this->getSymbols(o1.symbols, h, n1);
522       CodeBlockParserOptions o2;
523       o2.qualifyStaticVariables = b;
524       o2.qualifyMemberVariables = b;
525       o2.modifier = std::make_shared<StandardVariableModifier>(h, m2);
526       o2.mn = md.getRegistredMembersNames();
527       o2.smn = md.getRegistredStaticMembersNames();
528       this->getSymbols(o2.symbols, h, n1);
529       this->readNextBlock(c1, c2, o1, o2);
530       this->mb.setCode(h, n1, c1, o.m, o.p);
531       this->mb.setCode(h, n2, c2, o.m, o.p);
532     }
533   }  // end of BehaviourDSLCommon::readCodeBlock
534 
addMaterialProperties(const VariableDescriptionContainer & mps)535   void BehaviourDSLCommon::addMaterialProperties(
536       const VariableDescriptionContainer& mps) {
537     constexpr const auto h = ModellingHypothesis::UNDEFINEDHYPOTHESIS;
538     const auto d = this->getBehaviourDSLDescription();
539     tfel::raise_if(!d.allowUserDefinedMaterialProperties,
540                    "BehaviourDSLCommon::addMaterialProperties: "
541                    "adding material properties is not allowed");
542     this->mb.addMaterialProperties(h, mps);
543   }  // end of BehaviourDSLCommon::addMaterialProperties
544 
addParameters(const VariableDescriptionContainer & params)545   void BehaviourDSLCommon::addParameters(
546       const VariableDescriptionContainer& params) {
547     constexpr const auto h = ModellingHypothesis::UNDEFINEDHYPOTHESIS;
548     const auto d = this->getBehaviourDSLDescription();
549     tfel::raise_if(!d.allowUserDefinedParameters,
550                    "BehaviourDSLCommon::addParameters: "
551                    "adding parameters is not allowed");
552     this->mb.addParameters(h, params);
553   }  // end of BehaviourDSLCommon::addParameters
554 
addStateVariables(const VariableDescriptionContainer & isvs)555   void BehaviourDSLCommon::addStateVariables(
556       const VariableDescriptionContainer& isvs) {
557     constexpr const auto h = ModellingHypothesis::UNDEFINEDHYPOTHESIS;
558     const auto d = this->getBehaviourDSLDescription();
559     tfel::raise_if(!d.allowUserDefinedStateVariables,
560                    "BehaviourDSLCommon::addStateVariables: "
561                    "adding state variables is not allowed");
562     this->mb.addStateVariables(h, isvs);
563   }  // end of BehaviourDSLCommon::addStateVariables
564 
addAuxiliaryStateVariables(const VariableDescriptionContainer & isvs)565   void BehaviourDSLCommon::addAuxiliaryStateVariables(
566       const VariableDescriptionContainer& isvs) {
567     constexpr const auto h = ModellingHypothesis::UNDEFINEDHYPOTHESIS;
568     const auto d = this->getBehaviourDSLDescription();
569     tfel::raise_if(!d.allowUserDefinedAuxiliaryStateVariables,
570                    "BehaviourDSLCommon::addAuxiliaryStateVariables: "
571                    "adding auxiliary state variables is not allowed");
572     this->mb.addAuxiliaryStateVariables(h, isvs);
573   }  // end of BehaviourDSLCommon::addAuxiliaryStateVariables
574 
addExternalStateVariables(const VariableDescriptionContainer & esvs)575   void BehaviourDSLCommon::addExternalStateVariables(
576       const VariableDescriptionContainer& esvs) {
577     constexpr const auto h = ModellingHypothesis::UNDEFINEDHYPOTHESIS;
578     const auto d = this->getBehaviourDSLDescription();
579     tfel::raise_if(!d.allowUserDefinedExternalStateVariables,
580                    "BehaviourDSLCommon::addExternalStateVariables: "
581                    "adding external state variables is not allowed");
582     this->mb.addExternalStateVariables(h, esvs);
583   }  // end of BehaviourDSLCommon::addExternalStateVariables
584 
addLocalVariables(const VariableDescriptionContainer & lvs)585   void BehaviourDSLCommon::addLocalVariables(
586       const VariableDescriptionContainer& lvs) {
587     constexpr const auto h = ModellingHypothesis::UNDEFINEDHYPOTHESIS;
588     const auto d = this->getBehaviourDSLDescription();
589     tfel::raise_if(!d.allowUserDefinedLocalVariables,
590                    "BehaviourDSLCommon::addLocalVariables: "
591                    "adding local variables is not allowed");
592     this->mb.addLocalVariables(h, lvs);
593   }  // end of BehaviourDSLCommon::addLocalVariables
594 
addIntegrationVariables(const VariableDescriptionContainer & ivs)595   void BehaviourDSLCommon::addIntegrationVariables(
596       const VariableDescriptionContainer& ivs) {
597     constexpr const auto h = ModellingHypothesis::UNDEFINEDHYPOTHESIS;
598     const auto d = this->getBehaviourDSLDescription();
599     tfel::raise_if(!d.allowUserDefinedIntegrationVariables,
600                    "BehaviourDSLCommon::addIntegrationVariables: "
601                    "adding integration variables is not allowed");
602     this->mb.addIntegrationVariables(h, ivs);
603   }  // end of BehaviourDSLCommon::addIntegrationVariables
604 
writeModelCall(std::ostream & out,std::vector<std::string> & tmpnames,const Hypothesis h,const ModelDescription & md,const std::string & vo,const std::string & vs,const std::string & bn) const605   void BehaviourDSLCommon::writeModelCall(std::ostream& out,
606                                           std::vector<std::string>& tmpnames,
607                                           const Hypothesis h,
608                                           const ModelDescription& md,
609                                           const std::string& vo,
610                                           const std::string& vs,
611                                           const std::string& bn) const {
612     auto throw_if = [this](const bool b, const std::string& m) {
613       if (b) {
614         this->throwRuntimeError("BehaviourDSLCommon::writeModelCall", m);
615       }
616     };
617     auto write_variable = [throw_if, &md, &out](const std::string& v, const unsigned short d) {
618       if (d == 0) {
619         out << "this->" << v << "+this->d" << v;
620       } else if (d == 1) {
621         out << "this->" << v;
622       } else {
623         throw_if(true, "invalid depth for the temperature '" + v +
624                            "' "
625                            "in model '" +
626                            md.className + "'");
627       }
628     };
629     const auto& bd = this->mb.getBehaviourData(h);
630     throw_if(md.outputs.size() != 1u, "invalid number of outputs for model '" + md.className + "'");
631     throw_if(!md.constantMaterialProperties.empty(), "constant material properties are not supported yet");
632     throw_if(md.functions.size() != 1u, "invalid number of functions in model '" + md.className + "'");
633     const auto& f = md.functions[0];
634     throw_if(f.modifiedVariables.empty(), "no modified variable for function '" + f.name + "'");
635     throw_if(f.modifiedVariables.size() != 1u, "invalid number of functions in model '" + md.className + "'");
636     throw_if(f.name.empty(), "unnamed function");
637     throw_if((f.usedVariables.empty()) && (!f.useTimeIncrement), "no used variable for function '" + f.name + "'");
638     const auto sm = this->getTemporaryVariableName(tmpnames, bn);
639     out << "// updating " << vs << "\n"
640         << "mfront::" << md.className << "<Type> " << sm << ";\n"
641         << "" << sm << ".setOutOfBoundsPolicy(this->policy);\n"
642         << "this->" << vo << " = " << sm << "." << f.name << "(";
643     const auto args = [&f] {
644       auto a = std::vector<std::string>{};
645       for (const auto& uv : f.usedVariables) {
646         a.push_back(uv);
647       }
648       if (f.useTimeIncrement) {
649         a.emplace_back("dt");
650       }
651       return a;
652     }();
653     const auto asvn = bd.getExternalNames(bd.getAuxiliaryStateVariables());
654     for (auto pa = std::begin(args); pa != std::end(args);) {
655       if (*pa == "dt") {
656         out << "this->dt";
657         ++pa;
658         continue;
659       }
660       const auto a = md.decomposeVariableName(*pa);
661       const auto& ea = md.getVariableDescription(a.first).getExternalName();
662       if (ea == bd.getExternalName(vs)) {
663         throw_if(a.second != 1, "invalid depth for variable '" + a.first +
664                                     "' "
665                                     "in model '" +
666                                     md.className + "'");
667         out << "this->" << vs;
668       } else if (std::find(std::begin(asvn), std::end(asvn), ea) != std::end(asvn)) {
669         const auto& av = bd.getAuxiliaryStateVariableDescriptionByExternalName(ea);
670         throw_if(!av.getAttribute<bool>("ComputedByExternalModel", false),
671                  "only auxiliary state variable computed by a model are allowed here");
672         write_variable(av.name, a.second);
673       } else {
674         const auto& en = bd.getExternalStateVariableDescriptionByExternalName(ea);
675         write_variable(en.name, a.second);
676       }
677       if (++pa != std::end(args)) {
678         out << ",";
679       }
680     }
681     out << ");\n";
682   }
683 
CodeBlockOptions()684   BehaviourDSLCommon::CodeBlockOptions::CodeBlockOptions() : p(BehaviourData::BODY), m(BehaviourData::CREATE) {
685     this->hypotheses.insert(ModellingHypothesis::UNDEFINEDHYPOTHESIS);
686   }  // end of BehaviourDSLCommon::CodeBlockOptions::CodeBlockOptions
687 
688   BehaviourDSLCommon::CodeBlockOptions::~CodeBlockOptions() = default;
689 
getBehaviourDescription() const690   const BehaviourDescription& BehaviourDSLCommon::getBehaviourDescription() const {
691     return this->mb;
692   }  // end of BehaviourDSLCommon::getBehaviourDescription
693 
getClassName() const694   std::string BehaviourDSLCommon::getClassName() const {
695     return this->mb.getClassName();
696   }  // end of BehaviourDSLCommon::getClassName
697 
addMaterialLaw(const std::string & m)698   void BehaviourDSLCommon::addMaterialLaw(const std::string& m) {
699     this->mb.addMaterialLaw(m);
700   }  // end of BehaviourDSLCommon::addMaterialLaw
701 
appendToIncludes(const std::string & c)702   void BehaviourDSLCommon::appendToIncludes(const std::string& c) {
703     this->mb.appendToIncludes(c);
704   }  // end of BehaviourDSLCommon::appendToIncludes
705 
appendToMembers(const std::string & c)706   void BehaviourDSLCommon::appendToMembers(const std::string& c) {
707     this->mb.appendToMembers(ModellingHypothesis::UNDEFINEDHYPOTHESIS, c, true);
708   }  // end of BehaviourDSLCommon::appendToMembers
709 
appendToPrivateCode(const std::string & c)710   void BehaviourDSLCommon::appendToPrivateCode(const std::string& c) {
711     this->mb.appendToPrivateCode(ModellingHypothesis::UNDEFINEDHYPOTHESIS, c, true);
712   }  // end of BehaviourDSLCommon::appendToPrivateCode
713 
appendToSources(const std::string & c)714   void BehaviourDSLCommon::appendToSources(const std::string& c) {
715     this->mb.appendToSources(c);
716   }  // end of BehaviourDSLCommon::appendToSources
717 
appendToHypothesesList(std::set<Hypothesis> & h,const std::string & v) const718   void BehaviourDSLCommon::appendToHypothesesList(std::set<Hypothesis>& h, const std::string& v) const {
719     if (v == ".+") {
720       const auto& ash = ModellingHypothesis::getModellingHypotheses();
721       for (const auto& lh : ash) {
722         this->appendToHypothesesList(h, ModellingHypothesis::toString(lh));
723       }
724     } else {
725       const auto nh = ModellingHypothesis::fromString(v);
726       if (!this->isModellingHypothesisSupported(nh)) {
727         this->throwRuntimeError("BehaviourDSLCommon::appendToHypothesesList",
728                                 "hypothesis '" + v + "' is not supported by this parser");
729       }
730       if (this->mb.areModellingHypothesesDefined()) {
731         const auto& bh = this->mb.getModellingHypotheses();
732         if (bh.find(nh) == bh.end()) {
733           this->throwRuntimeError("BehaviourDSLCommon::appendToHypothesesList",
734                                   "hypothesis '" + v +
735                                       "' is not supported by the "
736                                       "behaviour (This means that one of the "
737                                       "'@ModellingHypothesis' or '@ModellingHypotheses'"
738                                       "keyword was used earlier)");
739         }
740       }
741       if (!h.insert(nh).second) {
742         this->throwRuntimeError("BehaviourDSLCommon::appendToHypothesesList",
743                                 "hypothesis '" + v + "' multiply defined");
744       }
745     }
746   }  // end of BehaviourDSLCommon::appendToHypothesesList
747 
getSymbols(std::map<std::string,std::string> & symbols,const Hypothesis h,const std::string &)748   void BehaviourDSLCommon::getSymbols(
749       std::map<std::string, std::string>& symbols,
750       const Hypothesis h,
751       const std::string&) {
752     addSymbol(symbols, "I\u2082", "Stensor::Id()");
753     addSymbol(symbols, "I\u2084", "Stensor4::Id()");
754     addSymbol(symbols, "\u2297", "^");
755     addSymbol(symbols, "\u22C5", "*");
756     this->mb.getSymbols(symbols, h);
757   }  // end of BehaviourDSLCommon::getSymbols
758 
readCodeBlockOptions(CodeBlockOptions & o,const bool s)759   void BehaviourDSLCommon::readCodeBlockOptions(CodeBlockOptions& o, const bool s) {
760     using namespace tfel::utilities;
761     using namespace tfel::material;
762     auto cposition = false;
763     auto cmode = false;
764     const auto dh = [this] {
765       if (this->mb.areModellingHypothesesDefined()) {
766         const auto mh = this->mb.getModellingHypotheses();
767         if (mh.size() == 1) {
768           return *(mh.begin());
769         }
770       }
771       return ModellingHypothesis::UNDEFINEDHYPOTHESIS;
772     }();
773     o.hypotheses.clear();
774     if (this->current == this->tokens.end()) {
775       o.hypotheses.insert(dh);
776       return;
777     }
778     if (this->current->value != "<") {
779       o.hypotheses.insert(dh);
780       return;
781     }
782     auto options = std::vector<Token>{};
783     this->readList(options, "BehaviourDSLCommon::readCodeBlockOptions", "<", ">", true);
784     for (const auto& t : options) {
785       if (t.value == "Append") {
786         if (cmode) {
787           this->throwRuntimeError("BehaviourDSLCommon::readCodeBlockOptions",
788                                   "insertion mode already specificed");
789         }
790         cmode = true;
791         o.m = BehaviourData::CREATEORAPPEND;
792       } else if (t.value == "Replace") {
793         if (cmode) {
794           this->throwRuntimeError("BehaviourDSLCommon::readCodeBlockOptions",
795                                   "insertion mode already specificed");
796         }
797         cmode = true;
798         o.m = BehaviourData::CREATEORREPLACE;
799       } else if (t.value == "Create") {
800         if (cmode) {
801           this->throwRuntimeError("BehaviourDSLCommon::readCodeBlockOptions",
802                                   "insertion mode already specificed");
803         }
804         cmode = true;
805         o.m = BehaviourData::CREATE;
806       } else if (t.value == "Body") {
807         if (cposition) {
808           this->throwRuntimeError("BehaviourDSLCommon::readCodeBlockOptions",
809                                   "insertion position already specificed");
810         }
811         cposition = true;
812         o.p = BehaviourData::BODY;
813       } else if (t.value == "AtBeginning") {
814         if (cposition) {
815           this->throwRuntimeError("BehaviourDSLCommon::readCodeBlockOptions",
816                                   "insertion position already specificed");
817         }
818         cposition = true;
819         o.p = BehaviourData::AT_BEGINNING;
820       } else if (t.value == "AtEnd") {
821         if (cposition) {
822           this->throwRuntimeError("BehaviourDSLCommon::readCodeBlockOptions",
823                                   "insertion position already specificed");
824         }
825         cposition = true;
826         o.p = BehaviourData::AT_END;
827       } else if ((t.flag == Token::String) && (t.value.substr(1, t.value.size() - 2) == "+")) {
828         this->appendToHypothesesList(o.hypotheses, t.value.substr(1, t.value.size() - 2));
829       } else if (ModellingHypothesis::isModellingHypothesis(t.value)) {
830         this->appendToHypothesesList(o.hypotheses, t.value);
831       } else {
832         o.untreated.push_back(t);
833       }
834     }
835     if (o.hypotheses.empty()) {
836       o.hypotheses.insert(dh);
837     }
838     // checks
839     if (!s) {
840       if (o.hypotheses.size() != 1u) {
841         this->throwRuntimeError("BehaviourDSLCommon::readCodeBlockOptions: ",
842                                 "specialisation is not allowed");
843       }
844       if (*(o.hypotheses.begin()) != dh) {
845         this->throwRuntimeError("BehaviourDSLCommon::readCodeBlockOptions: ",
846                                 "specialisation is not allowed");
847       }
848     }
849   }  // end of BehaviourDSLCommon::readCodeBlockOptions
850 
851   std::shared_ptr<MaterialPropertyDescription>
handleMaterialPropertyDescription(const std::string & f)852   BehaviourDSLCommon::handleMaterialPropertyDescription(const std::string& f) {
853     return DSLBase::handleMaterialPropertyDescription(f);
854   }  // end of BehaviourDSLCommon::handleMaterialPropertyDescription
855 
getModelDescription(const std::string & f)856   ModelDescription BehaviourDSLCommon::getModelDescription(const std::string& f) {
857     if (getVerboseMode() >= VERBOSE_DEBUG) {
858       getLogStream() << "BehaviourDSLCommon::getModelDescription: "
859                      << "treating file '" << f << "'\n";
860     }
861     // getting informations the source files
862     const auto path = SearchPathsHandler::search(f);
863     ModelDSL dsl;
864     try {
865       dsl.setInterfaces({"mfront"});
866       dsl.analyseFile(path, {}, {});
867       const auto t = dsl.getTargetsDescription();
868       if (!t.specific_targets.empty()) {
869         this->throwRuntimeError("BehaviourDSLCommon::getModelDescription",
870                                 "error while treating file '" + f +
871                                     "'.\n"
872                                     "Specific targets are not supported");
873       }
874       for (const auto& h : t.headers) {
875         this->appendToIncludes("#include\"" + h + "\"");
876       }
877       this->atds.push_back(std::move(t));
878       this->externalMFrontFiles.insert({path, {"mfront"}});
879     } catch (std::exception& e) {
880       this->throwRuntimeError("BehaviourDSLCommon::getModelDescription",
881                               "error while treating file '" + f + "'\n" + std::string(e.what()));
882     } catch (...) {
883       this->throwRuntimeError("BehaviourDSLCommon::getModelDescription", "error while treating file '" + f + "'");
884     }
885     const auto& md = dsl.getModelDescription();
886     this->reserveName(md.className);
887     if (getVerboseMode() >= VERBOSE_DEBUG) {
888       getLogStream() << "BehaviourDSLCommon::getModelDescription: "
889                      << "end of file '" << f << "' treatment\n";
890     }
891     return md;
892   }  // end of BehaviourDSLCommon::getModelDescription
893 
declareMainVariables()894   void BehaviourDSLCommon::declareMainVariables() {
895     decltype(this->gradients.size()) n =
896         std::min(this->gradients.size(), this->thermodynamic_forces.size());
897     while (n != 0) {
898       this->mb.addMainVariable(this->gradients.front(),
899                                this->thermodynamic_forces.front());
900       this->gradients.erase(this->gradients.begin());
901       this->thermodynamic_forces.erase(this->thermodynamic_forces.begin());
902       --n;
903     }
904   }  // end of BehaviourDSLCommon::declareMainVariables
905 
treatGradient()906   void BehaviourDSLCommon::treatGradient() {
907     VariableDescriptionContainer ngradients;
908     this->readVarList(ngradients, true);
909     std::for_each(ngradients.begin(), ngradients.end(),
910                   [this](const VariableDescription& v) {
911                     Gradient g(v);
912                     Gradient::setIsIncrementKnownAttribute(g, true);
913                     this->gradients.emplace_back(std::move(g));
914                   });
915     this->declareMainVariables();
916   }  // end of BehaviourDSLCommon::treatGradient
917 
treatThermodynamicForce()918   void BehaviourDSLCommon::treatThermodynamicForce() {
919     VariableDescriptionContainer ntfs;
920     this->readVarList(ntfs, true);
921     std::for_each(ntfs.begin(), ntfs.end(),
922                   [this](const VariableDescription& f) {
923                     this->thermodynamic_forces.emplace_back(f);
924                   });
925     this->declareMainVariables();
926   }  // end of BehaviourDSLCommon::treatThermodynamicForce
927 
treatTangentOperatorBlock()928   void BehaviourDSLCommon::treatTangentOperatorBlock() {
929     const char* const m =
930         "BehaviourDSLCommon::treatTangentOperatorBlock";
931     this->checkNotEndOfFile(m);
932     const auto b = this->current->value;
933     ++(this->current);
934     this->checkNotEndOfFile(m);
935     this->readSpecifiedToken(m, ";");
936     this->mb.setTangentOperatorBlocks(std::vector<std::string>(1u, b));
937   }  // end of BehaviourDSLCommon::treatTangentOperatorBlock
938 
treatTangentOperatorBlocks()939   void BehaviourDSLCommon::treatTangentOperatorBlocks() {
940     const char* const m =
941         "BehaviourDSLCommon::treatTangentOperatorBlocks";
942     this->checkNotEndOfFile(m);
943     auto values = std::vector<tfel::utilities::Token>{};
944     this->checkNotEndOfFile(m);
945     this->readList(values, m, "{", "}", false);
946     this->checkNotEndOfFile(m);
947     this->readSpecifiedToken(m, ";");
948     auto blocks = std::vector<std::string>{};
949     for (const auto& v : values) {
950       blocks.push_back(v.value);
951     }
952     this->mb.setTangentOperatorBlocks(blocks);
953   }  // end of BehaviourDSLCommon::treatTangentOperatorBlocks
954 
treatAdditionalTangentOperatorBlock()955   void BehaviourDSLCommon::treatAdditionalTangentOperatorBlock() {
956     const char* const m =
957         "BehaviourDSLCommon::treatAdditionalTangentOperatorBlock";
958     this->checkNotEndOfFile(m);
959     const auto b = this->current->value;
960     ++(this->current);
961     this->checkNotEndOfFile(m);
962     this->readSpecifiedToken(m, ";");
963     this->mb.addTangentOperatorBlock(b);
964   }  // end of BehaviourDSLCommon::treatAdditionalTangentOperatorBlock
965 
treatAdditionalTangentOperatorBlocks()966   void BehaviourDSLCommon::treatAdditionalTangentOperatorBlocks() {
967     const char* const m =
968         "BehaviourDSLCommon::treatAdditionalTangentOperatorBlocks";
969     this->checkNotEndOfFile(m);
970     auto values = std::vector<tfel::utilities::Token>{};
971     this->checkNotEndOfFile(m);
972     this->readList(values, m, "{", "}", false);
973     this->checkNotEndOfFile(m);
974     this->readSpecifiedToken(m, ";");
975     for (const auto& v : values) {
976       this->mb.addTangentOperatorBlock(v.value);
977     }
978   }  // end of BehaviourDSLCommon::treatAdditionalTangentOperatorBlock
979 
treatModel()980   void BehaviourDSLCommon::treatModel() {
981     if (getVerboseMode() >= VERBOSE_DEBUG) {
982       getLogStream() << "BehaviourDSLCommon::treatModel: begin\n";
983     }
984     auto md = this->getModelDescription(this->readString("BehaviourDSLCommon::treatModel"));
985     this->mb.addModelDescription(md);
986     if (getVerboseMode() >= VERBOSE_DEBUG) {
987       getLogStream() << "BehaviourDSLCommon::treatModel: end\n";
988     }
989     this->readSpecifiedToken("BehaviourDSLCommon::treatModel", ";");
990   }  // end of BehaviourDSLCommon::treatModel
991 
treatUnsupportedCodeBlockOptions(const CodeBlockOptions & o)992   void BehaviourDSLCommon::treatUnsupportedCodeBlockOptions(const CodeBlockOptions& o) {
993     if (o.untreated.empty()) {
994       return;
995     }
996     std::ostringstream msg;
997     if (o.untreated.size() == 1u) {
998       msg << "option '" << o.untreated[0].value << "' is invalid";
999     } else {
1000       msg << "the";
1001       for (const auto& opt : o.untreated) {
1002         msg << " '" << opt.value << "'";
1003       }
1004       msg << " options are invalid";
1005     }
1006     this->throwRuntimeError(
1007         "BehaviourDSLCommon::"
1008         "treatUnsupportedCodeBlockOptions",
1009         msg.str());
1010   }  // end of BehaviourDSLCommon::treatUnsupportedCodeBlockOptions
1011 
addStaticVariableDescription(const StaticVariableDescription & v)1012   void BehaviourDSLCommon::addStaticVariableDescription(const StaticVariableDescription& v) {
1013     this->mb.addStaticVariable(ModellingHypothesis::UNDEFINEDHYPOTHESIS, v);
1014   }  // end of BehaviourDSLCommon::addStaticVariableDescription
1015 
getIntegerConstant(const std::string & n) const1016   int BehaviourDSLCommon::getIntegerConstant(const std::string& n) const {
1017     return this->mb.getIntegerConstant(ModellingHypothesis::UNDEFINEDHYPOTHESIS, n);
1018   }  // end of BehaviourDSLCommon::getIntegerConstant
1019 
getDefaultModellingHypotheses() const1020   std::set<BehaviourDSLCommon::Hypothesis> BehaviourDSLCommon::getDefaultModellingHypotheses() const {
1021     // see the method documentation
1022     return {ModellingHypothesis::AXISYMMETRICALGENERALISEDPLANESTRAIN,
1023             ModellingHypothesis::AXISYMMETRICAL,
1024             ModellingHypothesis::PLANESTRAIN,
1025             ModellingHypothesis::GENERALISEDPLANESTRAIN,
1026             ModellingHypothesis::TRIDIMENSIONAL};
1027   }  // end of BehaviourDSLCommon::getDefaultModellingHypotheses
1028 
isModellingHypothesisSupported(const Hypothesis h) const1029   bool BehaviourDSLCommon::isModellingHypothesisSupported(const Hypothesis h) const {
1030     const auto mhs = this->getBehaviourDSLDescription().supportedModellingHypotheses;
1031     return std::find(mhs.cbegin(), mhs.cend(), h) != mhs.end();
1032   }  // end of BehaviourDSLCommon::isModellingHypothesesSupported
1033 
getBehaviourFileName() const1034   std::string BehaviourDSLCommon::getBehaviourFileName() const {
1035     return "TFEL/Material/" + this->mb.getClassName() + ".hxx";
1036   }  // end of BehaviourDSLCommon::getBehaviourFileName
1037 
getBehaviourDataFileName() const1038   std::string BehaviourDSLCommon::getBehaviourDataFileName() const {
1039     return "TFEL/Material/" + this->mb.getClassName() + "BehaviourData.hxx";
1040   }  // end of BehaviourDSLCommon::getBehaviourDataFileName
1041 
getIntegrationDataFileName() const1042   std::string BehaviourDSLCommon::getIntegrationDataFileName() const {
1043     return "TFEL/Material/" + this->mb.getClassName() + "IntegrationData.hxx";
1044   }  // end of BehaviourDSLCommon::getIntegrationDataFileName
1045 
getSrcFileName() const1046   std::string BehaviourDSLCommon::getSrcFileName() const {
1047     return this->mb.getClassName() + ".cxx";
1048   }  // end of BehaviourDSLCommon::getSrcFileName
1049 
analyseFile(const std::string & fileName_,const std::vector<std::string> & ecmds,const std::map<std::string,std::string> & s)1050   void BehaviourDSLCommon::analyseFile(const std::string& fileName_,
1051                                        const std::vector<std::string>& ecmds,
1052                                        const std::map<std::string, std::string>& s) {
1053     this->importFile(fileName_, ecmds, s);
1054     // Adding some stuff
1055     this->endsInputFileProcessing();
1056     // setting the name of the output files
1057     // targets description
1058     for (const auto& i : this->interfaces) {
1059       i.second->getTargetsDescription(this->td, this->mb);
1060     }
1061     for (auto& l : this->td.libraries) {
1062       insert_if(this->td.getLibrary(l.name).sources, this->getSrcFileName());
1063     }
1064     insert_if(this->td.headers, this->getBehaviourFileName());
1065     insert_if(this->td.headers, this->getBehaviourDataFileName());
1066     insert_if(this->td.headers, this->getIntegrationDataFileName());
1067     this->completeTargetsDescription();
1068   }
1069 
disableVariableDeclaration()1070   void BehaviourDSLCommon::disableVariableDeclaration() {
1071     if (this->mb.allowsNewUserDefinedVariables()) {
1072       this->completeVariableDeclaration();
1073       this->mb.disallowNewUserDefinedVariables();
1074     }
1075   } // end of BehaviourDSLCommon::disableVariableDeclaration
1076 
completeVariableDeclaration()1077   void BehaviourDSLCommon::completeVariableDeclaration() {
1078     using namespace mfront::bbrick;
1079     const auto& g = tfel::glossary::Glossary::getGlossary();
1080     if (getVerboseMode() >= VERBOSE_DEBUG) {
1081       getLogStream() << "BehaviourDSLCommon::completeVariableDeclaration: begin\n";
1082     }
1083     if ((!this->gradients.empty()) || (!this->thermodynamic_forces.empty())) {
1084       this->throwRuntimeError(
1085           "BehaviourDSLCommon::completeVariableDeclaration",
1086           "The number of gradients does not match the number of "
1087           "thermodynamic forces");
1088     }
1089     // defining modelling hypotheses
1090     if (!this->mb.areModellingHypothesesDefined()) {
1091       auto dmh = this->getDefaultModellingHypotheses();
1092       // taking into account restrictin du to the `Plate` othotropic
1093       // axes convention
1094       if ((this->mb.getSymmetryType() == mfront::ORTHOTROPIC) &&
1095           (this->mb.getOrthotropicAxesConvention() == OrthotropicAxesConvention::PLATE)) {
1096         for (auto ph = dmh.begin(); ph != dmh.end();) {
1097           if ((*ph != ModellingHypothesis::TRIDIMENSIONAL) && (*ph != ModellingHypothesis::PLANESTRESS) &&
1098               (*ph != ModellingHypothesis::PLANESTRAIN) && (*ph != ModellingHypothesis::GENERALISEDPLANESTRAIN)) {
1099             ph = dmh.erase(ph);
1100           } else {
1101             ++ph;
1102           }
1103         }
1104       }
1105       this->mb.setModellingHypotheses(dmh);
1106     }
1107     const auto& mh = this->mb.getModellingHypotheses();
1108     // treating bricks
1109     if (!this->bricks.empty()) {
1110       if (getVerboseMode() >= VERBOSE_DEBUG) {
1111         getLogStream() << "BehaviourDSLCommon::completeVariableDeclaration: "
1112                        << "treating bricks\n";
1113       }
1114       for (const auto h : mh) {
1115         auto& d = this->mb.getBehaviourData(h);
1116         RequirementManager r{d, this->mb.useQt()};
1117         // for(const auto& pb : this->bricks){
1118         //   pb->declareProviders(r,h);
1119         // }
1120         for (const auto& pb : this->bricks) {
1121           pb->addRequirements(r, h);
1122         }
1123         // unmatched requirements
1124         auto umrqs = std::vector<std::string>{};
1125         const auto& urs = r.getUnresolvedRequirements();
1126         for (const auto& n : urs) {
1127           const auto s = SupportedTypes{};
1128           const auto& ur = r.getRequirement(n);
1129           if ((s.getTypeFlag(ur.type) != SupportedTypes::SCALAR) ||
1130               (find(ur.aproviders.begin(), ur.aproviders.end(), ProviderIdentifier::MATERIALPROPERTY) ==
1131                ur.aproviders.end())) {
1132             umrqs.push_back(ur.name);
1133           }
1134         }
1135         if (!umrqs.empty()) {
1136           std::string msg = "the following requirements can't be met: ";
1137           for (const auto& umrq : umrqs) {
1138             msg += "\n- " + umrq;
1139           }
1140           this->throwRuntimeError("BehaviourDSLCommon::completeVariableDeclaration", msg);
1141         }
1142         for (const auto& n : urs) {
1143           const auto& ur = r.getRequirement(n);
1144           this->mb.addMaterialProperty(h, {ur.type, ur.name, ur.asize, 0u});
1145           if (!g.contains(ur.name)) {
1146             this->mb.setEntryName(h, ur.name, ur.name);
1147           }
1148         }
1149       }
1150     }
1151     for (const auto& pb : this->bricks) {
1152       pb->completeVariableDeclaration();
1153     }
1154     if (getVerboseMode() >= VERBOSE_DEBUG) {
1155       auto& log = getLogStream();
1156       log << "behaviour '" << this->mb.getClassName() << "' supports the following hypotheses: \n";
1157       for (const auto& h : mh) {
1158         log << " - " << ModellingHypothesis::toString(h);
1159         if (this->mb.hasSpecialisedMechanicalData(h)) {
1160           log << " (specialised)";
1161         }
1162         log << '\n';
1163       }
1164     }
1165     // time step scaling factors
1166     if (!this->mb.hasParameter(ModellingHypothesis::UNDEFINEDHYPOTHESIS, "minimal_time_step_scaling_factor")) {
1167       VariableDescription e("real", "minimal_time_step_scaling_factor", 1u, 0u);
1168       e.description = "minimal value for the time step scaling factor";
1169       this->mb.addParameter(ModellingHypothesis::UNDEFINEDHYPOTHESIS, e,
1170                             BehaviourData::ALREADYREGISTRED);
1171       this->mb.setParameterDefaultValue(
1172           ModellingHypothesis::UNDEFINEDHYPOTHESIS,
1173           "minimal_time_step_scaling_factor", 0.1);
1174       this->mb.setEntryName(ModellingHypothesis::UNDEFINEDHYPOTHESIS,
1175                             "minimal_time_step_scaling_factor",
1176                             "minimal_time_step_scaling_factor");
1177     }
1178     if (!this->mb.hasParameter(ModellingHypothesis::UNDEFINEDHYPOTHESIS,
1179                                "maximal_time_step_scaling_factor")) {
1180       VariableDescription e("real", "maximal_time_step_scaling_factor", 1u, 0u);
1181       e.description = "maximal value for the time step scaling factor";
1182       this->mb.addParameter(ModellingHypothesis::UNDEFINEDHYPOTHESIS, e,
1183                             BehaviourData::ALREADYREGISTRED);
1184       this->mb.setParameterDefaultValue(
1185           ModellingHypothesis::UNDEFINEDHYPOTHESIS,
1186           "maximal_time_step_scaling_factor",
1187           std::numeric_limits<double>::max());
1188       this->mb.setEntryName(ModellingHypothesis::UNDEFINEDHYPOTHESIS,
1189                             "maximal_time_step_scaling_factor",
1190                             "maximal_time_step_scaling_factor");
1191     }
1192     // incompatible options
1193     if ((this->mb.getAttribute(BehaviourDescription::computesStiffnessTensor, false)) &&
1194         (this->mb.getAttribute(BehaviourDescription::requiresStiffnessTensor, false))) {
1195       this->throwRuntimeError("BehaviourDSLCommon::completeVariableDeclaration",
1196                               "internal error, incompatible options for stiffness tensor");
1197     }
1198     // check of stiffness tensor requirement
1199     if ((this->mb.getBehaviourType() == BehaviourDescription::STANDARDSTRAINBASEDBEHAVIOUR) ||
1200         (this->mb.getBehaviourType() == BehaviourDescription::STANDARDFINITESTRAINBEHAVIOUR)) {
1201       if ((mh.find(ModellingHypothesis::PLANESTRESS) != mh.end()) ||
1202           (mh.find(ModellingHypothesis::AXISYMMETRICALGENERALISEDPLANESTRESS) != mh.end())) {
1203         if (this->mb.getAttribute(BehaviourDescription::requiresStiffnessTensor,false)) {
1204           if (!this->mb.hasAttribute(BehaviourDescription::requiresUnAlteredStiffnessTensor)) {
1205             this->throwRuntimeError("BehaviourDSLCommon::completeVariableDeclaration",
1206                                     "No option was given to the '@RequireStiffnessTensor' keyword.\n"
1207                                     "For plane stress hypotheses, it is required to precise whether "
1208                                     "the expected stiffness tensor is 'Altered' (the plane stress "
1209                                     "hypothesis is taken into account) or 'UnAltered' (the stiffness "
1210                                     "tensor is the same as in plane strain)");
1211           }
1212         }
1213       }
1214     }
1215     if (this->mb.getSymmetryType() == mfront::ORTHOTROPIC) {
1216       // if no orthotropic axes convention is defined, one can't compute
1217       // stiffness tensor, thermal expansion or stress free expansion
1218       // correctly, except for the 3D modelling hypothesis
1219       for (const auto h : this->mb.getDistinctModellingHypotheses()) {
1220         if (((this->mb.areElasticMaterialPropertiesDefined()) &&
1221              (this->mb.getElasticMaterialProperties().size() == 9u)) ||
1222             ((this->mb.areThermalExpansionCoefficientsDefined()) &&
1223              (this->mb.getThermalExpansionCoefficients().size() == 3u)) ||
1224             (this->mb.isStressFreeExansionAnisotropic(h))) {
1225           if (this->mb.getOrthotropicAxesConvention() == OrthotropicAxesConvention::DEFAULT) {
1226             // in this case, only tridimensional case is supported
1227             if (h != ModellingHypothesis::TRIDIMENSIONAL) {
1228               this->throwRuntimeError("BehaviourDSLCommon::completeVariableDeclaration",
1229                                       "An orthotropic axes convention must be choosen when "
1230                                       "using one of @ComputeStiffnessTensor, "
1231                                       "@ComputeThermalExpansion, @Swelling, @AxilalGrowth keywords in behaviours which "
1232                                       "shall be valid in other modelling hypothesis than "
1233                                       "'Tridimensional'. This message was triggered because "
1234                                       "either the thermal expansion or to the stiffness tensor "
1235                                       "is orthotropic.\n"
1236                                       "Either restrict the validity of the behaviour to "
1237                                       "'Tridimensional' (see @ModellingHypothesis) or "
1238                                       "choose and orthotropic axes convention as on option "
1239                                       "to the @OrthotropicBehaviour keyword");
1240             }
1241           }
1242         }
1243       }
1244     }
1245     if (getVerboseMode() >= VERBOSE_DEBUG) {
1246       getLogStream() << "BehaviourDSLCommon::completeVariableDeclaration: end\n";
1247     }
1248   }  // end of BehaviourDSLCommon::completeVariableDeclaration
1249 
endsInputFileProcessing()1250   void BehaviourDSLCommon::endsInputFileProcessing() {
1251     if (getVerboseMode() >= VERBOSE_DEBUG) {
1252       getLogStream() << "BehaviourDSLCommon::endsInputFileProcessing: begin\n";
1253     }
1254     this->disableVariableDeclaration();
1255     // restrictions on user defined compute stress free expansion
1256     for (const auto h : this->mb.getDistinctModellingHypotheses()) {
1257       const auto& d = this->mb.getBehaviourData(h);
1258       if (d.hasCode(BehaviourData::ComputeStressFreeExpansion)) {
1259         const auto& cb = d.getCodeBlock(BehaviourData::ComputeStressFreeExpansion);
1260         for (const auto& v : cb.members) {
1261           if (d.isLocalVariableName(v)) {
1262             this->throwRuntimeError(
1263                 "BehaviourDSLCommon::"
1264                 "endsInputFileProcessing: ",
1265                 "local variables can't be used in "
1266                 "@ComputeStressFreeExpansion blocks "
1267                 "(local variables are not initialized yet "
1268                 "when the stress free expansions "
1269                 "are computed)");
1270           }
1271         }
1272       }
1273     }
1274     if (this->mb.areSlipSystemsDefined()) {
1275       this->mb.appendToIncludes("#include \"TFEL/Material/" +
1276                                 this->mb.getClassName() + "SlipSystems.hxx\"");
1277     }
1278     //
1279     if (this->mb.getBehaviourType() ==
1280         BehaviourDescription::STANDARDFINITESTRAINBEHAVIOUR) {
1281       const auto mhs = this->getModellingHypothesesToBeTreated();
1282       for (const auto h :
1283            {ModellingHypothesis::PLANESTRESS,
1284             ModellingHypothesis::AXISYMMETRICALGENERALISEDPLANESTRESS}) {
1285         if (mhs.find(h) != mhs.end()) {
1286           if (!this->mb.hasSpecialisedMechanicalData(h)) {
1287             this->mb.specialize(h);
1288           }
1289         }
1290       }
1291     }
1292     // calling interfaces
1293     if (getPedanticMode()) {
1294       this->doPedanticChecks();
1295     }
1296     for (const auto& pb : this->bricks) {
1297       pb->endTreatment();
1298     }
1299     if (getVerboseMode() >= VERBOSE_DEBUG) {
1300       getLogStream() << "BehaviourDSLCommon::endsInputFileProcessing: end\n";
1301     }
1302   }  // end of BehaviourDSLCommon::endsInputFileProcessing
1303 
1304   /*!
1305    * \return the "true" integration variables (state variables are excluded)
1306    * \param[in] md : mechanical behaviour data
1307    */
getIntegrationVariables(const BehaviourData & md)1308   static VarContainer getIntegrationVariables(const BehaviourData& md) {
1309     const auto& ivs = md.getIntegrationVariables();
1310     VarContainer v;
1311     for (const auto& iv : ivs) {
1312       if (!md.isStateVariableName(iv.name)) {
1313         v.push_back(iv);
1314       }
1315     }
1316     return v;
1317   }  // end of getIntegrationVariables
1318 
1319   /*!
1320    * \brief various checks
1321    * \param[in] v  : variables
1322    * \param[in] t  : variable type
1323    * \param[in] uv : list of all used variables
1324    * \param[in] b1 : check if the variable is used
1325    * \param[in] b2 : check if the variable increment (or rate) is used
1326    * \param[in] b3 : check if glossary name is declared
1327    * \param[in] b4 : check if variable is used in more than one code block (test for local variables)
1328    */
performPedanticChecks(const BehaviourData & md,const VarContainer & v,const std::string & t,const std::map<std::string,unsigned short> & uv,const bool b1=true,const bool b2=true,const bool b3=true,const bool b4=false)1329   static void performPedanticChecks(const BehaviourData& md,
1330                                     const VarContainer& v,
1331                                     const std::string& t,
1332                                     const std::map<std::string, unsigned short>& uv,
1333                                     const bool b1 = true,
1334                                     const bool b2 = true,
1335                                     const bool b3 = true,
1336                                     const bool b4 = false) {
1337     using namespace tfel::glossary;
1338     const auto& glossary = Glossary::getGlossary();
1339     auto& log = getLogStream();
1340     for (const auto& vd : v) {
1341       if (b1) {
1342         const auto p = uv.find(vd.name);
1343         if (p == uv.end()) {
1344           log << "- " << t << " '" << vd.name << "' is unused.\n";
1345         } else {
1346           if (b4 && p->second == 1) {
1347             log << "- " << t << " '" << vd.name << "' is used in one code block only.\n";
1348           }
1349         }
1350       }
1351       if (b2) {
1352         if (uv.find("d" + vd.name) == uv.end()) {
1353           log << "- " << t << " increment 'd" << vd.name << "' is unused.\n";
1354         }
1355       }
1356       if (b3) {
1357         if ((!md.hasGlossaryName(vd.name)) && (!md.hasEntryName(vd.name))) {
1358           log << "- " << t << " '" << vd.name << "' has no glossary name.\n";
1359         }
1360       }
1361       if (vd.description.empty()) {
1362         auto hasDoc = false;
1363         if (md.hasGlossaryName(vd.name)) {
1364           const auto& e = glossary.getGlossaryEntry(md.getExternalName(vd.name));
1365           hasDoc = (!e.getShortDescription().empty()) || (!e.getDescription().empty());
1366         }
1367         if (!hasDoc) {
1368           log << "- " << t << " '" << vd.name << "' has no description.\n";
1369         }
1370       }
1371     }
1372   }
1373 
1374   /*!
1375    * \brief various checks on static variables
1376    * \param[in] v  : variables
1377    * \param[in] uv : list of all static variables
1378    */
performPedanticChecks(const StaticVarContainer & v,const std::map<std::string,unsigned short> & uv)1379   static void performPedanticChecks(const StaticVarContainer& v, const std::map<std::string, unsigned short>& uv) {
1380     auto& log = getLogStream();
1381     for (const auto& vd : v) {
1382       if (uv.find(vd.name) == uv.end()) {
1383         log << "- static variable '" << vd.name << "' is unused.\n";
1384       }
1385     }
1386   }
1387 
doPedanticChecks() const1388   void BehaviourDSLCommon::doPedanticChecks() const {
1389     const auto& hs = this->mb.getDistinctModellingHypotheses();
1390     auto& log = getLogStream();
1391     log << "\n* Pedantic checks\n";
1392     for (auto h : hs) {
1393       const auto& md = this->mb.getBehaviourData(h);
1394       // checks if variables are used
1395       if (h == ModellingHypothesis::UNDEFINEDHYPOTHESIS) {
1396         log << "\n** Beginning pedantic checks for default modelling hypothesis\n\n";
1397       } else {
1398         log << "\n** Beginning pedantic checks for modelling hypothesis '" << ModellingHypothesis::toString(h)
1399             << "'\n\n";
1400       }
1401       // getting all used variables
1402       const auto& cbs = md.getCodeBlockNames();
1403       auto members = std::map<std::string, unsigned short>{};   // variable names and counts
1404       auto smembers = std::map<std::string, unsigned short>{};  // static variable nanes and counts
1405       for (const auto& cbs_pcbs : cbs) {
1406         const auto& cb = md.getCodeBlock(cbs_pcbs);
1407         if (cb.description.empty()) {
1408           log << "- code block '" << cbs_pcbs << "' has no description\n";
1409         }
1410         for (const auto& v : cb.members) {
1411           if (members.count(v) == 0) {
1412             members[v] = 1;
1413           } else {
1414             ++(members[v]);
1415           }
1416         }
1417         for (const auto& v : cb.staticMembers) {
1418           if (smembers.count(v) == 0) {
1419             smembers[v] = 1;
1420           } else {
1421             ++(smembers[v]);
1422           }
1423         }
1424       }
1425       performPedanticChecks(md, md.getMaterialProperties(), "material property", members, true, false, true);
1426       const auto& ivs = getIntegrationVariables(md);
1427       performPedanticChecks(md, ivs, "integration variable", members, false, true, false);
1428       performPedanticChecks(md, md.getStateVariables(), "state variable", members);
1429       performPedanticChecks(md, md.getAuxiliaryStateVariables(), "auxiliary state variable", members, true, false);
1430       performPedanticChecks(md, md.getExternalStateVariables(), "external state variable", members);
1431       performPedanticChecks(md, md.getLocalVariables(), "local variable", members, true, false, false, true);
1432       performPedanticChecks(md, md.getParameters(), "parameter", members, true, false);
1433       performPedanticChecks(md.getStaticVariables(), smembers);
1434     }
1435     log << "\n# End of pedantic checks\n";
1436   }  // end of BehaviourDSLCommon::pedanticChecks
1437 
1438   std::set<BehaviourDSLCommon::Hypothesis>
getModellingHypothesesToBeTreated() const1439   BehaviourDSLCommon::getModellingHypothesesToBeTreated() const {
1440     // modelling hypotheses handled by the interfaces (if at least one
1441     // interface is defined), or by the behaviour
1442     std::set<Hypothesis> mhs;
1443     if (this->interfaces.empty()) {
1444       const auto& bh = this->mb.getModellingHypotheses();
1445       mhs.insert(bh.begin(), bh.end());
1446     } else {
1447       // calling the interfaces
1448       for (const auto& i : this->interfaces) {
1449         const auto& ih = i.second->getModellingHypothesesToBeTreated(this->mb);
1450         mhs.insert(ih.begin(), ih.end());
1451       }
1452     }
1453     return mhs;
1454   }  // end of BehaviourDSLCommon::getModellingHypothesesToBeTreated
1455 
generateOutputFiles()1456   void BehaviourDSLCommon::generateOutputFiles() {
1457     tfel::system::systemCall::mkdir("src");
1458     tfel::system::systemCall::mkdir("include");
1459     tfel::system::systemCall::mkdir("include/TFEL/");
1460     tfel::system::systemCall::mkdir("include/TFEL/Material");
1461     //! generating sources du to external material properties and models
1462     std::ofstream behaviourFile("include/" + this->getBehaviourFileName());
1463     std::ofstream behaviourDataFile("include/" +
1464                                     this->getBehaviourDataFileName());
1465     std::ofstream integrationDataFile("include/" +
1466                                       this->getIntegrationDataFileName());
1467     std::ofstream srcFile("src/" + this->getSrcFileName());
1468     if (!behaviourFile) {
1469       this->throwRuntimeError("BehaviourDSLCommon::generateOutputFiles",
1470                               "unable to open '" +
1471                                   this->getBehaviourFileName() +
1472                                   "' "
1473                                   "for writing output file");
1474     }
1475     if (!behaviourDataFile) {
1476       this->throwRuntimeError("BehaviourDSLCommon::generateOutputFiles",
1477                               "unable to open '" +
1478                                   this->getBehaviourDataFileName() +
1479                                   "' "
1480                                   "for writing output file");
1481     }
1482     if (!integrationDataFile) {
1483       this->throwRuntimeError("BehaviourDSLCommon::generateOutputFiles",
1484                               "unable to open '" +
1485                                   this->getIntegrationDataFileName() +
1486                                   "' "
1487                                   "for writing output file");
1488     }
1489     if (!srcFile) {
1490       this->throwRuntimeError("BehaviourDSLCommon::generateOutputFiles",
1491                               "unable to open '" + this->getSrcFileName() +
1492                                   "' "
1493                                   "for writing output file");
1494     }
1495     for (const auto& em : this->externalMFrontFiles) {
1496       this->callMFront(em.second, {em.first});
1497     }
1498     auto write_classes = [this, &behaviourFile, &behaviourDataFile,
1499                           &integrationDataFile](const Hypothesis h) {
1500       const auto n = h == ModellingHypothesis::UNDEFINEDHYPOTHESIS
1501                          ? "default hypothesis"
1502                          : "'" + ModellingHypothesis::toString(h) + "'";
1503       if (getVerboseMode() >= VERBOSE_DEBUG) {
1504         auto& log = getLogStream();
1505         log << "BehaviourDSLCommon::generateOutputFiles: "
1506             << "treating " + n + "\n";
1507       }
1508       // Generating BehaviourData's outputClass
1509       if (getVerboseMode() >= VERBOSE_DEBUG) {
1510         auto& log = getLogStream();
1511         log << "BehaviourDSLCommon::generateOutputFiles: "
1512             << "writing behaviour data for " + n + "\n";
1513       }
1514       this->writeBehaviourDataClass(behaviourDataFile, h);
1515       // Generating IntegrationData's outputClass
1516       if (getVerboseMode() >= VERBOSE_DEBUG) {
1517         auto& log = getLogStream();
1518         log << "BehaviourDSLCommon::generateOutputFiles: "
1519             << "writing integration data for " + n + "\n";
1520       }
1521       this->writeIntegrationDataClass(integrationDataFile, h);
1522       // Generating Behaviour's outputFile
1523       if (getVerboseMode() >= VERBOSE_DEBUG) {
1524         auto& log = getLogStream();
1525         log << "BehaviourDSLCommon::generateOutputFiles: "
1526             << "writing behaviour class for " + n + "\n";
1527       }
1528       this->writeBehaviourClass(behaviourFile, h);
1529     };
1530     // generate outpout files
1531     this->writeBehaviourDataFileBegin(behaviourDataFile);
1532     this->writeIntegrationDataFileBegin(integrationDataFile);
1533     this->writeBehaviourFileBegin(behaviourFile);
1534     if (this->mb.areSlipSystemsDefined()) {
1535       this->generateSlipSystemsFiles();
1536     }
1537     const auto mhs = this->getModellingHypothesesToBeTreated();
1538     if (!this->mb.areAllMechanicalDataSpecialised(mhs)) {
1539       write_classes(ModellingHypothesis::UNDEFINEDHYPOTHESIS);
1540     }
1541     for (const auto& h : mhs) {
1542       if (mb.hasSpecialisedMechanicalData(h)) {
1543         write_classes(h);
1544       }
1545     }
1546     this->writeBehaviourDataFileEnd(behaviourDataFile);
1547     this->writeIntegrationDataFileEnd(integrationDataFile);
1548     this->writeBehaviourFileEnd(behaviourFile);
1549     // Generating behaviour's source file
1550     if (getVerboseMode() >= VERBOSE_DEBUG) {
1551       auto& log = getLogStream();
1552       log << "BehaviourDSLCommon::generateOutputFiles : writing source file\n";
1553     }
1554     this->writeSrcFile(srcFile);
1555     // calling the interfaces
1556     for (const auto& i : this->interfaces) {
1557       if (getVerboseMode() >= VERBOSE_DEBUG) {
1558         auto& log = getLogStream();
1559         log << "BehaviourDSLCommon::generateOutputFiles : "
1560             << "calling interface '" << i.first << "'\n";
1561       }
1562       i.second->endTreatment(this->mb, this->fd);
1563     }
1564     behaviourFile.close();
1565     behaviourDataFile.close();
1566     integrationDataFile.close();
1567     srcFile.close();
1568   }
1569 
generateSlipSystemsFiles()1570   void BehaviourDSLCommon::generateSlipSystemsFiles() {
1571     using SlipSystemsDescription = BehaviourDescription::SlipSystemsDescription;
1572     using vector = SlipSystemsDescription::vector;
1573     using tensor = SlipSystemsDescription::tensor;
1574     auto throw_if = [this](const bool b, const std::string& m) {
1575       if (b) {
1576         this->throwRuntimeError(
1577             "FiniteStrainSingleCrystalBrick::"
1578             "generateSlipSystems",
1579             m);
1580       }
1581     };
1582     auto write_vector = [](std::ostream& out, const std::string& v, const std::vector<vector>& ts) {
1583       for (decltype(ts.size()) i = 0; i != ts.size(); ++i) {
1584         const auto& t = ts[i];
1585         out << v << "[" << i << "] = vector{"
1586             << "real(" << t[0] << "),"
1587             << "real(" << t[1] << "),"
1588             << "real(" << t[2] << ")};\n";
1589       }
1590     };
1591     auto write_tensor = [](std::ostream& out, const std::string& mu, const std::vector<tensor>& ts) {
1592       for (decltype(ts.size()) i = 0; i != ts.size(); ++i) {
1593         const auto& t = ts[i];
1594         out << mu << "[" << i << "] = tensor{"
1595             << "real(" << t[0] << "),"
1596             << "real(" << t[1] << "),"
1597             << "real(" << t[2] << "),"
1598             << "real(" << t[3] << "),"
1599             << "real(" << t[4] << "),"
1600             << "real(" << t[5] << "),"
1601             << "real(" << t[6] << "),"
1602             << "real(" << t[7] << "),"
1603             << "real(" << t[8] << ")};\n";
1604       }
1605     };
1606     auto write_stensor = [](std::ostream& out, const std::string& mus, const std::vector<tensor>& ts) {
1607       TFEL_CONSTEXPR const auto cste = tfel::math::Cste<long double>::sqrt2 / 2;
1608       for (decltype(ts.size()) i = 0; i != ts.size(); ++i) {
1609         const auto& t = ts[i];
1610         out << mus << "[" << i << "] = stensor{"
1611             << "real(" << t[0] << "),"
1612             << "real(" << t[1] << "),"
1613             << "real(" << t[2] << "),"
1614             << "real(" << (t[3] + t[4]) * cste << "),"
1615             << "real(" << (t[5] + t[6]) * cste << "),"
1616             << "real(" << (t[7] + t[8]) * cste << ")};\n";
1617       }
1618     };
1619     const auto& sss = this->mb.getSlipSystems();
1620     const auto nb = sss.getNumberOfSlipSystemsFamilies();
1621     const auto cn = this->mb.getClassName() + "SlipSystems";
1622     tfel::system::systemCall::mkdir("include");
1623     tfel::system::systemCall::mkdir("include/TFEL/");
1624     tfel::system::systemCall::mkdir("include/TFEL/Material");
1625     auto file = "include/TFEL/Material/" + cn + ".hxx";
1626     std::ofstream out(file);
1627     throw_if(!out, "can't open file '" + file + "'");
1628     out.exceptions(std::ios::badbit | std::ios::failbit);
1629     out << "/*!\n"
1630         << "* \\file   " << file << '\n'
1631         << "* \\brief  "
1632         << "this file decares the " << cn << " class.\n"
1633         << "*         File generated by " << MFrontHeader::getVersionName() << " "
1634         << "version " << MFrontHeader::getVersionNumber() << '\n';
1635     if (!this->fd.authorName.empty()) {
1636       out << "* \\author " << this->fd.authorName << '\n';
1637     }
1638     if (!this->fd.date.empty()) {
1639       out << "* \\date   " << this->fd.date << '\n';
1640     }
1641     out << " */\n\n";
1642     out << "#ifndef LIB_TFEL_MATERIAL_" << makeUpperCase(cn) << "_HXX\n"
1643         << "#define LIB_TFEL_MATERIAL_" << makeUpperCase(cn) << "_HXX\n\n"
1644 	<< "#if (defined _WIN32 || defined _WIN64)\n"
1645       	<< "#ifdef min\n"
1646       	<< "#undef min\n"
1647 	<< "#endif /* min */\n"
1648       	<< "#ifdef max\n"
1649       	<< "#undef max\n"
1650 	<< "#endif /* max */\n"
1651       	<< "#ifdef small\n"
1652       	<< "#undef small\n"
1653 	<< "#endif /* small */\n"
1654       	<< "#endif /* (defined _WIN32 || defined _WIN64) */\n\n"
1655         << "#include\"TFEL/Raise.hxx\"\n"
1656         << "#include\"TFEL/Math/tvector.hxx\"\n"
1657         << "#include\"TFEL/Math/stensor.hxx\"\n"
1658         << "#include\"TFEL/Math/tensor.hxx\"\n\n"
1659         << "namespace tfel{\n\n"
1660         << "namespace material{\n\n"
1661         << "template<typename real>\n"
1662         << "struct " << cn << '\n'
1663         << "{\n"
1664         << "//! a simple alias\n"
1665         << "using tensor = tfel::math::tensor<3u,real>;\n"
1666         << "//! a simple alias\n"
1667         << "using vector = tfel::math::tvector<3u,real>;\n"
1668         << "//! a simple alias\n"
1669         << "using stensor = tfel::math::stensor<3u,real>;\n";
1670     auto nss = size_type{};
1671     for (size_type idx = 0; idx != nb; ++idx) {
1672       nss += sss.getNumberOfSlipSystems(idx);
1673     }
1674     if (nb == 1u) {
1675       const auto nss0 = sss.getNumberOfSlipSystems(0);
1676       out << "//! number of sliding systems\n"
1677           << "static constexpr const unsigned short Nss"
1678           << " = " << nss << ";\n"
1679           << "//! number of sliding systems (first and uniq family)\n"
1680           << "static constexpr const unsigned short Nss0"
1681           << " = " << nss0 << ";\n";
1682     } else {
1683       for (size_type idx = 0; idx != nb; ++idx) {
1684         out << "//! number of sliding systems\n"
1685             << "static constexpr const unsigned short Nss" << idx << " = " << sss.getNumberOfSlipSystems(idx) << ";\n";
1686       }
1687       out << "static constexpr const unsigned short Nss = ";
1688       for (size_type idx = 0; idx != nb;) {
1689         out << "Nss" << idx;
1690         if (++idx != nb) {
1691           out << "+";
1692         }
1693       }
1694       out << ";\n";
1695     }
1696     out << "//! tensor of directional sense\n"
1697         << "tfel::math::tvector<Nss,tensor> mu;\n"
1698         << "//! symmetric tensor of directional sense\n"
1699         << "tfel::math::tvector<Nss,stensor> mus;\n"
1700         << "//! normal to slip plane\n"
1701         << "tfel::math::tvector<Nss,vector> np;\n"
1702         << "//! unit vector in the slip direction\n"
1703         << "tfel::math::tvector<Nss,vector> ns;\n";
1704     for (size_type idx = 0; idx != nb; ++idx) {
1705       out << "//! tensor of directional sense\n"
1706           << "tfel::math::tvector<Nss" << idx << ",tensor> mu" << idx << ";\n"
1707           << "//! symmetric tensor of directional sense\n"
1708           << "tfel::math::tvector<Nss" << idx << ",stensor> mus" << idx << ";\n"
1709           << "//! normal to slip plane\n"
1710           << "tfel::math::tvector<Nss" << idx << ",vector> np" << idx << ";\n"
1711           << "//! unit vector in the slip direction\n"
1712           << "tfel::math::tvector<Nss" << idx << ",vector> ns" << idx << ";\n";
1713     }
1714     if (this->mb.hasInteractionMatrix()) {
1715       out << "//! interaction matrix\n"
1716           << "tfel::math::tmatrix<Nss,Nss,real> mh;\n";
1717       out << "//! interaction matrix\n"
1718           << "tfel::math::tmatrix<Nss,Nss,real> him;\n";
1719     }
1720     if (this->mb.hasDislocationsMeanFreePathInteractionMatrix()) {
1721       out << "tfel::math::tmatrix<Nss,Nss,real> dim;\n";
1722     }
1723     if (nb != 1u) {
1724       out << "/*!\n"
1725           << " * \\return the gobal index of the jth system of ith family\n"
1726           << " * \\param[in] i: slip system family\n"
1727           << " * \\param[in] j: local slip system index\n"
1728           << " */\n"
1729           << "constexpr unsigned short offset(const unsigned short,\nconst unsigned short) const;\n";
1730       for (size_type i = 0; i != nb; ++i) {
1731         out << "/*!\n"
1732             << " * \\return the gobal index of the ith system of " << i << "th family\n"
1733             << " * \\param[in] i: local slip system index\n"
1734             << " */\n"
1735             << "constexpr unsigned short offset" << i << "(const unsigned short) const;\n";
1736       }
1737     }
1738     out << "/*!\n"
1739         << " * \\return true if two systems are coplanar\n"
1740         << " * \\param[in] i: first slip system index\n"
1741         << " * \\param[in] j: second slip system index\n"
1742         << " */\n"
1743         << "bool areCoplanar(const unsigned short,\n"
1744         << "                 const unsigned short) const;\n"
1745         << "//! return the unique instance of the class\n"
1746         << "static const " << cn << "&\n"
1747         << "getSlidingSystems();\n"
1748         << "//! return the unique instance of the class\n"
1749         << "static const " << cn << "&\n"
1750         << "getSlipSystems();\n"
1751         << "//! return the unique instance of the class\n"
1752         << "static const " << cn << "&\n"
1753         << "getGlidingSystems();\n"
1754         << "private:\n"
1755         << "//! Constructor\n"
1756         << cn << "();\n"
1757         << "//! move constructor (disabled)\n"
1758         << cn << "(" << cn << "&&) = delete;\n"
1759         << "//! copy constructor (disabled)\n"
1760         << cn << "(const " << cn << "&) = delete;\n"
1761         << "//! move operator (disabled)\n"
1762         << cn << "&\n"
1763         << "operator=(" << cn << "&&) = delete;\n"
1764         << "//! copy constructor (disabled)\n"
1765         << cn << "&\n"
1766         << "operator=(const " << cn << "&) = delete;\n"
1767         << "}; // end of struct " << cn << "\n\n"
1768         << "//! a simple alias\n"
1769         << "template<typename real>\n"
1770         << "using " << this->mb.getClassName() << "SlidingSystems "
1771         << "= " << cn << "<real>;\n\n"
1772         << "//! a simple alias\n"
1773         << "template<typename real>\n"
1774         << "using " << this->mb.getClassName() << "GlidingSystems "
1775         << "= " << cn << "<real>;\n\n"
1776         << "} // end of namespace material\n\n"
1777         << "} // end of namespace tfel\n\n"
1778         << "#include\"TFEL/Material/" << cn << ".ixx\"\n\n"
1779         << "#endif /* LIB_TFEL_MATERIAL_" << makeUpperCase(cn) << "_HXX */\n";
1780     out.close();
1781     file = "include/TFEL/Material/" + cn + ".ixx";
1782     out.open(file);
1783     throw_if(!out, "can't open file '" + file + "'");
1784     out.exceptions(std::ios::badbit | std::ios::failbit);
1785     out.precision(std::numeric_limits<long double>::digits10);
1786     out << "/*!\n"
1787         << "* \\file   " << file << '\n'
1788         << "* \\brief  "
1789         << "this file implements the " << cn << " class.\n"
1790         << "*         File generated by " << MFrontHeader::getVersionName() << " "
1791         << "version " << MFrontHeader::getVersionNumber() << '\n';
1792     if (!this->fd.authorName.empty()) {
1793       out << "* \\author " << this->fd.authorName << '\n';
1794     }
1795     if (!this->fd.date.empty()) {
1796       out << "* \\date   " << this->fd.date << '\n';
1797     }
1798     out << " */\n\n";
1799     out << "#ifndef LIB_TFEL_MATERIAL_" << makeUpperCase(cn) << "_IXX\n"
1800         << "#define LIB_TFEL_MATERIAL_" << makeUpperCase(cn) << "_IXX\n\n"
1801         << "#include\"TFEL/Math/General/MathConstants.hxx\"\n\n"
1802         << "namespace tfel{\n\n"
1803         << "namespace material{\n\n"
1804         << "template<typename real>\n"
1805         << "const " << cn << "<real>&\n"
1806         << cn << "<real>::getSlidingSystems(){\n"
1807         << "static const " << cn << " i;\n"
1808         << "return i;\n"
1809         << "} // end of " << cn << "::getSlidingSystems\n\n"
1810         << "template<typename real>\n"
1811         << "const " << cn << "<real>&\n"
1812         << cn << "<real>::getSlipSystems(){\n"
1813         << "return " << cn << "<real>::getSlidingSystems();\n"
1814         << "} // end of " << cn << "::getSlipSystems\n\n"
1815         << "template<typename real>\n"
1816         << "const " << cn << "<real>&\n"
1817         << cn << "<real>::getGlidingSystems(){\n"
1818         << "return " << cn << "<real>::getSlidingSystems();\n"
1819         << "} // end of " << cn << "::getGlidingSystems\n\n"
1820         << "template<typename real>\n"
1821         << cn << "<real>::" << cn << "(){\n";
1822     std::vector<tensor> gots;
1823     std::vector<vector> gnss;
1824     std::vector<vector> gnps;
1825     // orientation tensors
1826     for (size_type idx = 0; idx != nb; ++idx) {
1827       const auto& ots = sss.getOrientationTensors(idx);
1828       write_tensor(out, "this->mu" + std::to_string(idx), ots);
1829       gots.insert(gots.end(), ots.begin(), ots.end());
1830     }
1831     write_tensor(out, "this->mu", gots);
1832     // symmetric orientation tensors
1833     for (size_type idx = 0; idx != nb; ++idx) {
1834       write_stensor(out, "this->mus" + std::to_string(idx), sss.getOrientationTensors(idx));
1835     }
1836     write_stensor(out, "this->mus", gots);
1837     // normal to slip planes
1838     for (size_type idx = 0; idx != nb; ++idx) {
1839       const auto& nps = sss.getSlipPlaneNormals(idx);
1840       write_vector(out, "this->np" + std::to_string(idx), nps);
1841       gnps.insert(gnps.end(), nps.begin(), nps.end());
1842     }
1843     write_vector(out, "this->np", gnps);
1844     // slip direction
1845     for (size_type idx = 0; idx != nb; ++idx) {
1846       const auto& nss2 = sss.getSlipDirections(idx);
1847       write_vector(out, "this->ns" + std::to_string(idx), nss2);
1848       gnss.insert(gnss.end(), nss2.begin(), nss2.end());
1849     }
1850     write_vector(out, "this->ns", gnss);
1851 
1852     auto write_imatrix = [&out, &sss, &nb, &nss](const std::vector<long double>& m, const std::string& n) {
1853       const auto ims = sss.getInteractionMatrixStructure();
1854       auto count = size_type{};  // number of terms of the matrix treated so far
1855       out << "this->" << n << " = {";
1856       for (size_type idx = 0; idx != nb; ++idx) {
1857         const auto gsi = sss.getSlipSystems(idx);
1858         for (size_type idx2 = 0; idx2 != gsi.size(); ++idx2) {
1859           for (size_type jdx = 0; jdx != nb; ++jdx) {
1860             const auto gsj = sss.getSlipSystems(jdx);
1861             for (size_type jdx2 = 0; jdx2 != gsj.size(); ++jdx2) {
1862               const auto r = ims.getRank(gsi[idx2], gsj[jdx2]);
1863               out << "real(" << m[r] << ")";
1864               if (++count != nss * nss) {
1865                 out << ",";
1866               }
1867             }
1868           }
1869           out << '\n';
1870         }
1871       }
1872       out << "};\n";
1873 
1874     };
1875     if (this->mb.hasInteractionMatrix()) {
1876       write_imatrix(sss.getInteractionMatrix(), "mh");
1877       write_imatrix(sss.getInteractionMatrix(), "him");
1878     }
1879     if (this->mb.hasDislocationsMeanFreePathInteractionMatrix()) {
1880       write_imatrix(sss.getDislocationsMeanFreePathInteractionMatrix(), "dim");
1881     }
1882     out << "} // end of " << cn << "::" << cn << "\n\n";
1883     if (nb != 1u) {
1884       out << "template<typename real>\n"
1885           << "constexpr unsigned short\n"
1886           << cn << "<real>::offset(const unsigned short i,\n"
1887           << "const unsigned short j\n) const{\n"
1888           << "const auto oi = [&i]() -> unsigned short{\n"
1889           << "switch(i){\n";
1890       for (size_type i = 0; i != nb; ++i) {
1891         out << "case " << i << ":\n";
1892         if (i == 0) {
1893           out << "return 0;\n"
1894               << "break;\n";
1895         } else {
1896           out << "return ";
1897           for (size_type j = 0; j != i;) {
1898             out << "Nss" << j;
1899             if (++j != i) {
1900               out << "+";
1901             }
1902           }
1903           out << ";\n"
1904               << "break;\n";
1905         }
1906       }
1907       out << "default:\n"
1908           << "tfel::raise<std::out_of_range>(\"" << cn << "::offset: :\"\n\"invalid index"
1909           << "\");\n"
1910           << "}\n"
1911           << "}();\n"
1912           << "return oi+j;\n"
1913           << "} // end of offset\n\n";
1914       for (size_type i = 0; i != nb; ++i) {
1915         out << "template<typename real>\n"
1916             << "constexpr unsigned short\n"
1917             << cn << "<real>::offset" << i << "(const unsigned short i) const{\n";
1918         if (i != 0) {
1919           out << "constexpr const unsigned short o = ";
1920           for (size_type j = 0; j != i;) {
1921             out << "Nss" << j;
1922             if (++j != i) {
1923               out << "+";
1924             }
1925           }
1926           out << ";\n"
1927               << "return o+i;\n";
1928         } else {
1929           out << "return i;\n";
1930         }
1931         out << "} // end of offset" << i << "\n\n";
1932       }
1933     }
1934     out << "template<typename real>\n"
1935         << "bool " << cn << "<real>::areCoplanar(const unsigned short i,\n"
1936         << "                                     const unsigned short j) const{\n";
1937     std::vector<std::vector<bool>> are_coplanar(nss, std::vector<bool>(nss));
1938     auto i = size_type{};
1939     for (size_type idx = 0; idx != nb; ++idx) {
1940       const auto gsi = sss.getSlipSystems(idx);
1941       for (size_type idx2 = 0; idx2 != gsi.size(); ++idx2, ++i) {
1942         auto j = size_type{};
1943         for (size_type jdx = 0; jdx != nb; ++jdx) {
1944           const auto gsj = sss.getSlipSystems(jdx);
1945           for (size_type jdx2 = 0; jdx2 != gsj.size(); ++jdx2, ++j) {
1946             if (gsi[idx2].is<SlipSystemsDescription::system3d>()) {
1947               const auto& si = gsi[idx2].get<SlipSystemsDescription::system3d>();
1948               const auto& sj = gsj[jdx2].get<SlipSystemsDescription::system3d>();
1949               const auto& ni = si.plane;
1950               const auto& nj = sj.plane;
1951               are_coplanar[i][j] =
1952                   (std::equal(ni.begin(), ni.end(), nj.begin()) ||
1953                    std::equal(ni.begin(), ni.end(), nj.begin(), [](const int a, const int b) { return a == -b; }));
1954             } else {
1955               const auto& si = gsi[idx2].get<SlipSystemsDescription::system4d>();
1956               const auto& sj = gsj[jdx2].get<SlipSystemsDescription::system4d>();
1957               const auto& ni = si.plane;
1958               const auto& nj = sj.plane;
1959               are_coplanar[i][j] =
1960                   (std::equal(ni.begin(), ni.end(), nj.begin()) ||
1961                    std::equal(ni.begin(), ni.end(), nj.begin(), [](const int a, const int b) { return a == -b; }));
1962             }
1963           }
1964         }
1965       }
1966     }
1967     out << "const auto mi = std::min(i,j);\n"
1968         << "const auto mj = std::max(i,j);\n"
1969         << "switch(mi){\n";
1970     for (i = 0; i != nss; ++i) {
1971       out << "case " << i << ":\n";
1972       if (i + 1 == nss) {
1973         out << "return (mi==" << nss - 1 << ")&&(mj==" << nss - 1 << ");\n";
1974       } else {
1975         out << "switch (mj){\n";
1976         for (size_type j = i; j != nss; ++j) {
1977           out << "case " << j << ":\n"
1978               << "return " << (are_coplanar[i][j] ? "true" : "false") << ";\n"
1979               << "break;\n";
1980         }
1981         out << "default:\n"
1982             << "return false;\n"
1983             << "}\n";
1984       }
1985       out << "break;\n";
1986     }
1987     out << "default:\n"
1988         << "break;\n"
1989         << "}\n"
1990         << "return false;\n"
1991         << "}\n\n"
1992         << "} // end of namespace material\n\n"
1993         << "} // end of namespace tfel\n\n"
1994         << "#endif /* LIB_TFEL_MATERIAL_" << makeUpperCase(cn) << "_IXX */\n";
1995   }
1996 
declareExternalStateVariableProbablyUnusableInPurelyImplicitResolution(const Hypothesis h,const std::string & n)1997   void BehaviourDSLCommon::declareExternalStateVariableProbablyUnusableInPurelyImplicitResolution(
1998       const Hypothesis h, const std::string& n) {
1999     if (!this->explicitlyDeclaredUsableInPurelyImplicitResolution) {
2000       this->mb.setUsableInPurelyImplicitResolution(h, false);
2001     }
2002     this->mb.declareExternalStateVariableProbablyUnusableInPurelyImplicitResolution(h, n);
2003   }  // end of BehaviourDSLCommon::declareExternalStateVariableProbablyUnusableInPurelyImplicitResolution
2004 
standardModifier(const Hypothesis h,const std::string & var,const bool addThisPtr)2005   std::string BehaviourDSLCommon::standardModifier(const Hypothesis h, const std::string& var, const bool addThisPtr) {
2006     if ((this->mb.isExternalStateVariableIncrementName(h, var)) || (var == "dT")) {
2007       this->declareExternalStateVariableProbablyUnusableInPurelyImplicitResolution(h, var.substr(1));
2008     }
2009     if (addThisPtr) {
2010       return "this->" + var;
2011     }
2012     return var;
2013   }  // end of BehaviourDSLCommon::standardModifier
2014 
tangentOperatorVariableModifier(const Hypothesis h,const std::string & var,const bool addThisPtr)2015   std::string BehaviourDSLCommon::tangentOperatorVariableModifier(const Hypothesis h,
2016                                                                   const std::string& var,
2017                                                                   const bool addThisPtr) {
2018     return this->standardModifier(h, var, addThisPtr);
2019   }  // end of BehaviourDSLCommon::tangentOperatorVariableModifier
2020 
treatStrainMeasure()2021   void BehaviourDSLCommon::treatStrainMeasure() {
2022     this->checkNotEndOfFile("BehaviourDSLCommon::treatStrainMeasure", "Expected strain measure name.");
2023     const auto fs = this->current->value;
2024     ++(this->current);
2025     this->readSpecifiedToken("BehaviourDSLCommon::treatStrainMeasure", ";");
2026     if (fs == "Hencky") {
2027       this->mb.setStrainMeasure(BehaviourDescription::HENCKY);
2028     } else if (fs == "GreenLagrange") {
2029       this->mb.setStrainMeasure(BehaviourDescription::GREENLAGRANGE);
2030     } else if ((fs == "Linearised") || (fs == "Linearized")) {
2031       this->mb.setStrainMeasure(BehaviourDescription::LINEARISED);
2032     } else {
2033       this->throwRuntimeError("BehaviourDSLCommon::treatStrainMeasure", "unsupported strain measure '" + fs + "'");
2034     }
2035   }  // end of BehaviourDSLCommon::treatStrainMeasure
2036 
treatPrivate()2037   void BehaviourDSLCommon::treatPrivate() {
2038     auto hs = std::set<Hypothesis>{};
2039     this->readHypothesesList(hs);
2040     const auto beg = this->current;
2041     for (const auto& h : hs) {
2042       const auto& d = this->mb.getBehaviourData(h);
2043       this->current = beg;
2044       CodeBlockParserOptions o;
2045       o.mn = d.getRegistredMembersNames();
2046       o.smn = d.getRegistredStaticMembersNames();
2047       o.qualifyStaticVariables = true;
2048       o.qualifyMemberVariables = true;
2049       o.modifier = std::make_shared<StandardVariableModifier>(
2050           h, [this](const Hypothesis hv, const std::string& v, const bool b) {
2051             return this->standardModifier(hv, v, b);
2052           });
2053       this->mb.appendToPrivateCode(h, this->readNextBlock(o).code, true);
2054     }
2055   }  // end of void BehaviourDSLCommon::treatPrivate
2056 
treatMembers()2057   void BehaviourDSLCommon::treatMembers() {
2058     auto hs = std::set<Hypothesis>{};
2059     this->readHypothesesList(hs);
2060     const auto beg = this->current;
2061     for (const auto& h : hs) {
2062       const auto& d = this->mb.getBehaviourData(h);
2063       this->current = beg;
2064       CodeBlockParserOptions o;
2065       o.mn = d.getRegistredMembersNames();
2066       o.smn = d.getRegistredStaticMembersNames();
2067       o.qualifyStaticVariables = true;
2068       o.qualifyMemberVariables = true;
2069       o.modifier = std::make_shared<StandardVariableModifier>(
2070           h, [this](const Hypothesis hv, const std::string& v, const bool b) {
2071             return this->standardModifier(hv, v, b);
2072           });
2073       this->mb.appendToMembers(h, this->readNextBlock(o).code, true);
2074     }
2075   }  // end of BehaviourDSLCommon::treatMembers
2076 
treatBrick()2077   void BehaviourDSLCommon::treatBrick() {
2078     using Parameters = AbstractBehaviourBrick::Parameters;
2079     auto& f = BehaviourBrickFactory::getFactory();
2080     auto parameters = Parameters{};
2081     this->checkNotEndOfFile("BehaviourDSLCommon::treatBehaviourBrick",
2082                             "Expected brick name or '<'.");
2083     if (this->current->value == "<") {
2084       auto options = std::vector<tfel::utilities::Token>{};
2085       this->readList(options, "BehaviourDSLCommon::treatBehaviourBrick", "<", ">", true);
2086       for (const auto& o : options) {
2087         const auto pos = o.value.find('=');
2088         if (pos != std::string::npos) {
2089           if (pos == 0) {
2090             this->throwRuntimeError("BehaviourDSLCommon::treatBehaviourBrick",
2091 				    "no parameter name given");
2092           }
2093           // extracting the name
2094           const auto& n = o.value.substr(0, pos);
2095           if (pos == o.value.size()) {
2096             this->throwRuntimeError("BehaviourDSLCommon::treatBehaviourBrick",
2097                                     "no option given to the "
2098                                     "parameter '" +
2099                                         n + "'");
2100           }
2101           // extracting the option
2102           parameters.insert({n, o.value.substr(pos + 1)});
2103         } else {
2104           parameters.insert({o.value, ""});
2105         }
2106       }
2107     }
2108     this->checkNotEndOfFile("BehaviourDSLCommon::treatBehaviourBrick",
2109                             "Expected brick name.");
2110     const auto b = [this]() -> std::string {
2111       if (this->current->flag == tfel::utilities::Token::String) {
2112         return this->readString("BehaviourDSLCommon::treatBehaviourBrick");
2113       }
2114       const auto r = this->current->value;
2115       ++(this->current);
2116       return r;
2117     }();
2118     const auto d = [this] {
2119       using namespace tfel::utilities;
2120       using DataMap = std::map<std::string, Data>;
2121       if ((this->current != this->tokens.end()) &&
2122           (this->current->value == "{")) {
2123         DataParsingOptions o;
2124         o.allowMultipleKeysInMap = true;
2125         return Data::read(this->current, this->tokens.end(), o).get<DataMap>();
2126       }
2127       return DataMap();
2128     }();
2129     const auto br = f.get(b, *this, this->mb);
2130     br->initialize(parameters, d);
2131     this->readSpecifiedToken("BehaviourDSLCommon::treatBehaviourBrick", ";");
2132     this->bricks.push_back(std::move(br));
2133   }  // end of BehaviourDSLCommon::treatBrick
2134 
treatTangentOperator()2135   void BehaviourDSLCommon::treatTangentOperator() {
2136     using namespace std;
2137     using namespace tfel::material;
2138     using namespace tfel::utilities;
2139     CodeBlockOptions o;
2140     this->readCodeBlockOptions(o, true);
2141     if (this->mb.getBehaviourType() == BehaviourDescription::STANDARDFINITESTRAINBEHAVIOUR) {
2142       auto po = o.untreated.begin();
2143       const auto poe = o.untreated.end();
2144       auto ktype = std::string{};
2145       while (po != poe) {
2146         const auto& opt = *po;
2147         if (opt.flag != Token::Standard) {
2148           continue;
2149         }
2150         for (const auto& to : getFiniteStrainBehaviourTangentOperatorFlags()) {
2151           if (opt.value ==
2152               convertFiniteStrainBehaviourTangentOperatorFlagToString(to)) {
2153             ktype = opt.value;
2154             break;
2155           }
2156         }
2157         if (!ktype.empty()) {
2158           o.untreated.erase(po);
2159           break;
2160         }
2161         ++po;
2162       }
2163       if (ktype.empty()) {
2164         ostringstream msg;
2165         msg << "Undefined tangent operator type '" + ktype +
2166                    "'. Valid tangent operator type are :\n";
2167         for (const auto& to : getFiniteStrainBehaviourTangentOperatorFlags()) {
2168           msg << "- "
2169               << convertFiniteStrainBehaviourTangentOperatorFlagToString(to)
2170               << " : " << getFiniteStrainBehaviourTangentOperatorDescription(to)
2171               << '\n';
2172         }
2173         this->throwRuntimeError("BehaviourDSLCommon::treatTangentOperator",
2174                                 msg.str());
2175       }
2176       this->readTangentOperatorCodeBlock(
2177           o, std::string(BehaviourData::ComputeTangentOperator) + "-" + ktype);
2178       for (const auto& h : o.hypotheses) {
2179         if (!this->mb.hasAttribute(h, BehaviourData::hasConsistentTangentOperator)) {
2180           this->mb.setAttribute(h, BehaviourData::hasConsistentTangentOperator, true);
2181         }
2182       }
2183     } else {
2184       this->readTangentOperatorCodeBlock(o,
2185                                          BehaviourData::ComputeTangentOperator);
2186       for (const auto& h : o.hypotheses) {
2187         this->mb.setAttribute(h, BehaviourData::hasConsistentTangentOperator, true);
2188       }
2189     }
2190   }  // end of BehaviourDSLCommon::treatTangentOperator
2191 
readTangentOperatorCodeBlock(const CodeBlockOptions & o,const std::string & n)2192   void BehaviourDSLCommon::readTangentOperatorCodeBlock(
2193       const CodeBlockOptions& o, const std::string& n) {
2194     this->treatUnsupportedCodeBlockOptions(o);
2195     this->readCodeBlock(*this, o, n,
2196                         &BehaviourDSLCommon::tangentOperatorVariableModifier,
2197                         true);
2198   }  // end of BehaviourDSLCommon::readTangentOperatorCodeBlock
2199 
treatIsTangentOperatorSymmetric()2200   void BehaviourDSLCommon::treatIsTangentOperatorSymmetric() {
2201     auto hs = std::set<Hypothesis>{};
2202     this->readHypothesesList(hs);
2203     this->checkNotEndOfFile("BehaviourDSLCommon::treatIsTangentOperatorSymmetric : ", "Expected 'true' or 'false'.");
2204     auto b = this->readBooleanValue("BehaviourDSLCommon::treatIsTangentOperatorSymmetric");
2205     this->readSpecifiedToken("BehaviourDSLCommon::treatIsTangentOperatorSymmetric", ";");
2206     for (const auto& h : hs) {
2207       this->mb.setAttribute(h, BehaviourData::isConsistentTangentOperatorSymmetric, b);
2208     }
2209   }  // end of BehaviourDSLCommon::treatTangentOperator
2210 
treatLibrary()2211   void BehaviourDSLCommon::treatLibrary() {
2212     const auto& l = this->readOnlyOneToken();
2213     if (!isValidLibraryName(l)) {
2214       this->throwRuntimeError("BehaviourDSLCommon::treatLibrary",
2215                               "invalid library name '" + l + "'");
2216     }
2217     this->mb.setLibrary(l);
2218   }  // end of BehaviourDSLCommon::treatLibrary
2219 
treatComputeThermalExpansion()2220   void BehaviourDSLCommon::treatComputeThermalExpansion() {
2221     using namespace tfel::utilities;
2222     using ExternalMFrontMaterialProperty = BehaviourDescription::ExternalMFrontMaterialProperty;
2223     using DataMap = std::map<std::string, Data>;
2224     const std::string m("BehaviourDSLCommon::treatComputeThermalExpansion");
2225     const auto h = ModellingHypothesis::UNDEFINEDHYPOTHESIS;
2226     const auto n = "thermal_expansion_reference_temperature";
2227     auto throw_if = [this, m](const bool b, const std::string& msg) {
2228       if (b) {
2229         this->throwRuntimeError(m, msg);
2230       }
2231     };
2232     auto addTref = [this, throw_if, h, n](const double v) {
2233       if (this->mb.hasParameter(h, n)) {
2234         const auto Tref = this->mb.getFloattingPointParameterDefaultValue(h, n);
2235         throw_if(tfel::math::ieee754::fpclassify(Tref - v) != FP_ZERO, "inconsistent reference temperature");
2236       } else {
2237         VariableDescription Tref("temperature", n, 1u, 0u);
2238         Tref.description =
2239             "value of the reference temperature for "
2240             "the computation of the thermal expansion";
2241         this->mb.addParameter(h, Tref, BehaviourData::ALREADYREGISTRED);
2242         this->mb.setParameterDefaultValue(h, n, v);
2243         this->mb.setEntryName(h, n, "ThermalExpansionReferenceTemperature");
2244       }
2245     };
2246     auto addTi = [this, h](const double v) {
2247       VariableDescription Ti("temperature", "initial_geometry_reference_temperature", 1u, 0u);
2248       Ti.description = "value of the temperature when the initial geometry was measured";
2249       this->mb.addParameter(h, Ti, BehaviourData::ALREADYREGISTRED);
2250       this->mb.setParameterDefaultValue(h, "initial_geometry_reference_temperature", v);
2251       this->mb.setEntryName(h, "initial_geometry_reference_temperature", "ReferenceTemperatureForInitialGeometry");
2252     };  // end of addTi
2253     throw_if(this->mb.getAttribute<bool>(BehaviourDescription::requiresThermalExpansionCoefficientTensor, false),
2254              "@ComputeThermalExpansion can be used along with "
2255              "@RequireThermalExpansionCoefficientTensor");
2256     const auto& acs = this->readMaterialPropertyOrArrayOfMaterialProperties(m);
2257     this->checkNotEndOfFile(m);
2258     if (this->current->value == "{") {
2259       const auto data = Data::read(this->current, this->tokens.end()).get<DataMap>();
2260       throw_if(data.size() != 1u,
2261                "invalid number of data. "
2262                "Only the 'reference_temperature' is expected");
2263       const auto pd = data.begin();
2264       throw_if(pd->first != "reference_temperature",
2265                "the only data expected is "
2266                "'reference_temperature' (read '" +
2267                    pd->first + "')");
2268       throw_if(!pd->second.is<double>(), "invalid type for data 'reference_temperature'");
2269       addTref(pd->second.get<double>());
2270     }
2271     this->readSpecifiedToken(m, ";");
2272     throw_if((acs.size() != 1u) && (acs.size() != 3u), "invalid number of file names given");
2273     if (acs.size() == 3u) {
2274       // the material shall have been declared orthotropic
2275       throw_if(this->mb.getSymmetryType() != mfront::ORTHOTROPIC,
2276                "the mechanical behaviour must be orthotropic "
2277                "to give more than one thermal expansion coefficient.");
2278     }
2279     for (const auto& a : acs) {
2280       if (a.is<ExternalMFrontMaterialProperty>()) {
2281         const auto& mpd = *(a.get<ExternalMFrontMaterialProperty>().mpd);
2282         if (mpd.staticVars.contains("ReferenceTemperature")) {
2283           const auto Tref = mpd.staticVars.get("ReferenceTemperature");
2284           addTref(Tref.value);
2285         } else {
2286           if (getVerboseMode() != VERBOSE_QUIET) {
2287             auto& os = getLogStream();
2288             os << "no reference temperature in material property '";
2289             if (mpd.material.empty()) {
2290               os << mpd.material << '_';
2291             }
2292             os << mpd.law << "'\n";
2293           }
2294         }
2295       }
2296     }
2297     if (acs.size() == 1u) {
2298       this->mb.setThermalExpansionCoefficient(acs.front());
2299     } else {
2300       this->mb.setThermalExpansionCoefficients(acs[0], acs[1], acs[2]);
2301     }
2302     if (!this->mb.hasParameter(h, n)) {
2303       addTref(293.15);
2304     }
2305     if (!this->mb.hasParameter(h, "initial_geometry_reference_temperature")) {
2306       addTi(293.15);
2307     }
2308   }  // end of BehaviourDSLCommon::treatComputeThermalExpansion
2309 
treatElasticMaterialProperties()2310   void BehaviourDSLCommon::treatElasticMaterialProperties() {
2311     if (this->mb.getAttribute<bool>(BehaviourDescription::requiresStiffnessTensor, false)) {
2312       this->throwRuntimeError("BehaviourDSLCommon::treatElasticMaterialProperties",
2313                               "@ElasticMaterialProperties can not be used along with "
2314                               "@RequireStiffnessTensor");
2315     }
2316     this->readElasticMaterialProperties();
2317   }
2318 
extractMaterialProperty(const std::string & m,const tfel::utilities::Token & t)2319   BehaviourDescription::MaterialProperty BehaviourDSLCommon::extractMaterialProperty(const std::string& m,
2320                                                                                      const tfel::utilities::Token& t) {
2321     if (t.flag == tfel::utilities::Token::String) {
2322       // file name of formula
2323       const auto f = t.value.substr(1, t.value.size() - 2);
2324       if (tfel::utilities::ends_with(f, ".mfront")) {
2325         // file name
2326         BehaviourDescription::ExternalMFrontMaterialProperty mp;
2327         mp.mpd = this->handleMaterialPropertyDescription(f);
2328         return std::move(mp);
2329       } else {
2330         BehaviourDescription::AnalyticMaterialProperty mp;
2331         mp.f = f;
2332         return std::move(mp);
2333       }
2334     }
2335     BehaviourDescription::ConstantMaterialProperty mp;
2336     try {
2337       mp.value = std::stold(t.value);
2338     } catch (std::exception& e) {
2339       this->throwRuntimeError(m, "can't convert token '" + t.value +
2340                                      "' to long double "
2341                                      "(" +
2342                                      std::string(e.what()) + ")");
2343     }
2344     return std::move(mp);
2345   }
2346 
2347   std::vector<BehaviourDescription::MaterialProperty>
readMaterialPropertyOrArrayOfMaterialProperties(const std::string & m)2348   BehaviourDSLCommon::readMaterialPropertyOrArrayOfMaterialProperties(const std::string& m) {
2349     auto mps = std::vector<BehaviourDescription::MaterialProperty>{};
2350     this->checkNotEndOfFile(m);
2351     if (this->current->value == "{") {
2352       auto mpv = std::vector<tfel::utilities::Token>{};
2353       this->readList(mpv, m, "{", "}", false);
2354       for (const auto& t : mpv) {
2355         mps.push_back(this->extractMaterialProperty(m, t));
2356       }
2357     } else {
2358       mps.push_back(this->extractMaterialProperty(m, *(this->current)));
2359       ++(this->current);
2360     }
2361     return mps;
2362   }
2363 
readElasticMaterialProperties()2364   void BehaviourDSLCommon::readElasticMaterialProperties() {
2365     const auto& emps =
2366         this->readMaterialPropertyOrArrayOfMaterialProperties("BehaviourDSLCommon::readElasticMaterialProperties");
2367     this->readSpecifiedToken("BehaviourDSLCommon::readElasticMaterialProperties", ";");
2368     if ((emps.size() != 2u) && (emps.size() != 9u)) {
2369       this->throwRuntimeError("BehaviourDSLCommon::readElasticMaterialProperties",
2370                               "invalid number of file names given");
2371     }
2372     if (emps.size() == 9u) {
2373       // the material shall have been declared orthotropic
2374       if (this->mb.getSymmetryType() != mfront::ORTHOTROPIC) {
2375         this->throwRuntimeError("BehaviourDSLCommon::readElasticMaterialProperties",
2376                                 "the mechanical behaviour must be orthotropic to give more than "
2377                                 "two elastic material properties.");
2378       }
2379       setElasticSymmetryType(this->mb, mfront::ORTHOTROPIC);
2380     } else {
2381       setElasticSymmetryType(this->mb, mfront::ISOTROPIC);
2382     }
2383     this->mb.setElasticMaterialProperties(emps);
2384   }
2385 
treatComputeStiffnessTensor()2386   void BehaviourDSLCommon::treatComputeStiffnessTensor() {
2387     if (this->mb.getAttribute<bool>(BehaviourDescription::requiresStiffnessTensor, false)) {
2388       this->throwRuntimeError("BehaviourDSLCommon::treatComputeStiffnessTensor",
2389                               "@ComputeStiffnessTensor can be used along with "
2390                               "@RequireStiffnessTensor");
2391     }
2392     if (this->current->value == "<") {
2393       this->treatStiffnessTensorOption();
2394     }
2395     this->readElasticMaterialProperties();
2396     this->mb.setAttribute(BehaviourDescription::computesStiffnessTensor, true, false);
2397   }  // end of BehaviourDSLCommon::treatComputeStiffnessTensor
2398 
treatHillTensor()2399   void BehaviourDSLCommon::treatHillTensor() {
2400     if (this->mb.getSymmetryType() != mfront::ORTHOTROPIC) {
2401       this->throwRuntimeError("BehaviourDSLCommon::treatHillTensor",
2402                               "the mechanical behaviour must be orthotropic to define "
2403                               "a Hill tensor.");
2404     }
2405     this->checkNotEndOfFile("BehaviourDSLCommon::treatModellingHypothesis");
2406     // variable name
2407     if (!this->isValidIdentifier(this->current->value)) {
2408       this->throwRuntimeError("BehaviourDSLCommon::treatHillTensor: ",
2409                               "variable name is not valid "
2410                               "(read '" +
2411                                   this->current->value + "').");
2412     }
2413     auto v = VariableDescription{"tfel::math::st2tost2<N,stress>", this->current->value, 1u, this->current->line};
2414     v.description = "Hill tensor";
2415     ++(this->current);
2416     // Hill coefficients
2417     const auto& hcs = this->readMaterialPropertyOrArrayOfMaterialProperties("BehaviourDSLCommon::treatHillTensor");
2418     this->readSpecifiedToken("BehaviourDSLCommon::treatHillTensor", ";");
2419     if (hcs.size() != 6u) {
2420       this->throwRuntimeError("BehaviourDSLCommon::treatHillTensor", "invalid number of hill coefficients");
2421     }
2422     this->mb.addHillTensor(v, hcs);
2423   }  // end of BehaviourDSLCommon::treatHillTensor
2424 
treatModellingHypothesis()2425   void BehaviourDSLCommon::treatModellingHypothesis() {
2426     this->checkNotEndOfFile("BehaviourDSLCommon::treatModellingHypothesis");
2427     const auto h = ModellingHypothesis::fromString(this->current->value);
2428     ++(this->current);
2429     this->checkNotEndOfFile("BehaviourDSLCommon::treatModellingHypothesis");
2430     this->readSpecifiedToken("BehaviourDSLCommon::treatModellingHypothesis", ";");
2431     if (!this->isModellingHypothesisSupported(h)) {
2432       this->throwRuntimeError("BehaviourDSLCommon::treatModellingHypothesis",
2433                               "unsupported modelling hypothesis '" + ModellingHypothesis::toString(h) + "'");
2434     }
2435     std::set<Hypothesis> hypotheses;
2436     hypotheses.insert(h);
2437     this->mb.setModellingHypotheses(hypotheses);
2438   }  // end of BehaviourDSLCommon::treatModellingHypothesis
2439 
treatModellingHypotheses()2440   void BehaviourDSLCommon::treatModellingHypotheses() {
2441     using namespace tfel::utilities;
2442     auto hypotheses = std::set<Hypothesis>{};
2443     auto values = std::vector<Token>{};
2444     this->checkNotEndOfFile("BehaviourDSLCommon::treatModellingHypotheses");
2445     this->readList(values, "BehaviourDSLCommon::treatModellingHypotheses", "{", "}", false);
2446     this->checkNotEndOfFile("BehaviourDSLCommon::treatModellingHypotheses");
2447     this->readSpecifiedToken("BehaviourDSLCommon::treatModellingHypotheses", ";");
2448     for (const auto& v : values) {
2449       if (v.flag == Token::String) {
2450         this->appendToHypothesesList(hypotheses, v.value.substr(1, v.value.size() - 2));
2451       } else {
2452         this->appendToHypothesesList(hypotheses, v.value);
2453       }
2454     }
2455     if (hypotheses.empty()) {
2456       this->throwRuntimeError("BehaviourDSLCommon::treatModellingHypotheses", "no hypothesis declared");
2457     }
2458     this->mb.setModellingHypotheses(hypotheses);
2459   }  // end of BehaviourDSLCommon::treatModellingHypotheses
2460 
treatUsableInPurelyImplicitResolution()2461   void BehaviourDSLCommon::treatUsableInPurelyImplicitResolution() {
2462     const auto h = ModellingHypothesis::UNDEFINEDHYPOTHESIS;
2463     this->readSpecifiedToken("BehaviourDSLCommon::treatUsableInPurelyImplicitResolution", ";");
2464     if (this->explicitlyDeclaredUsableInPurelyImplicitResolution) {
2465       this->throwRuntimeError("BehaviourDSLCommon::treatUsableInPurelyImplicitResolution",
2466                               "keyword '@UsableInPurelyImplicitResolution' already called");
2467     }
2468     this->explicitlyDeclaredUsableInPurelyImplicitResolution = true;
2469     this->mb.setUsableInPurelyImplicitResolution(h, true);
2470   }  // end of BehaviourDSLCommon::treatUsableInPurelyImplicitResolution
2471 
treatParameterMethod(const Hypothesis h)2472   void BehaviourDSLCommon::treatParameterMethod(const Hypothesis h) {
2473     using namespace std;
2474     using namespace tfel::utilities;
2475     const auto n = tfel::unicode::getMangledString(this->current->value);
2476     ++(this->current);
2477     this->checkNotEndOfFile("BehaviourDSLCommon::treatParameterMethod");
2478     this->readSpecifiedToken("BehaviourDSLCommon::treatParameterMethod", ".");
2479     this->checkNotEndOfFile("BehaviourDSLCommon::treatParameterMethod");
2480     if (this->current->value == "setDefaultValue") {
2481       ++(this->current);
2482       this->checkNotEndOfFile("BehaviourDSLCommon::treatParameterMethod");
2483       this->readSpecifiedToken("BehaviourDSLCommon::treatParameterMethod", "(");
2484       this->checkNotEndOfFile("BehaviourDSLCommon::treatParameterMethod");
2485       double value = tfel::utilities::convert<double>(this->current->value);
2486       ++(this->current);
2487       this->checkNotEndOfFile("BehaviourDSLCommon::treatParameterMethod");
2488       this->readSpecifiedToken("BehaviourDSLCommon::treatParameterMethod", ")");
2489       this->checkNotEndOfFile("BehaviourDSLCommon::treatParameterMethod");
2490       this->readSpecifiedToken("BehaviourDSLCommon::treatParameterMethod", ";");
2491       this->mb.setParameterDefaultValue(h, n, value);
2492     } else {
2493       --(this->current);
2494       --(this->current);
2495       this->treatVariableMethod(h);
2496     }
2497   }  // end of BehaviourDSLCommon::treatParameterMethod
2498 
isCallableVariable(const Hypothesis h,const std::string & n) const2499   bool BehaviourDSLCommon::isCallableVariable(const Hypothesis h,
2500                                               const std::string& n) const {
2501     if (h == ModellingHypothesis::UNDEFINEDHYPOTHESIS) {
2502       for (const auto& g : this->gradients) {
2503         if (g.name == n) {
2504           return true;
2505         }
2506       }
2507       for (const auto& f : this->thermodynamic_forces) {
2508         if (f.name == n) {
2509           return true;
2510         }
2511       }
2512       if (this->mb.isGradientName(n) || this->mb.isThermodynamicForceName(n)) {
2513         return true;
2514       }
2515     }
2516     return ((this->mb.isMaterialPropertyName(h, n)) ||
2517             (this->mb.isStateVariableName(h, n)) ||
2518             (this->mb.isAuxiliaryStateVariableName(h, n)) ||
2519             (this->mb.isExternalStateVariableName(h, n)) ||
2520             (this->mb.isLocalVariableName(h, n)) ||
2521             (this->mb.isStaticVariableName(h, n)) ||
2522             (this->mb.isParameterName(h, n)) ||
2523             (this->mb.isIntegrationVariableName(h, n)));
2524   }  // end of BehaviourDSLCommon::isCallableVariable
2525 
treatSetGlossaryNameMethod()2526   std::string BehaviourDSLCommon::treatSetGlossaryNameMethod() {
2527     using namespace tfel::utilities;
2528     using namespace tfel::glossary;
2529     const auto& glossary = Glossary::getGlossary();
2530     this->checkNotEndOfFile("BehaviourDSLCommon::treatSetGlossaryMethod");
2531     this->readSpecifiedToken("BehaviourDSLCommon::treatSetGlossaryMethod",
2532                              "setGlossaryName");
2533     this->readSpecifiedToken("BehaviourDSLCommon::treatSetGlossaryMethod", "(");
2534     this->checkNotEndOfFile("BehaviourDSLCommon::treatSetGlossaryMethod");
2535     if (this->current->flag != Token::String) {
2536       this->throwRuntimeError("BehaviourDSLCommon::treatSetGlossaryMethod: ",
2537                               "expected to read a string");
2538     }
2539     const auto& g =
2540         this->current->value.substr(1, this->current->value.size() - 2);
2541     if (!glossary.contains(g)) {
2542       this->throwRuntimeError("BehaviourDSLCommon::treatSetGlossaryMethod: ",
2543                               "'" + g + "' is not a glossary name");
2544     }
2545     ++(this->current);
2546     this->checkNotEndOfFile("BehaviourDSLCommon::treatSetGlossaryMethod");
2547     this->readSpecifiedToken("BehaviourDSLCommon::treatSetGlossaryMethod", ")");
2548     return g;
2549   }  // end of treatSetGlossaryNameMethod
2550 
treatSetEntryNameMethod()2551   std::string BehaviourDSLCommon::treatSetEntryNameMethod() {
2552     using namespace tfel::utilities;
2553     this->checkNotEndOfFile("BehaviourDSLCommon::treatSetEntryNameMethod");
2554     this->readSpecifiedToken("BehaviourDSLCommon::treatSetEntryNameMethod",
2555                              "setEntryName");
2556     this->checkNotEndOfFile("BehaviourDSLCommon::treatSetEntryNameMethod");
2557     this->readSpecifiedToken("BehaviourDSLCommon::treatSetEntryNameMethod", "(");
2558     this->checkNotEndOfFile("BehaviourDSLCommon::treatSetEntryNameMethod");
2559     if (this->current->flag != Token::String) {
2560       this->throwRuntimeError("BehaviourDSLCommon::treatSetEntryNameMethod: ",
2561                               "expected to read a string");
2562     }
2563     const auto& e =
2564         this->current->value.substr(1, this->current->value.size() - 2);
2565     if (!this->isValidIdentifier(e)) {
2566       this->throwRuntimeError("BehaviourDSLCommon::treatSetEntryNameMethod: ",
2567                               "invalid entry name '" + e + "'");
2568     }
2569     ++(this->current);
2570     this->readSpecifiedToken("BehaviourDSLCommon::treatSetEntryNameMethod",
2571                              ")");
2572     return e;
2573   }  // end of treatSetEntryNameMethod
2574 
treatGradientMethod()2575   void BehaviourDSLCommon::treatGradientMethod() {
2576     const auto n = tfel::unicode::getMangledString(this->current->value);
2577     ++(this->current);
2578     this->checkNotEndOfFile("BehaviourDSLCommon::treatGradientMethod");
2579     this->readSpecifiedToken("BehaviourDSLCommon::treatGradientMethod", ".");
2580     this->checkNotEndOfFile("BehaviourDSLCommon::treatGradientMethod");
2581     if (this->current->value == "setGlossaryName") {
2582       const auto gn = this->treatSetGlossaryNameMethod();
2583       bool treated = false;
2584       for (auto& g : this->gradients) {
2585         if (g.name == n) {
2586           g.setGlossaryName(gn);
2587           treated = true;
2588           break;
2589         }
2590       }
2591       if (!treated) {
2592         if (!this->mb.isGradientName(n)) {
2593           this->throwRuntimeError(
2594               "BehaviourDSLCommon::treatGradientMethod",
2595               "invalid call, '" +
2596               n + "' is not a registred gradient");
2597         }
2598         this->mb.setGlossaryName(n, gn);
2599       }
2600     } else if (this->current->value == "setEntryName") {
2601       const auto e = this->treatSetEntryNameMethod();
2602       bool treated = false;
2603       for (auto& g : this->gradients) {
2604         if (g.name == n) {
2605           g.setEntryName(e);
2606           treated = true;
2607           break;
2608         }
2609       }
2610       if (!treated) {
2611         if (!this->mb.isGradientName(n)) {
2612           this->throwRuntimeError(
2613               "BehaviourDSLCommon::treatGradientMethod",
2614               "invalid call, '" +
2615               n + "' is not a registred gradient");
2616         }
2617         this->mb.setEntryName(n, e);
2618       }
2619     } else {
2620       this->throwRuntimeError(
2621           "BehaviourDSLCommon::treatGradientMethod",
2622           "unsupported method '" + this->current->value + "'");
2623     }
2624     this->checkNotEndOfFile("BehaviourDSLCommon::treatGradientMethod");
2625     this->readSpecifiedToken("BehaviourDSLCommon::treatGradientMethod", ";");
2626   }  // end of BehaviourDSLCommon::treatGradientMethod
2627 
treatThermodynamicForceMethod()2628   void BehaviourDSLCommon::treatThermodynamicForceMethod() {
2629     const auto n = tfel::unicode::getMangledString(this->current->value);
2630     ++(this->current);
2631     this->checkNotEndOfFile(
2632         "BehaviourDSLCommon::treatThermodynamicForceMethod");
2633     this->readSpecifiedToken(
2634         "BehaviourDSLCommon::treatThermodynamicForceMethod", ".");
2635     this->checkNotEndOfFile("BehaviourDSLCommon::treatThermodynamicForceMethod");
2636     if (this->current->value == "setGlossaryName") {
2637       const auto gn = this->treatSetGlossaryNameMethod();
2638       bool treated = false;
2639       for (auto& f : this->thermodynamic_forces) {
2640         if (f.name == n) {
2641           f.setGlossaryName(gn);
2642           treated = true;
2643           break;
2644         }
2645       }
2646       if (!treated) {
2647         if (!this->mb.isThermodynamicForceName(n)) {
2648           this->throwRuntimeError(
2649               "BehaviourDSLCommon::treatThermodynamicForceMethod",
2650               "invalid call, '" +
2651               n + "' is not a registred thermodynamic force");
2652         }
2653         this->mb.setGlossaryName(n, gn);
2654       }
2655     } else if (this->current->value == "setEntryName") {
2656       const auto e = this->treatSetEntryNameMethod();
2657       bool treated = false;
2658       for (auto& f : this->thermodynamic_forces) {
2659         if (f.name == n) {
2660           f.setEntryName(e);
2661           treated = true;
2662           break;
2663         }
2664       }
2665       if (!treated) {
2666         if (!this->mb.isThermodynamicForceName(n)) {
2667           this->throwRuntimeError(
2668               "BehaviourDSLCommon::treatThermodynamicForceMethod",
2669               "invalid call, '" +
2670               n + "' is not a registred thermodynamic force");
2671         }
2672         this->mb.setEntryName(n, e);
2673       }
2674     } else {
2675       this->throwRuntimeError(
2676           "BehaviourDSLCommon::treatThermodynamicForceMethod",
2677           "unsupported method '" + this->current->value + "'");
2678     }
2679     this->checkNotEndOfFile(
2680         "BehaviourDSLCommon::treatThermodynamicForceMethod");
2681     this->readSpecifiedToken(
2682         "BehaviourDSLCommon::treatThermodynamicForceMethod", ";");
2683   }  // end of BehaviourDSLCommon::treatThermodynamicForceMethod
2684 
treatVariableMethod(const Hypothesis h)2685   void BehaviourDSLCommon::treatVariableMethod(const Hypothesis h) {
2686     const auto n = tfel::unicode::getMangledString(this->current->value);
2687     ++(this->current);
2688     this->checkNotEndOfFile("BehaviourDSLCommon::treatVariableMethod");
2689     this->readSpecifiedToken("BehaviourDSLCommon::treatVariableMethod", ".");
2690     this->checkNotEndOfFile("BehaviourDSLCommon::treatVariableMethod");
2691     if (this->current->value == "setGlossaryName") {
2692       this->mb.setGlossaryName(h, n, this->treatSetGlossaryNameMethod());
2693     } else if (this->current->value == "setEntryName") {
2694       this->mb.setEntryName(h, n, this->treatSetEntryNameMethod());
2695     } else {
2696       this->treatUnknownVariableMethod(h, n);
2697     }
2698     this->checkNotEndOfFile("BehaviourDSLCommon::treatVariableMethod");
2699     this->readSpecifiedToken("BehaviourDSLCommon::treatVariableMethod", ";");
2700   }  // end of BehaviourDSLCommon::treatVariableMethod
2701 
treatUnknownVariableMethod(const Hypothesis,const std::string & n)2702   void BehaviourDSLCommon::treatUnknownVariableMethod(const Hypothesis, const std::string& n) {
2703     this->throwRuntimeError("BehaviourDSLCommon::treatUnknownVariableMethod : ",
2704                             "unknown method '" + this->current->value + "' for variable '" + n +
2705                                 "', "
2706                                 "valid methods are 'setGlossaryName' or 'setEntryName'");
2707   }  // end of BehaviourDSLCommon::treatUnknownVariableMethod
2708 
treatUnknownKeyword()2709   void BehaviourDSLCommon::treatUnknownKeyword() {
2710     TokensContainer::const_iterator p2;
2711     auto treated = false;
2712     --(this->current);
2713     const auto key = this->current->value;
2714     ++(this->current);
2715     this->checkNotEndOfFile("BehaviourDSLCommon::treatUnknownKeyword");
2716     for (const auto& b : bricks) {
2717       auto p = b->treatKeyword(key, this->current, this->tokens.end());
2718       if (p.first) {
2719         if (treated) {
2720           if (p2 != p.second) {
2721             this->throwRuntimeError("BehaviourDSLCommon::treatUnknownKeyword", "the keyword '" + key +
2722                                                                                    "' has been treated "
2723                                                                                    "by two interfaces/analysers but "
2724                                                                                    "results were differents");
2725           }
2726         }
2727         p2 = p.second;
2728         treated = true;
2729       }
2730     }
2731     if (!treated) {
2732       if (this->current->value == "[") {
2733         ++(this->current);
2734         this->checkNotEndOfFile("BehaviourDSLCommon::treatUnknownKeyword");
2735         auto s = std::vector<std::string>{};
2736         while (this->current->value != "]") {
2737           this->checkNotEndOfFile("BehaviourDSLCommon::treatUnknownKeyword");
2738           const auto t = [this]() -> std::string {
2739             if (this->current->flag == tfel::utilities::Token::String) {
2740               return this->current->value.substr(1, this->current->value.size() - 2);
2741             }
2742             return this->current->value;
2743           }();
2744           ++(this->current);
2745           this->checkNotEndOfFile("BehaviourDSLCommon::treatUnknownKeyword");
2746           if (std::find(s.begin(), s.end(), t) == s.end()) {
2747             s.push_back(t);
2748           }
2749           if (this->current->value != "]") {
2750             this->readSpecifiedToken("BehaviourDSLCommon::treatUnknownKeyword", ",");
2751             this->checkNotEndOfFile("BehaviourDSLCommon::treatUnknownKeyword");
2752             if (this->current->value == "]") {
2753               this->throwRuntimeError("BehaviourDSLCommon::treatUnknownKeyword", "unexpected token ']'");
2754             }
2755           }
2756         }
2757         ++(this->current);
2758         for (auto& i : this->interfaces) {
2759           auto p = i.second->treatKeyword(this->mb, key, s, this->current, this->tokens.end());
2760           if (p.first) {
2761             if (treated) {
2762               if (p2 != p.second) {
2763                 this->throwRuntimeError("BehaviourDSLCommon::treatUnknownKeyword",
2764                                         "the keyword '" + key +
2765                                             "' has been treated "
2766                                             "by two interfaces/analysers but "
2767                                             "results were differents");
2768               }
2769             }
2770             p2 = p.second;
2771             treated = true;
2772           }
2773         }
2774         if (!treated) {
2775           this->ignoreKeyWord(key);
2776           return;
2777         }
2778       } else {
2779         for (const auto& i : this->interfaces) {
2780           auto p = i.second->treatKeyword(this->mb, key, {}, this->current, this->tokens.end());
2781           if (p.first) {
2782             if (treated) {
2783               if (p2 != p.second) {
2784                 this->throwRuntimeError("BehaviourDSLCommon::treatUnknownKeyword",
2785                                         "the keyword '" + key +
2786                                             "' has been treated "
2787                                             "by two interfaces/analysers but "
2788                                             "results were differents");
2789               }
2790             }
2791             p2 = p.second;
2792             treated = true;
2793           }
2794         }
2795       }
2796     }
2797     if (!treated) {
2798       DSLBase::treatUnknownKeyword();
2799     }
2800     this->current = p2;
2801   }  // end of BehaviourDSLCommon::treatUnknownKeyword
2802 
treatUseQt()2803   void BehaviourDSLCommon::treatUseQt() {
2804     this->checkNotEndOfFile("BehaviourDSLCommon::treatUseQt : ", "Expected 'true' or 'false'.");
2805     if (this->current->value == "true") {
2806       this->mb.setUseQt(true);
2807     } else if (this->current->value == "false") {
2808       this->mb.setUseQt(false);
2809     } else {
2810       this->throwRuntimeError("BehaviourDSLCommon::treatUseQt",
2811                               "Expected to read 'true' or 'false' instead of '" + this->current->value + ".");
2812     }
2813     ++(this->current);
2814     this->readSpecifiedToken("BehaviourDSLCommon::treatUseQt", ";");
2815   }  // end of BehaviourDSLCommon::treatUseQt
2816 
treatIsotropicBehaviour()2817   void BehaviourDSLCommon::treatIsotropicBehaviour() {
2818     if (this->mb.getSymmetryType() != mfront::ISOTROPIC) {
2819       this->throwRuntimeError("BehaviourDSLCommon::treatIsotropicBehaviour",
2820                               "this behaviour has been declared orthotropic");
2821     }
2822     this->readSpecifiedToken("BehaviourDSLCommon::treatIsotropicBehaviour", ";");
2823   }  // end of BehaviourDSLCommon::treatIsotropicBehaviour
2824 
treatOrthotropicBehaviour()2825   void BehaviourDSLCommon::treatOrthotropicBehaviour() {
2826     using namespace tfel::material;
2827     auto c = OrthotropicAxesConvention::DEFAULT;
2828     this->checkNotEndOfFile("BehaviourDSLCommon::treatOrthotropicBehaviour");
2829     if (this->current->value == "<") {
2830       this->readSpecifiedToken("BehaviourDSLCommon::treatOrthotropicBehaviour", "<");
2831       this->checkNotEndOfFile("BehaviourDSLCommon::treatOrthotropicBehaviour");
2832       if (this->current->value == "Pipe") {
2833         ++this->current;
2834         c = OrthotropicAxesConvention::PIPE;
2835       } else if (this->current->value == "Plate") {
2836         ++this->current;
2837         c = OrthotropicAxesConvention::PLATE;
2838       } else if (this->current->value == "Default") {
2839         ++this->current;
2840       } else {
2841         this->throwRuntimeError("BehaviourDSLCommon::treatOrthotropicBehaviour",
2842                                 "unsupported orthotropic axes convention");
2843       }
2844       this->readSpecifiedToken("BehaviourDSLCommon::treatOrthotropicBehaviour", ">");
2845     }
2846     this->readSpecifiedToken("BehaviourDSLCommon::treatOrthotropicBehaviour", ";");
2847     this->mb.setSymmetryType(mfront::ORTHOTROPIC);
2848     this->mb.setOrthotropicAxesConvention(c);
2849   }  // end of BehaviourDSLCommon::treatOrthotropicBehaviour
2850 
treatIsotropicElasticBehaviour()2851   void BehaviourDSLCommon::treatIsotropicElasticBehaviour() {
2852     this->readSpecifiedToken("BehaviourDSLCommon::treatIsotropicElasticBehaviour", ";");
2853     if (this->mb.getSymmetryType() != mfront::ORTHOTROPIC) {
2854       this->throwRuntimeError("BehaviourDSLCommon::treatIsotropicElasticBehaviour",
2855                               "this behaviour has not been declared orthotropic");
2856     }
2857     this->mb.setElasticSymmetryType(mfront::ISOTROPIC);
2858   }  // end of BehaviourDSLCommon::treatIsotropicElasticBehaviour
2859 
treatRequireStiffnessOperator()2860   void BehaviourDSLCommon::treatRequireStiffnessOperator() {
2861     if (getVerboseMode() >= VERBOSE_LEVEL2) {
2862       getLogStream() << "BehaviourDSLCommon::treatRequireStiffnessOperator : "
2863                      << "@RequireStiffnessOperator is deprecated\n"
2864                      << "You shall use @RequireStiffnessTensor instead\n";
2865     }
2866     this->treatRequireStiffnessTensor();
2867   }  // end of BehaviourDSLCommon::treatRequireStiffnessOperator
2868 
treatStiffnessTensorOption()2869   void BehaviourDSLCommon::treatStiffnessTensorOption() {
2870     this->readSpecifiedToken("BehaviourDSLCommon::treatStiffnessTensorOption", "<");
2871     this->checkNotEndOfFile("BehaviourDSLCommon::treatStiffnessTensorOption");
2872     if (this->current->value == "UnAltered") {
2873       this->mb.setAttribute(BehaviourDescription::requiresUnAlteredStiffnessTensor, true, false);
2874     } else if (this->current->value == "Altered") {
2875       this->mb.setAttribute(BehaviourDescription::requiresUnAlteredStiffnessTensor, false, false);
2876     } else {
2877       this->throwRuntimeError("BehaviourDSLCommon::treatStiffnessTensorOption : ",
2878                               "expected 'Altered' or 'UnAltered' option "
2879                               "(read '" +
2880                                   this->current->value + "')");
2881     }
2882     ++(this->current);
2883     this->readSpecifiedToken("BehaviourDSLCommon::treatStiffnessTensorOption", ">");
2884   }
2885 
treatRequireStiffnessTensor()2886   void BehaviourDSLCommon::treatRequireStiffnessTensor() {
2887     if (this->mb.hasAttribute(BehaviourDescription::computesStiffnessTensor)) {
2888       this->throwRuntimeError("BehaviourDSLCommon::treatRequireStiffnessTensor",
2889                               "@RequireStiffnessTensor can be used along with "
2890                               "@ComputeStiffnessTensor");
2891     }
2892     this->checkNotEndOfFile("BehaviourDSLCommon::treatRequireStiffnessTensor");
2893     if (this->current->value == "<") {
2894       this->treatStiffnessTensorOption();
2895     }
2896     this->readSpecifiedToken("BehaviourDSLCommon::treatRequireStiffnessTensor", ";");
2897     this->mb.setAttribute(BehaviourDescription::requiresStiffnessTensor, true, false);
2898   }  // end of BehaviourDSLCommon::treatRequireStiffnessTensor
2899 
treatRequireThermalExpansionCoefficientTensor()2900   void BehaviourDSLCommon::treatRequireThermalExpansionCoefficientTensor() {
2901     this->readSpecifiedToken("BehaviourDSLCommon::treatRequireThermalExpansionCoefficientTensor", ";");
2902     this->mb.setAttribute(BehaviourDescription::requiresThermalExpansionCoefficientTensor, true, false);
2903   }  // end of BehaviourDSLCommon::treatRequireThermalExpansionCoefficientTensor
2904 
setMaterialKnowledgeIdentifier(const std::string & i)2905   void BehaviourDSLCommon::setMaterialKnowledgeIdentifier(const std::string& i) {
2906     if (!isValidBehaviourName(i)) {
2907       this->throwRuntimeError("BehaviourDSLCommon::setMaterialKnowledgeIdentifier",
2908                               "invalid behaviour name '" + i+ "'");
2909     }
2910     this->mb.setBehaviourName(i);
2911     if (!isValidIdentifier(this->mb.getClassName())) {
2912       this->throwRuntimeError("BehaviourDSLCommon::setMaterialKnowledgeIdentifier",
2913                               "resulting class name is not valid (read '" +
2914                                   this->mb.getClassName() + "')");
2915     }
2916   }  // end of BehaviourDSLCommon::setMaterialKnowledgeIdentifier
2917 
treatBehaviour()2918   void BehaviourDSLCommon::treatBehaviour() {
2919     const auto& b = this->readOnlyOneToken();
2920     if (!isValidBehaviourName(b)) {
2921       this->throwRuntimeError("BehaviourDSLCommon::treatBehaviour",
2922                               "invalid behaviour name '" + b + "'");
2923     }
2924     if (this->overriden_implementation_name.empty()) {
2925       this->setMaterialKnowledgeIdentifier(b);
2926     }
2927   }  // end of BehaviourDSLCommon::treatBehaviour
2928 
readStringList(std::vector<std::string> & cont)2929   void BehaviourDSLCommon::readStringList(std::vector<std::string>& cont) {
2930     this->checkNotEndOfFile("BehaviourDSLCommon::readStringList", "Cannot read interface name.");
2931     auto endOfTreatment = false;
2932     while ((this->current != this->tokens.end()) && (!endOfTreatment)) {
2933       const auto s = this->current->value;
2934       if (!isValidIdentifier(s)) {
2935         --(this->current);
2936         this->throwRuntimeError("BehaviourDSLCommon::readStringList", "interface name is not valid (read '" + s + "')");
2937       }
2938       ++(this->current);
2939       this->checkNotEndOfFile("BehaviourDSLCommon::readStringList");
2940       if (this->current->value == ",") {
2941         ++(this->current);
2942       } else if (this->current->value == ";") {
2943         endOfTreatment = true;
2944         ++(this->current);
2945       } else {
2946         this->throwRuntimeError("BehaviourDSLCommon::readStringList", "',' or ';' expected after '" + s + "'");
2947       }
2948       if (find(cont.begin(), cont.end(), s) != cont.end()) {
2949         this->throwRuntimeError("BehaviourDSLCommon::readStringList", "'" + s + "' has already been registred.\n");
2950       }
2951       cont.push_back(s);
2952     }
2953     if (!endOfTreatment) {
2954       --(this->current);
2955       this->throwRuntimeError("BehaviourDSLCommon::readStringList", "Expected ';' before end of file.");
2956     }
2957   }
2958 
readHypothesesList()2959   std::set<BehaviourDSLCommon::Hypothesis> BehaviourDSLCommon::readHypothesesList() {
2960     std::set<Hypothesis> mh;
2961     this->readHypothesesList(mh);
2962     return mh;
2963   }  // end of BehaviourDSLCommon::readHypothesesList
2964 
readHypothesesList(std::set<Hypothesis> & h)2965   void BehaviourDSLCommon::readHypothesesList(std::set<Hypothesis>& h) {
2966     h.clear();
2967     if (this->current == this->tokens.end()) {
2968       h.insert(ModellingHypothesis::UNDEFINEDHYPOTHESIS);
2969       return;
2970     }
2971     if (this->current->value != "<") {
2972       h.insert(ModellingHypothesis::UNDEFINEDHYPOTHESIS);
2973       return;
2974     }
2975     auto values = std::vector<tfel::utilities::Token>{};
2976     this->readList(values, "BehaviourDSLCommon::readHypothesesList", "<", ">", true);
2977     for (const auto& v : values) {
2978       if (v.flag == tfel::utilities::Token::String) {
2979         this->appendToHypothesesList(h, v.value.substr(1, v.value.size() - 2));
2980       } else {
2981         this->appendToHypothesesList(h, v.value);
2982       }
2983     }
2984     if (h.empty()) {
2985       h.insert(ModellingHypothesis::UNDEFINEDHYPOTHESIS);
2986     }
2987   }  // end of BehaviourDSLCommon::readHypothesesList
2988 
readVariableList(VariableDescriptionContainer & v,std::set<Hypothesis> & h,void (BehaviourDescription::* m)(const Hypothesis,const VariableDescriptionContainer &,const BehaviourData::RegistrationStatus),const bool b1)2989   void BehaviourDSLCommon::readVariableList(VariableDescriptionContainer& v,
2990                                             std::set<Hypothesis>& h,
2991                                             void (BehaviourDescription::*m)(const Hypothesis,
2992                                                                             const VariableDescriptionContainer&,
2993                                                                             const BehaviourData::RegistrationStatus),
2994                                             const bool b1) {
2995     h.clear();
2996     v.clear();
2997     this->readHypothesesList(h);
2998     this->readVarList(v, b1);
2999     this->addVariableList(h, v, m);
3000   }  // end of BehaviourDSLCommon::readVariableList
3001 
addVariableList(const std::set<Hypothesis> & hypotheses,const VariableDescriptionContainer & v,void (BehaviourDescription::* m)(const Hypothesis,const VariableDescriptionContainer &,const BehaviourData::RegistrationStatus))3002   void BehaviourDSLCommon::addVariableList(const std::set<Hypothesis>& hypotheses,
3003                                            const VariableDescriptionContainer& v,
3004                                            void (BehaviourDescription::*m)(const Hypothesis,
3005                                                                            const VariableDescriptionContainer&,
3006                                                                            const BehaviourData::RegistrationStatus)) {
3007     for (const auto& h : hypotheses) {
3008       (this->mb.*m)(h, v, BehaviourData::UNREGISTRED);
3009     }
3010   }  // end of BehaviourDSLCommon::addVariableList
3011 
treatCoef()3012   void BehaviourDSLCommon::treatCoef() {
3013     VarContainer v;
3014     auto h = std::set<Hypothesis>{};
3015     this->readVariableList(v, h, &BehaviourDescription::addMaterialProperties, true);
3016   }  // end of BehaviourDSLCommon::treatCoef
3017 
treatLocalVar()3018   void BehaviourDSLCommon::treatLocalVar() {
3019     VarContainer v;
3020     auto h = std::set<Hypothesis>{};
3021     this->readVariableList(v, h, &BehaviourDescription::addLocalVariables, true);
3022   }  // end of BehaviourDSLCommon::treatLocalVar
3023 
treatInterface()3024   void BehaviourDSLCommon::treatInterface() {
3025     auto& mbif = BehaviourInterfaceFactory::getBehaviourInterfaceFactory();
3026     auto inames = std::vector<std::string>{};
3027     this->readStringList(inames);
3028     for (const auto& i : inames) {
3029       if (this->interfaces.count(i) == 0) {
3030         this->interfaces.insert({i, mbif.getInterface(i)});
3031       }
3032     }
3033   }  // end of BehaviourDSLCommon::treatInterface
3034 
setInterfaces(const std::set<std::string> & inames)3035   void BehaviourDSLCommon::setInterfaces(const std::set<std::string>& inames) {
3036     auto& mbif = BehaviourInterfaceFactory::getBehaviourInterfaceFactory();
3037     for (const auto& i : inames) {
3038       if (this->interfaces.count(i) == 0) {
3039         this->interfaces.insert({i, mbif.getInterface(i)});
3040       }
3041     }
3042   }  // end of BehaviourDSLCommon::setInterfaces
3043 
treatAPrioriTimeStepScalingFactor()3044   void BehaviourDSLCommon::treatAPrioriTimeStepScalingFactor() {
3045     this->readCodeBlock(*this, BehaviourData::APrioriTimeStepScalingFactor, &BehaviourDSLCommon::standardModifier, true,
3046                         true);
3047   }
3048 
treatIntegrator()3049   void BehaviourDSLCommon::treatIntegrator() {
3050     this->readCodeBlock(*this, BehaviourData::Integrator, &BehaviourDSLCommon::standardModifier, true, true);
3051   }  // end of BehaviourDSLCommon::treatIntegrator
3052 
treatAPosterioriTimeStepScalingFactor()3053   void BehaviourDSLCommon::treatAPosterioriTimeStepScalingFactor() {
3054     this->readCodeBlock(*this, BehaviourData::APosterioriTimeStepScalingFactor, &BehaviourDSLCommon::standardModifier,
3055                         true, true);
3056   }
3057 
treatStateVariable()3058   void BehaviourDSLCommon::treatStateVariable() {
3059     VarContainer v;
3060     auto h = std::set<Hypothesis>{};
3061     this->readVariableList(v, h, &BehaviourDescription::addStateVariables, true);
3062   } // end of BehaviourDSLCommon::treatStateVariable
3063 
treatAuxiliaryStateVariable()3064   void BehaviourDSLCommon::treatAuxiliaryStateVariable() {
3065     VarContainer v;
3066     auto h = std::set<Hypothesis>{};
3067     this->readVariableList(v, h, &BehaviourDescription::addAuxiliaryStateVariables, true);
3068   }  // end of BehaviourDSLCommon::treatAuxiliaryStateVariable
3069 
treatExternalStateVariable()3070   void BehaviourDSLCommon::treatExternalStateVariable() {
3071     VarContainer v;
3072     auto h = std::set<Hypothesis>{};
3073     this->readVariableList(v, h, &BehaviourDescription::addExternalStateVariables, true);
3074   } // end of BehaviourDSLCommon::treatExternalStateVariable()
3075 
treatBounds()3076   void BehaviourDSLCommon::treatBounds() {
3077     auto hs = std::set<Hypothesis>{};
3078     this->readHypothesesList(hs);
3079     auto b = this->current;
3080     for (const auto& h : hs) {
3081       this->current = b;
3082       const auto r = this->readVariableBounds();
3083       const auto v = extractVariableNameAndArrayPosition(r.first);
3084       if (std::get<1>(v)) {
3085         this->mb.setBounds(h, std::get<0>(v), std::get<2>(v), r.second);
3086       } else {
3087         this->mb.setBounds(h, std::get<0>(v), r.second);
3088       }
3089     }
3090     this->readSpecifiedToken("BehaviourDSLCommon::treatBounds", ";");
3091   }  // end of BehaviourDSLCommon::treatBounds
3092 
treatPhysicalBounds()3093   void BehaviourDSLCommon::treatPhysicalBounds() {
3094     auto hs = std::set<Hypothesis>{};
3095     this->readHypothesesList(hs);
3096     auto b = current;
3097     for (const auto& h : hs) {
3098       this->current = b;
3099       const auto bounds = this->readVariableBounds();
3100       this->mb.setPhysicalBounds(h, bounds.first, bounds.second);
3101     }
3102     this->readSpecifiedToken("BehaviourDSLCommon::treatBounds", ";");
3103   }  // end of BehaviourDSLCommon::treatPhysicalBounds
3104 
registerDefaultVarNames()3105   void BehaviourDSLCommon::registerDefaultVarNames() {
3106     const auto h = ModellingHypothesis::UNDEFINEDHYPOTHESIS;
3107     // all available tangent operators for finite strain behaviours
3108     const auto tos = tfel::material::getFiniteStrainBehaviourTangentOperatorFlags();
3109     // stiffness tensor
3110     this->mb.registerMemberName(h, "D");
3111     // stiffness tensor at the end of the time step
3112     this->mb.registerMemberName(h, "D_tdt");
3113     // tangent operator
3114     this->mb.registerMemberName(h, "Dt");
3115     this->reserveName("N");
3116     this->reserveName("Type");
3117     this->reserveName("use_qt");
3118     this->reserveName("src1");
3119     this->reserveName("src2");
3120     this->reserveName("policy_value");
3121     this->reserveName("integrate");
3122     this->reserveName("Psi_s");
3123     this->reserveName("Psi_d");
3124     this->reserveName("thermal_expansion_reference_temperature");
3125     this->reserveName("initial_geometry_reference_temperature");
3126     this->mb.registerMemberName(h, "computeThermodynamicForces");
3127     this->mb.registerMemberName(h, "computeFinalThermodynamicForces");
3128     this->mb.registerMemberName(h, "computeStressFreeExpansion");
3129     this->mb.registerMemberName(h, "computeInternalEnergy");
3130     this->mb.registerMemberName(h, "computeDissipatedEnergy");
3131     this->mb.registerMemberName(h, "computeFdF");
3132     this->mb.registerMemberName(h, "updateIntegrationVariables");
3133     this->mb.registerMemberName(h, "updateStateVariables");
3134     this->mb.registerMemberName(h, "updateAuxiliaryStateVariables");
3135     this->mb.registerMemberName(h, "getTangentOperator");
3136     this->mb.registerMemberName(h, "getMinimalTimeStepScalingFactor");
3137     this->mb.registerMemberName(h, "computeAPrioriTimeStepScalingFactor");
3138     this->mb.registerMemberName(h, "computeAPrioriTimeStepScalingFactorII");
3139     this->mb.registerMemberName(h, "computeAPosterioriTimeStepScalingFactor");
3140     this->mb.registerMemberName(h, "computeAPosterioriTimeStepScalingFactorII");
3141     this->reserveName("computeTangentOperator_");
3142     this->mb.registerMemberName(h, "computeConsistentTangentOperator");
3143     for (const auto& to : tos) {
3144       const auto ktype = convertFiniteStrainBehaviourTangentOperatorFlagToString(to);
3145       this->mb.registerMemberName(h, ktype);
3146       this->mb.registerMemberName(h, "computeConsistentTangentOperator_" + ktype);
3147       this->mb.registerMemberName(h, "tangentOperator_" + ktype);
3148     }
3149     this->reserveName("tangentOperator_sk2");
3150     this->reserveName("computePredictionOperator");
3151     for (const auto& to : tos) {
3152       const auto ktype = convertFiniteStrainBehaviourTangentOperatorFlagToString(to);
3153       this->mb.registerMemberName(h, "computePredictionOperator_" + ktype);
3154     }
3155     this->reserveName("smt");
3156     this->reserveName("smflag");
3157     this->reserveName("dl0_l0");
3158     this->reserveName("dl1_l0");
3159     this->reserveName("dl01_l0");
3160     this->reserveName("alpha_Ti");
3161     this->reserveName("alpha0_Ti");
3162     this->reserveName("alpha1_Ti");
3163     this->reserveName("alpha2_Ti");
3164     this->reserveName("alpha_T_t");
3165     this->reserveName("alpha_T_t_dt");
3166     this->reserveName("alpha0_T_t");
3167     this->reserveName("alpha0_T_t_dt");
3168     this->reserveName("alpha1_T_t");
3169     this->reserveName("alpha1_T_t_dt");
3170     this->reserveName("alpha2_T_t");
3171     this->reserveName("alpha2_T_t_dt");
3172     this->reserveName("TangentOperator");
3173     this->reserveName("StressFreeExpansionType");
3174     this->reserveName("behaviourData");
3175     this->reserveName("time_scaling_factor");
3176     this->reserveName("mp_bounds_check_status");
3177   }  // end of BehaviourDSLCommon::registerDefaultVarNames
3178 
reserveName(const std::string & n)3179   void BehaviourDSLCommon::reserveName(const std::string& n) {
3180     this->mb.reserveName(ModellingHypothesis::UNDEFINEDHYPOTHESIS, n);
3181   }
3182 
isNameReserved(const std::string & n) const3183   bool BehaviourDSLCommon::isNameReserved(const std::string& n) const { return this->mb.isNameReserved(n); }
3184 
writeVariablesDeclarations(std::ostream & f,const VariableDescriptionContainer & v,const std::string & prefix,const std::string & suffix,const std::string & fileName,const bool useTimeDerivative) const3185   void BehaviourDSLCommon::writeVariablesDeclarations(std::ostream& f,
3186                                                       const VariableDescriptionContainer& v,
3187                                                       const std::string& prefix,
3188                                                       const std::string& suffix,
3189                                                       const std::string& fileName,
3190                                                       const bool useTimeDerivative) const {
3191     for (const auto& e : v) {
3192       this->writeVariableDeclaration(f, e, prefix, suffix, fileName, useTimeDerivative);
3193     }
3194   }  // end of BehaviourDSLCommon::writeVariablesDeclarations
3195 
writeVariableDeclaration(std::ostream & f,const VariableDescription & v,const std::string & prefix,const std::string & suffix,const std::string & fileName,const bool useTimeDerivative) const3196   void BehaviourDSLCommon::writeVariableDeclaration(std::ostream& f,
3197                                                     const VariableDescription& v,
3198                                                     const std::string& prefix,
3199                                                     const std::string& suffix,
3200                                                     const std::string& fileName,
3201                                                     const bool useTimeDerivative) const {
3202     const auto n = prefix + v.name + suffix;
3203     const auto t = (!useTimeDerivative) ? v.type : this->getTimeDerivativeType(v.type);
3204     if ((!getDebugMode()) && (v.lineNumber != 0u)) {
3205       f << "#line " << v.lineNumber << " \"" << fileName << "\"\n";
3206     }
3207     if (v.arraySize == 1u) {
3208       f << t << " " << n << ";\n";
3209     } else {
3210       if (this->mb.useDynamicallyAllocatedVector(v.arraySize)) {
3211         f << "tfel::math::vector<" << t << " > " << n << ";\n";
3212       } else {
3213         f << "tfel::math::tvector<" << v.arraySize << ", " << t << " > " << n << ";\n";
3214       }
3215     }
3216   }  // end of BehaviourDSLCommon::writeVariableDeclaration
3217 
writeIncludes(std::ostream & file) const3218   void BehaviourDSLCommon::writeIncludes(std::ostream& file) const {
3219     if ((!file) || (!file.good())) {
3220       this->throwRuntimeError("BehaviourDSLCommon::writeIncludes", "output file is not valid");
3221     }
3222     const auto& h = this->mb.getIncludes();
3223     if (!h.empty()) {
3224       file << h << '\n';
3225     }
3226   }
3227 
writeNamespaceBegin(std::ostream & file) const3228   void BehaviourDSLCommon::writeNamespaceBegin(std::ostream& file) const {
3229     if ((!file) || (!file.good())) {
3230       this->throwRuntimeError("BehaviourDSLCommon::writeNamespaceBegin", "output file is not valid");
3231     }
3232     file << "namespace tfel{\n\n"
3233          << "namespace material{\n\n";
3234   }
3235 
writeNamespaceEnd(std::ostream & file) const3236   void BehaviourDSLCommon::writeNamespaceEnd(std::ostream& file) const {
3237     if ((!file) || (!file.good())) {
3238       this->throwRuntimeError("BehaviourDSLCommon::writeNamespaceEnd", "output file is not valid");
3239     }
3240     file << "} // end of namespace material\n\n"
3241          << "} // end of namespace tfel\n\n";
3242   }
3243 
writeStandardTFELTypedefs(std::ostream & file) const3244   void BehaviourDSLCommon::writeStandardTFELTypedefs(std::ostream& file) const {
3245     if ((!file) || (!file.good())) {
3246       this->throwRuntimeError("BehaviourDSLCommon::writeStandardTFELTypedefs", "output file is not valid");
3247     }
3248     file << "using ushort =  unsigned short;\n";
3249     if (this->mb.useQt()) {
3250       file << "using Types = tfel::config::Types<N,Type,use_qt>;\n";
3251     } else {
3252       file << "using Types = tfel::config::Types<N,Type,false>;\n";
3253     }
3254     file << "using real                = typename Types::real;\n"
3255          << "using time                = typename Types::time;\n"
3256          << "using length              = typename Types::length;\n"
3257          << "using frequency           = typename Types::frequency;\n"
3258          << "using stress              = typename Types::stress;\n"
3259          << "using strain              = typename Types::strain;\n"
3260          << "using strainrate          = typename Types::strainrate;\n"
3261          << "using stressrate          = typename Types::stressrate;\n"
3262          << "using temperature         = typename Types::temperature;\n"
3263          << "using thermalexpansion    = typename Types::thermalexpansion;\n"
3264          << "using thermalconductivity = typename Types::thermalconductivity;\n"
3265          << "using massdensity         = typename Types::massdensity;\n"
3266          << "using energydensity         = typename Types::energydensity;\n"
3267          << "using TVector             = typename Types::TVector;\n"
3268          << "using Stensor             = typename Types::Stensor;\n"
3269          << "using Stensor4            = typename Types::Stensor4;\n"
3270          << "using FrequencyStensor    = typename Types::FrequencyStensor;\n"
3271          << "using ForceTVector        = typename Types::ForceTVector;\n"
3272          << "using StressStensor       = typename Types::StressStensor;\n"
3273          << "using StressRateStensor   = typename Types::StressRateStensor;\n"
3274          << "using DisplacementTVector = typename Types::DisplacementTVector;\n"
3275          << "using StrainStensor       = typename Types::StrainStensor;\n"
3276          << "using StrainRateStensor   = typename Types::StrainRateStensor;\n"
3277          << "using StiffnessTensor     = typename Types::StiffnessTensor;\n"
3278          << "using Tensor              = typename Types::Tensor;\n"
3279          << "using FrequencyTensor     = typename Types::FrequencyTensor;\n"
3280          << "using StressTensor        = typename Types::StressTensor;\n"
3281          << "using ThermalExpansionCoefficientTensor = typename Types::ThermalExpansionCoefficientTensor;\n"
3282          << "using DeformationGradientTensor         = typename Types::DeformationGradientTensor;\n"
3283          << "using DeformationGradientRateTensor     = typename Types::DeformationGradientRateTensor;\n"
3284          << "using TemperatureGradient = typename Types::TemperatureGradient;\n"
3285          << "using HeatFlux = typename Types::HeatFlux;\n";
3286          // tangent operator
3287     if (this->mb.hasTangentOperator()) {
3288       file << "using TangentOperator   = " << this->mb.getTangentOperatorType()
3289            << ";\n";
3290     }
3291     // physical constants
3292     file << "using PhysicalConstants = tfel::PhysicalConstants<real>;\n";
3293   }  // end of BehaviourDSLCommon::writeStandardTFELTypedefs
3294 
getIntegrationVariablesIncrementsInitializers(const Hypothesis h) const3295   std::string BehaviourDSLCommon::getIntegrationVariablesIncrementsInitializers(const Hypothesis h) const {
3296     std::ostringstream f;
3297     const auto& vc = this->mb.getBehaviourData(h).getIntegrationVariables();
3298     for (auto p = vc.begin(); p != vc.end(); ++p) {
3299       const auto& v = *p;
3300       const auto flag = getTypeFlag(v.type);
3301       const auto n = v.name;
3302       const auto t = (!this->useStateVarTimeDerivative) ? v.type : this->getTimeDerivativeType(v.type);
3303       if (p != vc.begin()) {
3304         f << ",\n";
3305       }
3306       if (flag == SupportedTypes::SCALAR) {
3307         if (this->mb.useDynamicallyAllocatedVector(v.arraySize)) {
3308           f << "d" << n << "(" << v.arraySize << "," << t << "(0))";
3309         } else {
3310           f << "d" << n << "(" << t << "(0))";
3311         }
3312       } else if ((flag == SupportedTypes::TVECTOR) || (flag == SupportedTypes::STENSOR) ||
3313                  (flag == SupportedTypes::TENSOR)) {
3314         std::string traits;
3315         if (flag == SupportedTypes::TVECTOR) {
3316           traits = "VectorTraits";
3317         } else if (flag == SupportedTypes::STENSOR) {
3318           traits = "StensorTraits";
3319         } else if (flag == SupportedTypes::TENSOR) {
3320           traits = "TensorTraits";
3321         } else {
3322           this->throwRuntimeError("BehaviourDSLCommon::getIntegrationVariablesIncrementsInitializers",
3323                                   "internal error, tag unsupported");
3324         }
3325         if (v.arraySize == 1u) {
3326           f << "d" << n << "(typename tfel::math::" + traits + "<" << t << ">::NumType(0))";
3327         } else {
3328           if (this->mb.useDynamicallyAllocatedVector(v.arraySize)) {
3329             f << "d" << n << "(" << v.arraySize << "," << t << "(typename tfel::math::" + traits + "<" << t
3330               << ">::NumType(0)))";
3331           } else {
3332             f << "d" << n << "(" << t << "(typename tfel::math::" + traits + "<" << t << ">::NumType(0)))";
3333           }
3334         }
3335       } else {
3336         this->throwRuntimeError("BehaviourDSLCommon::getIntegrationVariablesIncrementsInitializers",
3337                                 "internal error, tag unsupported");
3338       }
3339     }
3340     return f.str();
3341   }  // end of SupportedTypes::getIntegrationVariablesInitializers
3342 
checkBehaviourDataFile(std::ostream & os) const3343   void BehaviourDSLCommon::checkBehaviourDataFile(std::ostream& os) const {
3344     if ((!os) || (!os.good())) {
3345       this->throwRuntimeError("BehaviourDSLCommon::checkBehaviourDataOutputFile", "output file is not valid");
3346     }
3347   }
3348 
writeBehaviourDataFileHeader(std::ostream & os) const3349   void BehaviourDSLCommon::writeBehaviourDataFileHeader(std::ostream& os) const {
3350     this->checkBehaviourDataFile(os);
3351     os << "/*!\n"
3352        << "* \\file   " << this->getBehaviourDataFileName() << '\n'
3353        << "* \\brief  "
3354        << "this file implements the " << this->mb.getClassName() << "BehaviourData"
3355        << " class.\n"
3356        << "*         File generated by " << MFrontHeader::getVersionName() << " "
3357        << "version " << MFrontHeader::getVersionNumber() << '\n';
3358     if (!this->fd.authorName.empty()) {
3359       os << "* \\author " << this->fd.authorName << '\n';
3360     }
3361     if (!this->fd.date.empty()) {
3362       os << "* \\date   " << this->fd.date << '\n';
3363     }
3364     os << " */\n\n";
3365   }
3366 
writeBehaviourDataFileHeaderBegin(std::ostream & os) const3367   void BehaviourDSLCommon::writeBehaviourDataFileHeaderBegin(std::ostream& os) const {
3368     this->checkBehaviourDataFile(os);
3369     os << "#ifndef LIB_TFELMATERIAL_" << makeUpperCase(this->mb.getClassName()) << "_BEHAVIOUR_DATA_HXX\n";
3370     os << "#define LIB_TFELMATERIAL_" << makeUpperCase(this->mb.getClassName()) << "_BEHAVIOUR_DATA_HXX\n\n";
3371   }
3372 
writeBehaviourDataFileHeaderEnd(std::ostream & os) const3373   void BehaviourDSLCommon::writeBehaviourDataFileHeaderEnd(std::ostream& os) const {
3374     this->checkBehaviourDataFile(os);
3375     os << "#endif /* LIB_TFELMATERIAL_" << makeUpperCase(this->mb.getClassName()) << "_BEHAVIOUR_DATA_HXX */\n";
3376   }
3377 
writeBehaviourDataStandardTFELIncludes(std::ostream & os) const3378   void BehaviourDSLCommon::writeBehaviourDataStandardTFELIncludes(std::ostream& os) const {
3379     auto b1 = false;
3380     auto b2 = false;
3381     this->checkBehaviourDataFile(os);
3382     os << "#include<limits>\n"
3383        << "#include<string>\n"
3384        << "#include<sstream>\n"
3385        << "#include<iostream>\n"
3386        << "#include<stdexcept>\n"
3387        << "#include<algorithm>\n\n"
3388        << "#include\"TFEL/Raise.hxx\"\n"
3389        << "#include\"TFEL/PhysicalConstants.hxx\"\n"
3390        << "#include\"TFEL/Config/TFELConfig.hxx\"\n"
3391        << "#include\"TFEL/Config/TFELTypes.hxx\"\n"
3392        << "#include\"TFEL/Metaprogramming/StaticAssert.hxx\"\n"
3393        << "#include\"TFEL/TypeTraits/IsFundamentalNumericType.hxx\"\n"
3394        << "#include\"TFEL/TypeTraits/IsReal.hxx\"\n"
3395        << "#include\"TFEL/Math/General/IEEE754.hxx\"\n";
3396     if (this->mb.useQt()) {
3397       os << "#include\"TFEL/Math/General/BaseCast.hxx\"\n";
3398     }
3399     this->mb.requiresTVectorOrVectorIncludes(b1, b2);
3400     if (b1) {
3401       os << "#include\"TFEL/Math/tvector.hxx\"\n"
3402          << "#include\"TFEL/Math/Vector/tvectorIO.hxx\"\n";
3403     }
3404     if (b2) {
3405       os << "#include\"TFEL/Math/vector.hxx\"\n";
3406     }
3407     os << "#include\"TFEL/Math/stensor.hxx\"\n"
3408        << "#include\"TFEL/Math/Stensor/StensorView.hxx\"\n"
3409        << "#include\"TFEL/Math/Stensor/StensorConceptIO.hxx\"\n"
3410        << "#include\"TFEL/Math/tmatrix.hxx\"\n"
3411        << "#include\"TFEL/Math/Matrix/tmatrixIO.hxx\"\n"
3412        << "#include\"TFEL/Math/st2tost2.hxx\"\n"
3413        << "#include\"TFEL/Math/ST2toST2/ST2toST2ConceptIO.hxx\"\n"
3414        << "#include\"TFEL/Math/ST2toST2/ST2toST2View.hxx\"\n";
3415     if ((this->mb.getBehaviourType() ==
3416          BehaviourDescription::STANDARDFINITESTRAINBEHAVIOUR) ||
3417         (this->mb.getBehaviourType() ==
3418          BehaviourDescription::GENERALBEHAVIOUR)) {
3419       os << "#include\"TFEL/Math/tensor.hxx\"\n"
3420          << "#include\"TFEL/Math/Tensor/TensorConceptIO.hxx\"\n"
3421          << "#include\"TFEL/Math/t2tot2.hxx\"\n"
3422          << "#include\"TFEL/Math/T2toT2/T2toT2ConceptIO.hxx\"\n"
3423          << "#include\"TFEL/Math/t2tost2.hxx\"\n"
3424          << "#include\"TFEL/Math/T2toST2/T2toST2ConceptIO.hxx\"\n"
3425          << "#include\"TFEL/Math/st2tot2.hxx\"\n"
3426          << "#include\"TFEL/Math/ST2toT2/ST2toT2ConceptIO.hxx\"\n"
3427          << "#include\"TFEL/Math/ST2toST2/ConvertToTangentModuli.hxx\"\n"
3428          << "#include\"TFEL/Math/ST2toST2/ConvertSpatialModuliToKirchhoffJaumanRateModuli.hxx\"\n"
3429          << "#include\"TFEL/Material/FiniteStrainBehaviourTangentOperator.hxx\"\n";
3430     }
3431     if (this->mb.getBehaviourType() == BehaviourDescription::GENERALBEHAVIOUR) {
3432       os << "#include\"TFEL/Math/T2toT2/T2toT2View.hxx\"\n"
3433          << "#include\"TFEL/Math/T2toST2/T2toST2View.hxx\"\n"
3434          << "#include\"TFEL/Math/ST2toT2/ST2toT2View.hxx\"\n";
3435     }
3436     os << "#include\"TFEL/Material/ModellingHypothesis.hxx\"\n\n";
3437   }  // end of BehaviourDSLCommon::writeBehaviourDataStandardTFELIncludes
3438 
writeBehaviourDataDefaultMembers(std::ostream & os) const3439   void BehaviourDSLCommon::writeBehaviourDataDefaultMembers(std::ostream& os) const {
3440     this->checkBehaviourDataFile(os);
3441     if (this->mb.getAttribute(BehaviourDescription::requiresStiffnessTensor, false)) {
3442       os << "//! stiffness tensor computed by the calling solver\n"
3443          << "StiffnessTensor D;\n";
3444     }
3445     if (this->mb.getAttribute(BehaviourDescription::requiresThermalExpansionCoefficientTensor, false)) {
3446       os << "ThermalExpansionCoefficientTensor A;\n";
3447     }
3448     for (const auto& mv : this->mb.getMainVariables()) {
3449       if (Gradient::isIncrementKnown(mv.first)) {
3450         os << mv.first.type << " " << mv.first.name << ";\n\n";
3451       } else {
3452         os << mv.first.type << " " << mv.first.name << "0;\n\n";
3453       }
3454       os << mv.second.type << " " << mv.second.name << ";\n\n";
3455     }
3456   }
3457 
writeBehaviourDataStandardTFELTypedefs(std::ostream & os) const3458   void BehaviourDSLCommon::writeBehaviourDataStandardTFELTypedefs(std::ostream& os) const {
3459     this->checkBehaviourDataFile(os);
3460     os << "static " << constexpr_c << " unsigned short TVectorSize = N;\n"
3461        << "typedef tfel::math::StensorDimeToSize<N> StensorDimeToSize;\n"
3462        << "static " << constexpr_c << " unsigned short StensorSize = "
3463        << "StensorDimeToSize::value;\n"
3464        << "typedef tfel::math::TensorDimeToSize<N> TensorDimeToSize;\n"
3465        << "static " << constexpr_c << " unsigned short TensorSize = "
3466        << "TensorDimeToSize::value;\n\n";
3467     this->writeStandardTFELTypedefs(os);
3468     os << '\n';
3469   }
3470 
writeBehaviourDataDisabledConstructors(std::ostream & os) const3471   void BehaviourDSLCommon::writeBehaviourDataDisabledConstructors(std::ostream& os) const {
3472     this->checkBehaviourDataFile(os);
3473   }
3474 
writeBehaviourDataConstructors(std::ostream & os,const Hypothesis h) const3475   void BehaviourDSLCommon::writeBehaviourDataConstructors(std::ostream& os, const Hypothesis h) const {
3476     const auto& md = this->mb.getBehaviourData(h);
3477     this->checkBehaviourDataFile(os);
3478     os << "/*!\n"
3479        << "* \\brief Default constructor\n"
3480        << "*/\n"
3481        << this->mb.getClassName() << "BehaviourData()\n"
3482        << "{}\n\n"
3483        << "/*!\n"
3484        << "* \\brief copy constructor\n"
3485        << "*/\n"
3486        << this->mb.getClassName() << "BehaviourData(const " << this->mb.getClassName() << "BehaviourData& src)\n"
3487        << ": ";
3488     auto first = true;
3489     if (this->mb.getAttribute(BehaviourDescription::requiresStiffnessTensor, false)) {
3490       os << "D(src.D)";
3491       first = false;
3492     }
3493     if (this->mb.getAttribute(BehaviourDescription::requiresThermalExpansionCoefficientTensor, false)) {
3494       if (!first) {
3495         os << ",\n";
3496       }
3497       os << "A(src.A)";
3498       first = false;
3499     }
3500     for (const auto& mv : this->mb.getMainVariables()) {
3501       if (!first) {
3502         os << ",\n";
3503       }
3504       if (Gradient::isIncrementKnown(mv.first)) {
3505         os << mv.first.name << "(src." << mv.first.name << "),\n";
3506       } else {
3507         os << mv.first.name << "0(src." << mv.first.name << "0),\n";
3508       }
3509       os << mv.second.name << "(src." << mv.second.name << ")";
3510       first = false;
3511     }
3512     for (const auto& v : md.getMaterialProperties()) {
3513       os << ",\n";
3514       os << v.name << "(src." << v.name << ")";
3515     }
3516     for (const auto& v : md.getStateVariables()) {
3517       os << ",\n";
3518       os << v.name << "(src." << v.name << ")";
3519     }
3520     for (const auto& v : md.getAuxiliaryStateVariables()) {
3521       os << ",\n";
3522       os << v.name << "(src." << v.name << ")";
3523     }
3524     for (const auto& v : md.getExternalStateVariables()) {
3525       os << ",\n";
3526       os << v.name << "(src." << v.name << ")";
3527     }
3528     os << "\n{}\n\n";
3529     // Creating constructor for external interfaces
3530     for (const auto& i : this->interfaces) {
3531       if (i.second->isBehaviourConstructorRequired(h, this->mb)) {
3532         i.second->writeBehaviourDataConstructor(os, h, this->mb);
3533       }
3534     }
3535   }  // end of BehaviourDSLCommon::WriteBehaviourDataConstructors
3536 
writeBehaviourDataAssignementOperator(std::ostream & os,const Hypothesis h) const3537   void BehaviourDSLCommon::writeBehaviourDataAssignementOperator(std::ostream& os, const Hypothesis h) const {
3538     const auto& md = this->mb.getBehaviourData(h);
3539     this->checkBehaviourDataFile(os);
3540     os << "/*\n"
3541        << "* \\brief Assignement operator\n"
3542        << "*/\n"
3543        << this->mb.getClassName() << "BehaviourData&\n"
3544        << "operator=(const " << this->mb.getClassName() << "BehaviourData& src){\n";
3545     for (const auto& dv : this->mb.getMainVariables()) {
3546       if (Gradient::isIncrementKnown(dv.first)) {
3547         os << "this->" << dv.first.name << " = src." << dv.first.name << ";\n";
3548       } else {
3549         os << "this->" << dv.first.name << "0 = src." << dv.first.name << "0;\n";
3550       }
3551       os << "this->" << dv.second.name << " = src." << dv.second.name << ";\n";
3552     }
3553     for (const auto& mp : md.getMaterialProperties()) {
3554       os << "this->" << mp.name << " = src." << mp.name << ";\n";
3555     }
3556     for (const auto& iv : md.getStateVariables()) {
3557       os << "this->" << iv.name << " = src." << iv.name << ";\n";
3558     }
3559     for (const auto& iv : md.getAuxiliaryStateVariables()) {
3560       os << "this->" << iv.name << " = src." << iv.name << ";\n";
3561     }
3562     for (const auto& ev : md.getExternalStateVariables()) {
3563       os << "this->" << ev.name << " = src." << ev.name << ";\n";
3564     }
3565     os << "return *this;\n"
3566        << "}\n\n";
3567   }  // end of BehaviourDSLCommon::writeBehaviourAssignementOperator
3568 
writeBehaviourDataExport(std::ostream & os,const Hypothesis h) const3569   void BehaviourDSLCommon::writeBehaviourDataExport(std::ostream& os, const Hypothesis h) const {
3570     this->checkBehaviourDataFile(os);
3571     for (const auto& i : this->interfaces) {
3572       i.second->exportMechanicalData(os, h, this->mb);
3573     }
3574   }
3575 
writeBehaviourDataPublicMembers(std::ostream & os) const3576   void BehaviourDSLCommon::writeBehaviourDataPublicMembers(std::ostream& os) const {
3577     this->checkBehaviourDataFile(os);
3578     if (this->mb.getAttribute(BehaviourDescription::requiresStiffnessTensor, false)) {
3579       os << "StiffnessTensor& getStiffnessTensor()\n"
3580          << "{\nreturn this->D;\n}\n\n"
3581          << "const StiffnessTensor& getStiffnessTensor() const\n"
3582          << "{\nreturn this->D;\n}\n\n";
3583     }
3584     if (this->mb.getAttribute(BehaviourDescription::requiresThermalExpansionCoefficientTensor, false)) {
3585       os << "ThermalExpansionCoefficientTensor& "
3586          << "getThermalExpansionCoefficientTensor()\n"
3587          << "{\nreturn this->A;\n}\n\n"
3588          << "const ThermalExpansionCoefficientTensor& "
3589          << "getThermalExpansionCoefficientTensor() const\n"
3590          << "{\nreturn this->A;\n}\n\n";
3591     }
3592   }  // end of BehaviourDSLCommon::writeBehaviourDataPublicMembers
3593 
writeBehaviourDataClassHeader(std::ostream & os) const3594   void BehaviourDSLCommon::writeBehaviourDataClassHeader(std::ostream& os) const {
3595     this->checkBehaviourDataFile(os);
3596     os << "/*!\n"
3597        << "* \\class " << this->mb.getClassName() << "BehaviourData\n"
3598        << "* \\brief This class implements the " << this->mb.getClassName() << "BehaviourData"
3599        << " .\n"
3600        << "* \\param H, modelling hypothesis.\n"
3601        << "* \\param typename Type, numerical type.\n"
3602        << "* \\param bool use_qt, conditional saying if quantities are use.\n";
3603     if (!this->fd.authorName.empty()) {
3604       os << "* \\author " << this->fd.authorName << '\n';
3605     }
3606     if (!this->fd.date.empty()) {
3607       os << "* \\date   " << this->fd.date << '\n';
3608     }
3609     os << "*/\n";
3610   }
3611 
writeBehaviourDataForwardDeclarations(std::ostream & os) const3612   void BehaviourDSLCommon::writeBehaviourDataForwardDeclarations(std::ostream& os) const {
3613     this->checkBehaviourDataFile(os);
3614     os << "//! \\brief forward declaration\n"
3615        << "template<ModellingHypothesis::Hypothesis hypothesis,typename,bool>\n"
3616        << "class " << this->mb.getClassName() << "BehaviourData;\n\n"
3617        << "//! \\brief forward declaration\n"
3618        << "template<ModellingHypothesis::Hypothesis hypothesis,typename Type,bool use_qt>\n"
3619        << "class " << this->mb.getClassName() << "IntegrationData;\n\n";
3620     if (this->mb.useQt()) {
3621       os << "//! \\brief forward declaration\n";
3622       os << "template<ModellingHypothesis::Hypothesis hypothesis,typename Type,bool use_qt>\n";
3623       os << "std::ostream&\n operator <<(std::ostream&,";
3624       os << "const " << this->mb.getClassName() << "BehaviourData<hypothesis,Type,use_qt>&);\n\n";
3625     } else {
3626       os << "//! \\brief forward declaration\n";
3627       os << "template<ModellingHypothesis::Hypothesis hypothesis,typename Type>\n";
3628       os << "std::ostream&\n operator <<(std::ostream&,";
3629       os << "const " << this->mb.getClassName() << "BehaviourData<hypothesis,Type,false>&);\n\n";
3630     }
3631     // maintenant, il faut déclarer toutes les spécialisations partielles...
3632     for (const auto& h : this->mb.getModellingHypotheses()) {
3633       if (this->mb.hasSpecialisedMechanicalData(h)) {
3634         if (this->mb.useQt()) {
3635           os << "//! \\brief forward declaration\n"
3636              << "template<typename Type,bool use_qt>\n"
3637              << "std::ostream&\n operator <<(std::ostream&,"
3638              << "const " << this->mb.getClassName()
3639              << "BehaviourData<ModellingHypothesis::" << ModellingHypothesis::toUpperCaseString(h)
3640              << ",Type,use_qt>&);\n\n";
3641         } else {
3642           os << "//! \\brief forward declaration\n"
3643              << "template<typename Type>\n"
3644              << "std::ostream&\n operator <<(std::ostream&,"
3645              << "const " << this->mb.getClassName()
3646              << "BehaviourData<ModellingHypothesis::" << ModellingHypothesis::toUpperCaseString(h)
3647              << ",Type,false>&);\n\n";
3648         }
3649       }
3650     }
3651   }
3652 
writeBehaviourDataClassBegin(std::ostream & os,const Hypothesis h) const3653   void BehaviourDSLCommon::writeBehaviourDataClassBegin(std::ostream& os, const Hypothesis h) const {
3654     this->checkBehaviourDataFile(os);
3655     if (h == ModellingHypothesis::UNDEFINEDHYPOTHESIS) {
3656       if (this->mb.useQt()) {
3657         os << "template<ModellingHypothesis::Hypothesis hypothesis,typename Type,bool use_qt>\n";
3658         os << "class " << this->mb.getClassName() << "BehaviourData\n";
3659       } else {
3660         os << "template<ModellingHypothesis::Hypothesis hypothesis,typename Type>\n";
3661         os << "class " << this->mb.getClassName() << "BehaviourData<hypothesis,Type,false>\n";
3662       }
3663     } else {
3664       if (this->mb.useQt()) {
3665         os << "template<typename Type,bool use_qt>\n";
3666         os << "class " << this->mb.getClassName()
3667            << "BehaviourData<ModellingHypothesis::" << ModellingHypothesis::toUpperCaseString(h) << ",Type,use_qt>\n";
3668       } else {
3669         os << "template<typename Type>\n";
3670         os << "class " << this->mb.getClassName()
3671            << "BehaviourData<ModellingHypothesis::" << ModellingHypothesis::toUpperCaseString(h) << ",Type,false>\n";
3672       }
3673     }
3674     os << "{\n\n";
3675     if (h != ModellingHypothesis::UNDEFINEDHYPOTHESIS) {
3676       os << "static " << constexpr_c << " ModellingHypothesis::Hypothesis hypothesis = "
3677          << "ModellingHypothesis::" << ModellingHypothesis::toUpperCaseString(h) << ";\n";
3678     }
3679     os << "static " << constexpr_c << " unsigned short N = ModellingHypothesisToSpaceDimension<hypothesis>::value;\n"
3680        << "TFEL_STATIC_ASSERT(N==1||N==2||N==3);\n"
3681        << "TFEL_STATIC_ASSERT(tfel::typetraits::"
3682        << "IsFundamentalNumericType<Type>::cond);\n"
3683        << "TFEL_STATIC_ASSERT(tfel::typetraits::IsReal<Type>::cond);\n\n"
3684        << "friend std::ostream& operator<< <>(std::ostream&,const " << this->mb.getClassName() << "BehaviourData&);\n\n"
3685        << "/* integration data is declared friend to access"
3686        << "   driving variables at the beginning of the time step */\n";
3687     if (this->mb.useQt()) {
3688       os << "friend class " << this->mb.getClassName() << "IntegrationData<hypothesis,Type,use_qt>;\n\n";
3689     } else {
3690       os << "friend class " << this->mb.getClassName() << "IntegrationData<hypothesis,Type,false>;\n\n";
3691     }
3692   }
3693 
writeBehaviourDataClassEnd(std::ostream & os) const3694   void BehaviourDSLCommon::writeBehaviourDataClassEnd(std::ostream& os) const {
3695     this->checkBehaviourDataFile(os);
3696     os << "}; // end of " << this->mb.getClassName() << "BehaviourData"
3697        << "class\n\n";
3698   }
3699 
writeBehaviourDataMaterialProperties(std::ostream & os,const Hypothesis h) const3700   void BehaviourDSLCommon::writeBehaviourDataMaterialProperties(std::ostream& os, const Hypothesis h) const {
3701     this->checkBehaviourDataFile(os);
3702     this->writeVariablesDeclarations(os, this->mb.getBehaviourData(h).getMaterialProperties(), "", "",
3703                                      this->fd.fileName, false);
3704     os << '\n';
3705   }
3706 
writeBehaviourDataStateVariables(std::ostream & os,const Hypothesis h) const3707   void BehaviourDSLCommon::writeBehaviourDataStateVariables(std::ostream& os, const Hypothesis h) const {
3708     this->checkBehaviourDataFile(os);
3709     const auto& d = this->mb.getBehaviourData(h);
3710     this->writeVariablesDeclarations(os, d.getStateVariables(), "", "", this->fd.fileName, false);
3711     this->writeVariablesDeclarations(os, d.getAuxiliaryStateVariables(), "", "", this->fd.fileName, false);
3712     this->writeVariablesDeclarations(os, d.getExternalStateVariables(), "", "", this->fd.fileName, false);
3713     os << '\n';
3714   }
3715 
writeBehaviourDataOutputOperator(std::ostream & os,const Hypothesis h) const3716   void BehaviourDSLCommon::writeBehaviourDataOutputOperator(std::ostream& os, const Hypothesis h) const {
3717     this->checkBehaviourFile(os);
3718     const auto& d = this->mb.getBehaviourData(h);
3719     if (h == ModellingHypothesis::UNDEFINEDHYPOTHESIS) {
3720       if (this->mb.useQt()) {
3721         os << "template<ModellingHypothesis::Hypothesis hypothesis,typename Type,bool use_qt>\n";
3722         os << "std::ostream&\n";
3723         os << "operator <<(std::ostream& os,";
3724         os << "const " << this->mb.getClassName() << "BehaviourData<hypothesis,Type,use_qt>& b)\n";
3725       } else {
3726         os << "template<ModellingHypothesis::Hypothesis hypothesis,typename Type>\n";
3727         os << "std::ostream&\n";
3728         os << "operator <<(std::ostream& os,";
3729         os << "const " << this->mb.getClassName() << "BehaviourData<hypothesis,Type,false>& b)\n";
3730       }
3731     } else {
3732       if (this->mb.useQt()) {
3733         os << "template<typename Type,bool use_qt>\n";
3734         os << "std::ostream&\n";
3735         os << "operator <<(std::ostream& os,";
3736         os << "const " << this->mb.getClassName()
3737            << "BehaviourData<ModellingHypothesis::" << ModellingHypothesis::toUpperCaseString(h)
3738            << ",Type,use_qt>& b)\n";
3739       } else {
3740         os << "template<typename Type>\n";
3741         os << "std::ostream&\n";
3742         os << "operator <<(std::ostream& os,";
3743         os << "const " << this->mb.getClassName()
3744            << "BehaviourData<ModellingHypothesis::" << ModellingHypothesis::toUpperCaseString(h)
3745            << ",Type,false>& b)\n";
3746       }
3747     }
3748     os << "{\n";
3749     for (const auto& v : this->mb.getMainVariables()) {
3750       if (Gradient::isIncrementKnown(v.first)) {
3751         os << "os << \"" << displayName(v.first) << " : \" << b."
3752            << v.first.name << " << '\\n';\n";
3753       } else {
3754         if (getUnicodeOutputOption()) {
3755           os << "os << \"" << displayName(v.first) << "\u2080 : \" << b."
3756              << v.first.name << "0 << '\\n';\n";
3757         } else {
3758           os << "os << \"" << displayName(v.first) << "0 : \" << b."
3759              << v.first.name << "0 << '\\n';\n";
3760         }
3761       }
3762       os << "os << \"" << displayName(v.second) << " : \" << b."
3763          << v.second.name << " << '\\n';\n";
3764     }
3765     for (const auto& v : d.getMaterialProperties()) {
3766       os << "os << \"" << displayName(v) << " : \" << b." << v.name << " << '\\n';\n";
3767     }
3768     for (const auto& v : d.getStateVariables()) {
3769       os << "os << \"" << displayName(v) << " : \" << b." << v.name << " << '\\n';\n";
3770     }
3771     for (const auto& v : d.getAuxiliaryStateVariables()) {
3772       os << "os << \"" << displayName(v) << " : \" << b." << v.name << " << '\\n';\n";
3773     }
3774     for (const auto& v : d.getExternalStateVariables()) {
3775       os << "os << \"" << displayName(v) << " : \" << b." << v.name << " << '\\n';\n";
3776     }
3777     os << "return os;\n"
3778        << "}\n\n";
3779   }  //  BehaviourDSLCommon::writeBehaviourDataOutputOperator
3780 
writeBehaviourDataFileBegin(std::ostream & os) const3781   void BehaviourDSLCommon::writeBehaviourDataFileBegin(std::ostream& os) const {
3782     this->checkBehaviourDataFile(os);
3783     this->writeBehaviourDataFileHeader(os);
3784     this->writeBehaviourDataFileHeaderBegin(os);
3785     this->writeBehaviourDataStandardTFELIncludes(os);
3786     this->writeIncludes(os);
3787     // includes specific to interfaces
3788     for (const auto& i : this->interfaces) {
3789       i.second->writeInterfaceSpecificIncludes(os, this->mb);
3790     }
3791     this->writeNamespaceBegin(os);
3792     this->writeBehaviourDataForwardDeclarations(os);
3793   }  // end of BehaviourDSLCommon::writeBehaviourDataFile
3794 
writeBehaviourDataClass(std::ostream & os,const Hypothesis h) const3795   void BehaviourDSLCommon::writeBehaviourDataClass(std::ostream& os, const Hypothesis h) const {
3796     this->checkBehaviourDataFile(os);
3797     this->writeBehaviourDataClassBegin(os, h);
3798     this->writeBehaviourDataStandardTFELTypedefs(os);
3799     os << "protected:\n\n";
3800     this->writeBehaviourDataDefaultMembers(os);
3801     this->writeBehaviourDataMaterialProperties(os, h);
3802     this->writeBehaviourDataStateVariables(os, h);
3803     os << "public:\n\n";
3804     this->writeBehaviourDataDisabledConstructors(os);
3805     this->writeBehaviourDataConstructors(os, h);
3806     this->writeBehaviourDataMainVariablesSetters(os);
3807     this->writeBehaviourDataPublicMembers(os);
3808     this->writeBehaviourDataAssignementOperator(os, h);
3809     this->writeBehaviourDataExport(os, h);
3810     this->writeBehaviourDataClassEnd(os);
3811     this->writeBehaviourDataOutputOperator(os, h);
3812   }
3813 
writeBehaviourDataFileEnd(std::ostream & os) const3814   void BehaviourDSLCommon::writeBehaviourDataFileEnd(std::ostream& os) const {
3815     this->writeNamespaceEnd(os);
3816     this->writeBehaviourDataFileHeaderEnd(os);
3817   }  // end of BehaviourDSLCommon::writeBehaviourDataFileEnd
3818 
checkBehaviourFile(std::ostream & os) const3819   void BehaviourDSLCommon::checkBehaviourFile(std::ostream& os) const {
3820     if ((!os) || (!os.good())) {
3821       this->throwRuntimeError("BehaviourDSLCommon::checkBehaviourDataOutputFile", "output file is not valid");
3822     }
3823   }
3824 
writeBehaviourForwardDeclarations(std::ostream & os) const3825   void BehaviourDSLCommon::writeBehaviourForwardDeclarations(std::ostream& os) const {
3826     this->checkBehaviourFile(os);
3827     os << "//! \\brief forward declaration\n"
3828        << "template<ModellingHypothesis::Hypothesis,typename Type,bool use_qt>\n"
3829        << "class " << this->mb.getClassName() << ";\n\n";
3830     if (this->mb.useQt()) {
3831       os << "//! \\brief forward declaration\n"
3832          << "template<ModellingHypothesis::Hypothesis hypothesis,typename Type,bool use_qt>\n"
3833          << "std::ostream&\n operator <<(std::ostream&,"
3834          << "const " << this->mb.getClassName() << "<hypothesis,Type,use_qt>&);\n\n";
3835     } else {
3836       os << "//! \\brief forward declaration\n"
3837          << "template<ModellingHypothesis::Hypothesis hypothesis,typename Type>\n"
3838          << "std::ostream&\n operator <<(std::ostream&,"
3839          << "const " << this->mb.getClassName() << "<hypothesis,Type,false>&);\n\n";
3840     }
3841     // maintenant, il faut déclarer toutes les spécialisations partielles...
3842     const auto& mh = this->mb.getModellingHypotheses();
3843     for (const auto& h : mh) {
3844       if (this->mb.hasSpecialisedMechanicalData(h)) {
3845         if (this->mb.useQt()) {
3846           os << "//! \\brief forward declaration\n"
3847              << "template<typename Type,bool use_qt>\n"
3848              << "std::ostream&\n operator <<(std::ostream&,"
3849              << "const " << this->mb.getClassName()
3850              << "<ModellingHypothesis::" << ModellingHypothesis::toUpperCaseString(h) << ",Type,use_qt>&);\n\n";
3851         } else {
3852           os << "//! \\brief forward declaration\n"
3853              << "template<typename Type>\n"
3854              << "std::ostream&\n operator <<(std::ostream&,"
3855              << "const " << this->mb.getClassName()
3856              << "<ModellingHypothesis::" << ModellingHypothesis::toUpperCaseString(h) << ",Type,false>&);\n\n";
3857         }
3858       }
3859     }
3860   }  // end of BehaviourDSLCommon::writeBehaviourClassForwardDeclarations
3861 
writeBehaviourClassBegin(std::ostream & os,const Hypothesis h) const3862   void BehaviourDSLCommon::writeBehaviourClassBegin(std::ostream& os, const Hypothesis h) const {
3863     this->checkBehaviourFile(os);
3864     os << "/*!\n";
3865     os << "* \\class " << this->mb.getClassName() << '\n';
3866     os << "* \\brief This class implements the " << this->mb.getClassName() << " behaviour.\n";
3867     os << "* \\param hypothesis, modelling hypothesis.\n";
3868     os << "* \\param Type, numerical type.\n";
3869     if (this->mb.useQt()) {
3870       os << "* \\param use_qt, conditional "
3871          << "saying if quantities are use.\n";
3872     }
3873     if (!this->fd.authorName.empty()) {
3874       os << "* \\author " << this->fd.authorName << '\n';
3875     }
3876     if (!this->fd.date.empty()) {
3877       os << "* \\date   " << this->fd.date << '\n';
3878     }
3879     if (!this->fd.description.empty()) {
3880       os << this->fd.description << '\n';
3881     }
3882     os << "*/\n";
3883     const auto btype = this->mb.getBehaviourTypeFlag();
3884     if (h == ModellingHypothesis::UNDEFINEDHYPOTHESIS) {
3885       if (this->mb.useQt()) {
3886         os << "template<ModellingHypothesis::Hypothesis hypothesis,typename Type,bool use_qt>\n";
3887         os << "class " << this->mb.getClassName() << " final\n";
3888         os << ": public MechanicalBehaviour<" << btype << ",hypothesis,Type,use_qt>,\n";
3889         if (this->mb.getAttribute(BehaviourData::profiling, false)) {
3890           os << "public " << this->mb.getClassName() << "Profiler,\n";
3891         }
3892         os << "public " << this->mb.getClassName() << "BehaviourData<hypothesis,Type,use_qt>,\n";
3893         os << "public " << this->mb.getClassName() << "IntegrationData<hypothesis,Type,use_qt>";
3894         this->writeBehaviourParserSpecificInheritanceRelationship(os);
3895       } else {
3896         os << "template<ModellingHypothesis::Hypothesis hypothesis,typename Type>\n";
3897         os << "class " << this->mb.getClassName() << "<hypothesis,Type,false> final\n";
3898         os << ": public MechanicalBehaviour<" << btype << ",hypothesis,Type,false>,\n";
3899         if (this->mb.getAttribute(BehaviourData::profiling, false)) {
3900           os << "public " << this->mb.getClassName() << "Profiler,\n";
3901         }
3902         os << "public " << this->mb.getClassName() << "BehaviourData<hypothesis,Type,false>,\n";
3903         os << "public " << this->mb.getClassName() << "IntegrationData<hypothesis,Type,false>";
3904         this->writeBehaviourParserSpecificInheritanceRelationship(os);
3905       }
3906     } else {
3907       if (this->mb.useQt()) {
3908         os << "template<typename Type,bool use_qt>\n";
3909         os << "class " << this->mb.getClassName()
3910            << "<ModellingHypothesis::" << ModellingHypothesis::toUpperCaseString(h) << ",Type,use_qt> final\n";
3911         os << ": public MechanicalBehaviour<" << btype
3912            << ",ModellingHypothesis::" << ModellingHypothesis::toUpperCaseString(h) << ",Type,use_qt>,\n";
3913         if (this->mb.getAttribute(BehaviourData::profiling, false)) {
3914           os << "public " << this->mb.getClassName() << "Profiler,\n";
3915         }
3916         os << "public " << this->mb.getClassName()
3917            << "BehaviourData<ModellingHypothesis::" << ModellingHypothesis::toUpperCaseString(h) << ",Type,use_qt>,\n";
3918         os << "public " << this->mb.getClassName()
3919            << "IntegrationData<ModellingHypothesis::" << ModellingHypothesis::toUpperCaseString(h) << ",Type,use_qt>";
3920         this->writeBehaviourParserSpecificInheritanceRelationship(os);
3921       } else {
3922         os << "template<typename Type>\n";
3923         os << "class " << this->mb.getClassName()
3924            << "<ModellingHypothesis::" << ModellingHypothesis::toUpperCaseString(h) << ",Type,false> final\n";
3925         os << ": public MechanicalBehaviour<" << btype
3926            << ",ModellingHypothesis::" << ModellingHypothesis::toUpperCaseString(h) << ",Type,false>,\n";
3927         if (this->mb.getAttribute(BehaviourData::profiling, false)) {
3928           os << "public " << this->mb.getClassName() << "Profiler,\n";
3929         }
3930         os << "public " << this->mb.getClassName()
3931            << "BehaviourData<ModellingHypothesis::" << ModellingHypothesis::toUpperCaseString(h) << ",Type,false>,\n";
3932         os << "public " << this->mb.getClassName()
3933            << "IntegrationData<ModellingHypothesis::" << ModellingHypothesis::toUpperCaseString(h) << ",Type,false>";
3934       }
3935     }
3936     os << "{\n\n";
3937     if (h != ModellingHypothesis::UNDEFINEDHYPOTHESIS) {
3938       os << "static " << constexpr_c << " ModellingHypothesis::Hypothesis hypothesis = "
3939          << "ModellingHypothesis::" << ModellingHypothesis::toUpperCaseString(h) << ";\n";
3940     }
3941     os << "static " << constexpr_c << " unsigned short N = ModellingHypothesisToSpaceDimension<hypothesis>::value;\n\n";
3942     os << "TFEL_STATIC_ASSERT(N==1||N==2||N==3);\n";
3943     os << "TFEL_STATIC_ASSERT(tfel::typetraits::"
3944        << "IsFundamentalNumericType<Type>::cond);\n";
3945     os << "TFEL_STATIC_ASSERT(tfel::typetraits::IsReal<Type>::cond);\n\n";
3946     os << "friend std::ostream& operator<< <>(std::ostream&,const ";
3947     os << this->mb.getClassName() << "&);\n\n";
3948   }
3949 
writeBehaviourFileHeader(std::ostream & os) const3950   void BehaviourDSLCommon::writeBehaviourFileHeader(std::ostream& os) const {
3951     this->checkBehaviourFile(os);
3952     os << "/*!\n"
3953        << "* \\file   " << this->getBehaviourFileName() << '\n'
3954        << "* \\brief  "
3955        << "this file implements the " << this->mb.getClassName() << " Behaviour.\n"
3956        << "*         File generated by " << MFrontHeader::getVersionName() << " "
3957        << "version " << MFrontHeader::getVersionNumber() << '\n';
3958     if (!this->fd.authorName.empty()) {
3959       os << "* \\author " << this->fd.authorName << '\n';
3960     }
3961     if (!this->fd.date.empty()) {
3962       os << "* \\date   " << this->fd.date << '\n';
3963     }
3964     os << " */\n\n";
3965   }
3966 
writeBehaviourFileHeaderBegin(std::ostream & os) const3967   void BehaviourDSLCommon::writeBehaviourFileHeaderBegin(std::ostream& os) const {
3968     this->checkBehaviourFile(os);
3969     os << "#ifndef LIB_TFELMATERIAL_" << makeUpperCase(this->mb.getClassName()) << "_HXX\n"
3970        << "#define LIB_TFELMATERIAL_" << makeUpperCase(this->mb.getClassName()) << "_HXX\n\n";
3971   }
3972 
writeBehaviourFileHeaderEnd(std::ostream & os) const3973   void BehaviourDSLCommon::writeBehaviourFileHeaderEnd(std::ostream& os) const {
3974     this->checkBehaviourFile(os);
3975     os << "#endif /* LIB_TFELMATERIAL_" << makeUpperCase(this->mb.getClassName()) << "_HXX */\n";
3976   }
3977 
writeBehaviourClassEnd(std::ostream & os) const3978   void BehaviourDSLCommon::writeBehaviourClassEnd(std::ostream& os) const {
3979     this->checkBehaviourFile(os);
3980     os << "}; // end of " << this->mb.getClassName() << " class\n\n";
3981   }
3982 
treatUpdateAuxiliaryStateVariables()3983   void BehaviourDSLCommon::treatUpdateAuxiliaryStateVariables() {
3984     this->readCodeBlock(*this, BehaviourData::UpdateAuxiliaryStateVariables, &BehaviourDSLCommon::standardModifier,
3985                         true, true);
3986   }  // end of BehaviourDSLCommon::treatUpdateAuxiliaryStateVarBase
3987 
treatComputeStressFreeExpansion()3988   void BehaviourDSLCommon::treatComputeStressFreeExpansion() {
3989     this->readCodeBlock(*this, BehaviourData::ComputeStressFreeExpansion, &BehaviourDSLCommon::standardModifier, true,
3990                         true);
3991   }  // end of BehaviourDSLCommon::treatComputeStressFreeExpansion
3992 
treatSwelling()3993   void BehaviourDSLCommon::treatSwelling() {
3994     using VolumeSwelling = BehaviourData::VolumeSwellingStressFreeExpansion;
3995     using IsotropicSwelling = BehaviourData::IsotropicStressFreeExpansion;
3996     using OrthotropicSwelling = BehaviourData::OrthotropicStressFreeExpansion;
3997     using OrthotropicSwellingII = BehaviourData::OrthotropicStressFreeExpansionII;
3998     auto throw_if = [this](const bool b, const std::string& m) {
3999       if (b) {
4000         this->throwRuntimeError("BehaviourDSLCommon::treatSwelling", m);
4001       }
4002     };
4003     enum { VOLUME, LINEAR, ORTHOTROPIC, UNDEFINED } etype = UNDEFINED;
4004     const auto uh = ModellingHypothesis::UNDEFINEDHYPOTHESIS;
4005     throw_if((this->mb.getBehaviourType() != BehaviourDescription::STANDARDSTRAINBASEDBEHAVIOUR) &&
4006                  (this->mb.getBehaviourType() != BehaviourDescription::STANDARDFINITESTRAINBEHAVIOUR),
4007              "the @Swelling keyword is only valid for small or "
4008              "finite strain behaviours");
4009     this->checkNotEndOfFile("BehaviourDSLCommon::treatSwelling");
4010     if (this->current->value == "<") {
4011       auto options = std::vector<tfel::utilities::Token>{};
4012       this->readList(options, "BehaviourDSLCommon::treatSwelling", "<", ">", true);
4013       for (const auto& o : options) {
4014         this->checkNotEndOfFile("BehaviourDSLCommon::treatSwelling");
4015         if (o.value == "Orthotropic") {
4016           throw_if(etype != UNDEFINED,
4017                    "error while treating option "
4018                    "'Orthotropic', swelling type already defined");
4019           etype = ORTHOTROPIC;
4020         } else if (o.value == "Volume") {
4021           throw_if(etype != UNDEFINED,
4022                    "error while treating option "
4023                    "'Volume', swelling type already defined");
4024           etype = VOLUME;
4025         } else if (o.value == "Linear") {
4026           throw_if(etype != UNDEFINED,
4027                    "error while treating option "
4028                    "'Linear', swelling type already defined");
4029           etype = LINEAR;
4030         } else {
4031           throw_if(true, "unsupported option '" + o.value + "'");
4032         }
4033       }
4034     }
4035     throw_if(etype == UNDEFINED,
4036              "the user must explicitly state if "
4037              "what kind of swelling is expected using"
4038              "one of the options 'Linear', 'Volume' or 'Orthotropic'");
4039     const auto sd = this->readStressFreeExpansionHandler();
4040     this->readSpecifiedToken("BehaviourDSLCommon::treatSwelling", ";");
4041     if (sd.size() == 1) {
4042       throw_if(sd[0].is<BehaviourData::NullExpansion>(), "a null swelling is not allowed here");
4043       if (etype == VOLUME) {
4044         VolumeSwelling vs = {sd[0]};
4045         this->mb.addStressFreeExpansion(uh, vs);
4046       } else if (etype == LINEAR) {
4047         IsotropicSwelling is = {sd[0]};
4048         this->mb.addStressFreeExpansion(uh, is);
4049       } else if (etype == ORTHOTROPIC) {
4050         throw_if(!sd[0].is<BehaviourData::SFED_ESV>(), "one expects a external state variable name here");
4051         OrthotropicSwellingII os = {sd[0].get<BehaviourData::SFED_ESV>()};
4052         this->mb.addStressFreeExpansion(uh, os);
4053       } else {
4054         throw_if(true, "internal error");
4055       }
4056     } else if (sd.size() == 3) {
4057       throw_if(etype != ORTHOTROPIC,
4058                "the 'Orthotropic' option must be "
4059                "used for an orthotropic swelling");
4060       throw_if(sd[0].is<BehaviourData::NullExpansion>() && sd[1].is<BehaviourData::NullExpansion>() &&
4061                    sd[2].is<BehaviourData::NullExpansion>(),
4062                "all swelling component are null");
4063       OrthotropicSwelling os = {sd[0], sd[1], sd[2]};
4064       this->mb.addStressFreeExpansion(uh, os);
4065     } else {
4066       throw_if(true, "invalid number of swelling handler (shall be 1 or 3, " + std::to_string(sd.size()) + " given)");
4067     }
4068   }  // end of BehaviourDSLCommon::treatSwelling
4069 
readStressFreeExpansionHandler(const tfel::utilities::Token & t)4070   BehaviourData::StressFreeExpansionHandler BehaviourDSLCommon::readStressFreeExpansionHandler(
4071       const tfel::utilities::Token& t) {
4072     auto throw_if = [this](const bool b, const std::string& m) {
4073       if (b) {
4074         this->throwRuntimeError("BehaviourDSLCommon::readStressFreeExpansionHandler", m);
4075       }
4076     };
4077     if (t.flag == tfel::utilities::Token::String) {
4078       // using an external model
4079       const auto md = this->getModelDescription(t.value.substr(1, t.value.size() - 2));
4080       // check that the variable
4081       auto ptr = std::make_shared<ModelDescription>(md);
4082       return {ptr};
4083     }
4084     if (t.value == "0") {
4085       return {BehaviourData::NullExpansion{}};
4086     }
4087     throw_if(!CxxTokenizer::isValidIdentifier(t.value, true), "unexpected token '" + t.value +
4088                                                                   "', expected "
4089                                                                   "external state variable name");
4090     // using an external state variable
4091     // defining modelling hypotheses
4092     if (!this->mb.areModellingHypothesesDefined()) {
4093       this->mb.setModellingHypotheses(this->getDefaultModellingHypotheses());
4094     }
4095     for (const auto h : this->mb.getDistinctModellingHypotheses()) {
4096       throw_if(!this->mb.isExternalStateVariableName(h, t.value), "no external state variable named '" + t.value +
4097                                                                       "' "
4098                                                                       "has been declared");
4099     }
4100     return {BehaviourData::SFED_ESV{t.value}};
4101   }  // end of BehaviourDSLCommon::readStressFreeExpansionHandler
4102 
readStressFreeExpansionHandler()4103   std::vector<BehaviourData::StressFreeExpansionHandler> BehaviourDSLCommon::readStressFreeExpansionHandler() {
4104     auto throw_if = [this](const bool b, const std::string& m) {
4105       if (b) {
4106         this->throwRuntimeError("BehaviourDSLCommon::readStressFreeExpansionHandler", m);
4107       }
4108     };
4109     auto sda = std::vector<tfel::utilities::Token>{};
4110     auto sd = std::vector<BehaviourData::StressFreeExpansionHandler>{};
4111     this->checkNotEndOfFile("BehaviourDSLCommon::treatSwelling");
4112     if (this->current->value == "{") {
4113       this->readList(sda, "BehaviourDSLCommon::readCodeBlockOptions", "{", "}", true);
4114     } else {
4115       sda.push_back(*(this->current));
4116       ++(this->current);
4117     }
4118     if (sda.size() == 1u) {
4119       sd.push_back(this->readStressFreeExpansionHandler(sda[0]));
4120     } else if (sda.size() == 3u) {
4121       throw_if(this->mb.getSymmetryType() != mfront::ORTHOTROPIC,
4122                "orthotropic swelling is only  supported for "
4123                "orthotropic behaviours");
4124       sd.push_back(this->readStressFreeExpansionHandler(sda[0]));
4125       sd.push_back(this->readStressFreeExpansionHandler(sda[1]));
4126       sd.push_back(this->readStressFreeExpansionHandler(sda[2]));
4127     } else {
4128       throw_if(true,
4129                "invalid number of swelling description "
4130                "(expected one or three descriptions)");
4131     }
4132     return sd;
4133   }  // end of BehaviourDSLCommon::readStressFreeExpansionHandler
4134 
treatAxialGrowth()4135   void BehaviourDSLCommon::treatAxialGrowth() {
4136     using AxialGrowth = BehaviourData::AxialGrowth;
4137     const auto uh = ModellingHypothesis::UNDEFINEDHYPOTHESIS;
4138     auto throw_if = [this](const bool b, const std::string& m) {
4139       if (b) {
4140         this->throwRuntimeError("BehaviourDSLCommon::treatAxialGrowth", m);
4141       }
4142     };
4143     throw_if((this->mb.getBehaviourType() != BehaviourDescription::STANDARDSTRAINBASEDBEHAVIOUR) &&
4144                  (this->mb.getBehaviourType() != BehaviourDescription::STANDARDFINITESTRAINBEHAVIOUR),
4145              "the @AxialGrowth keyword is only valid for small or "
4146              "finite strain behaviours");
4147     throw_if(this->mb.getSymmetryType() != mfront::ORTHOTROPIC, "@AxialGrowth is only valid for orthotropic behaviour");
4148     this->checkNotEndOfFile("BehaviourDSLCommon::treatAxialGrowth");
4149     auto s = this->readStressFreeExpansionHandler(*(this->current));
4150     ++(this->current);
4151     this->readSpecifiedToken("BehaviourDSLCommon::treatAxialGrowth", ";");
4152     this->mb.addStressFreeExpansion(uh, AxialGrowth{s});
4153   }  // end of BehaviourDSLCommon::treatAxialGrowth
4154 
treatRelocation()4155   void BehaviourDSLCommon::treatRelocation() {
4156     using Relocation = BehaviourData::Relocation;
4157     auto throw_if = [this](const bool b, const std::string& m) {
4158       if (b) {
4159         this->throwRuntimeError("BehaviourDSLCommon::treatRelocation", m);
4160       }
4161     };
4162     throw_if((this->mb.getBehaviourType() != BehaviourDescription::STANDARDSTRAINBASEDBEHAVIOUR) &&
4163                  (this->mb.getBehaviourType() != BehaviourDescription::STANDARDFINITESTRAINBEHAVIOUR),
4164              "the @Relocation keyword is only valid for small or "
4165              "finite strain behaviours");
4166     if (!this->mb.areModellingHypothesesDefined()) {
4167       this->mb.setModellingHypotheses(this->getDefaultModellingHypotheses());
4168     }
4169     const auto& mh = this->mb.getModellingHypotheses();
4170     throw_if((mh.find(ModellingHypothesis::AXISYMMETRICALGENERALISEDPLANESTRESS) == mh.end()) &&
4171                  (mh.find(ModellingHypothesis::AXISYMMETRICALGENERALISEDPLANESTRAIN) == mh.end()) &&
4172                  (mh.find(ModellingHypothesis::GENERALISEDPLANESTRAIN) == mh.end()),
4173              "the @Relocation keyword has not effect on this behaviour as the none of "
4174              "the following hypothesis is supported:\n"
4175              "- AxisymmetricalGeneralisedPlaneStress\n"
4176              "- AxisymmetricalGeneralisedPlaneStrain\n"
4177              "- GeneralisedPlaneStrain");
4178     this->checkNotEndOfFile("BehaviourDSLCommon::treatRelocation");
4179     const auto s = this->readStressFreeExpansionHandler(*(this->current));
4180     ++(this->current);
4181     this->readSpecifiedToken("BehaviourDSLCommon::treatRelocation", ";");
4182     auto add = [this, &mh, &s](const Hypothesis h) {
4183       if (mh.find(h) != mh.end()) {
4184         this->mb.addStressFreeExpansion(h, Relocation{s});
4185       }
4186     };
4187     add(ModellingHypothesis::AXISYMMETRICALGENERALISEDPLANESTRESS);
4188     add(ModellingHypothesis::AXISYMMETRICALGENERALISEDPLANESTRAIN);
4189     add(ModellingHypothesis::GENERALISEDPLANESTRAIN);
4190   }  // end of BehaviourDSLCommon::treatRelocation
4191 
writeBehaviourUpdateIntegrationVariables(std::ostream & os,const Hypothesis h) const4192   void BehaviourDSLCommon::writeBehaviourUpdateIntegrationVariables(std::ostream& os, const Hypothesis h) const {
4193     const auto& d = this->mb.getBehaviourData(h);
4194     this->checkBehaviourFile(os);
4195     os << "/*!\n"
4196        << "* \\brief Update internal variables at end of integration\n"
4197        << "*/\n"
4198        << "void updateIntegrationVariables()";
4199     if (!d.getIntegrationVariables().empty()) {
4200       os << "{\n";
4201       for (const auto& v : d.getIntegrationVariables()) {
4202         if (!d.isStateVariableName(v.name)) {
4203           if (d.isMemberUsedInCodeBlocks(v.name)) {
4204             os << "this->" << v.name << " += "
4205                << "this->d" << v.name << ";\n";
4206           }
4207         }
4208       }
4209       os << "}\n\n";
4210     } else {
4211       os << "\n{}\n\n";
4212     }
4213   }  // end of BehaviourDSLCommon::writeBehaviourUpdateIntegrationVariables
4214 
writeBehaviourUpdateStateVariables(std::ostream & os,const Hypothesis h) const4215   void BehaviourDSLCommon::writeBehaviourUpdateStateVariables(std::ostream& os, const Hypothesis h) const {
4216     const auto& d = this->mb.getBehaviourData(h);
4217     this->checkBehaviourFile(os);
4218     os << "/*!\n"
4219        << "* \\brief Update internal variables at end of integration\n"
4220        << "*/\n"
4221        << "void updateStateVariables()";
4222     if (!d.getStateVariables().empty()) {
4223       os << "{\n";
4224       for (const auto& v : d.getStateVariables()) {
4225         os << "this->" << v.name << " += "
4226            << "this->d" << v.name << ";\n";
4227       }
4228       os << "}\n\n";
4229     } else {
4230       os << "\n{}\n\n";
4231     }
4232   }  // end of BehaviourDSLCommon::writeBehaviourUpdateStateVariables
4233 
writeBehaviourUpdateAuxiliaryStateVariables(std::ostream & os,const Hypothesis h) const4234   void BehaviourDSLCommon::writeBehaviourUpdateAuxiliaryStateVariables(std::ostream& os, const Hypothesis h) const {
4235     os << "/*!\n"
4236        << "* \\brief Update auxiliary state variables at end of integration\n"
4237        << "*/\n"
4238        << "void updateAuxiliaryStateVariables()";
4239     const auto& em = this->mb.getModelsDescriptions();
4240     if ((this->mb.hasCode(h, BehaviourData::UpdateAuxiliaryStateVariables)) || (!em.empty())) {
4241       os << "{\n"
4242          << "using namespace std;\n"
4243          << "using namespace tfel::math;\n";
4244       for (const auto& m : em) {
4245         if (m.outputs.size() == 1) {
4246           const auto vn = m.outputs[0].name;
4247           os << "this->" << vn << " += this->d" << vn << ";\n";
4248         } else {
4249           this->throwRuntimeError("BehaviourDSLCommon::writeBehaviourUpdateAuxiliaryStateVariables",
4250                                   "only models with one output are supported");
4251         }
4252       }
4253       if (this->mb.hasCode(h, BehaviourData::UpdateAuxiliaryStateVariables)) {
4254         writeMaterialLaws(os, this->mb.getMaterialLaws());
4255         os << this->mb.getCode(h, BehaviourData::UpdateAuxiliaryStateVariables) << "\n";
4256       }
4257       os << "}\n\n";
4258     } else {
4259       os << "\n{}\n\n";
4260     }
4261   }  // end of  BehaviourDSLCommon::writeBehaviourUpdateAuxiliaryStateVariables
4262 
writeBehaviourComputeInternalEnergy(std::ostream & os,const Hypothesis h) const4263   void BehaviourDSLCommon::writeBehaviourComputeInternalEnergy(std::ostream& os, const Hypothesis h) const {
4264     os << "/*!\n"
4265        << "* \\brief Update the internal energy at end of the time step\n"
4266        << "* \\param[in] Psi_s: internal energy at end of the time step\n"
4267        << "*/\n"
4268        << "void computeInternalEnergy(real& Psi_s) const";
4269     if (this->mb.hasCode(h, BehaviourData::ComputeInternalEnergy)) {
4270       os << "{\n"
4271          << "using namespace std;\n"
4272          << "using namespace tfel::math;\n";
4273       writeMaterialLaws(os, this->mb.getMaterialLaws());
4274       os << this->mb.getCode(h, BehaviourData::ComputeInternalEnergy) << "\n}\n\n";
4275     } else {
4276       os << "\n{\nPsi_s=0;\n}\n\n";
4277     }
4278   }  // end of BehaviourDSLCommon::writeBehaviourComputeInternalEnergy
4279 
writeBehaviourComputeDissipatedEnergy(std::ostream & os,const Hypothesis h) const4280   void BehaviourDSLCommon::writeBehaviourComputeDissipatedEnergy(std::ostream& os, const Hypothesis h) const {
4281     os << "/*!\n"
4282        << "* \\brief Update the dissipated energy at end of the time step\n"
4283        << "* \\param[in] Psi_d: dissipated energy at end of the time step\n"
4284        << "*/\n"
4285        << "void computeDissipatedEnergy(real& Psi_d) const";
4286     if (this->mb.hasCode(h, BehaviourData::ComputeDissipatedEnergy)) {
4287       os << "{\n"
4288          << "using namespace std;\n"
4289          << "using namespace tfel::math;\n";
4290       writeMaterialLaws(os, this->mb.getMaterialLaws());
4291       os << this->mb.getCode(h, BehaviourData::ComputeDissipatedEnergy) << "\n}\n\n";
4292     } else {
4293       os << "\n{\nPsi_d=0;\n}\n\n";
4294     }
4295   }  // end of BehaviourDSLCommon::writeBehaviourComputeDissipatedEnergy
4296 
hasUserDefinedTangentOperatorCode(const Hypothesis h) const4297   bool BehaviourDSLCommon::hasUserDefinedTangentOperatorCode(const Hypothesis h) const {
4298     using tfel::material::getFiniteStrainBehaviourTangentOperatorFlags;
4299     if (this->mb.getBehaviourType() == BehaviourDescription::STANDARDFINITESTRAINBEHAVIOUR) {
4300       // all available tangent operators for finite strain behaviours
4301       const auto tos = getFiniteStrainBehaviourTangentOperatorFlags();
4302       // search tangent operators defined by the user
4303       for (const auto& t : tos) {
4304         const auto ktype = convertFiniteStrainBehaviourTangentOperatorFlagToString(t);
4305         if (this->mb.hasCode(h, std::string(BehaviourData::ComputeTangentOperator) + '-' + ktype)) {
4306           return true;
4307         }
4308       }
4309     } else {
4310       if (this->mb.hasCode(h, BehaviourData::ComputeTangentOperator)) {
4311         return true;
4312       }
4313     }
4314     return false;
4315   }  // end of BehaviourDSLCommon::hasUserDefinedTangentOperatorCode
4316 
writeBehaviourIntegrator(std::ostream & os,const Hypothesis h) const4317   void BehaviourDSLCommon::writeBehaviourIntegrator(std::ostream& os, const Hypothesis h) const {
4318     const auto btype = this->mb.getBehaviourTypeFlag();
4319     this->checkBehaviourFile(os);
4320     os << "/*!\n"
4321        << "* \\brief Integrate behaviour  over the time step\n"
4322        << "*/\n"
4323        << "IntegrationResult\n"
4324        << "integrate(const SMFlag smflag, const SMType smt) override{\n"
4325        << "using namespace std;\n"
4326        << "using namespace tfel::math;\n";
4327     writeMaterialLaws(os, this->mb.getMaterialLaws());
4328     if ((this->mb.getBehaviourType() == BehaviourDescription::STANDARDSTRAINBASEDBEHAVIOUR) ||
4329         (this->mb.getBehaviourType() == BehaviourDescription::COHESIVEZONEMODEL)||
4330 	(this->mb.getBehaviourType() == BehaviourDescription::GENERALBEHAVIOUR)) {
4331       if (this->mb.useQt()) {
4332         os << "raise_if(smflag!=MechanicalBehaviour<" << btype << ",hypothesis,Type,use_qt>::STANDARDTANGENTOPERATOR,\n"
4333            << "\"invalid tangent operator flag\");\n";
4334       } else {
4335         os << "raise_if(smflag!=MechanicalBehaviour<" << btype << ",hypothesis,Type,false>::STANDARDTANGENTOPERATOR,\n"
4336            << "\"invalid tangent operator flag\");\n";
4337       }
4338     }
4339     os << "bool computeTangentOperator_ = smt!=NOSTIFFNESSREQUESTED;\n";
4340     if (this->mb.hasCode(h, BehaviourData::ComputePredictor)) {
4341       os << this->mb.getCode(h, BehaviourData::ComputePredictor) << '\n';
4342     }
4343     if (this->mb.hasCode(h, BehaviourData::Integrator)) {
4344       os << this->mb.getCode(h, BehaviourData::Integrator) << '\n';
4345     }
4346     os << "this->updateIntegrationVariables();\n"
4347        << "this->updateStateVariables();\n"
4348        << "this->updateAuxiliaryStateVariables();\n";
4349     for (const auto& v : this->mb.getBehaviourData(h).getPersistentVariables()) {
4350       this->writePhysicalBoundsChecks(os, v, false);
4351     }
4352     for (const auto& v : this->mb.getBehaviourData(h).getPersistentVariables()) {
4353       this->writeBoundsChecks(os, v, false);
4354     }
4355     if (this->hasUserDefinedTangentOperatorCode(h)) {
4356       os << "if(computeTangentOperator_){\n";
4357       if (this->mb.getBehaviourType() == BehaviourDescription::STANDARDFINITESTRAINBEHAVIOUR) {
4358         os << "if(!this->computeConsistentTangentOperator(smflag,smt)){\n";
4359       } else {
4360         os << "if(!this->computeConsistentTangentOperator(smt)){\n";
4361       }
4362       if (this->mb.useQt()) {
4363         os << "return MechanicalBehaviour<" << btype << ",hypothesis,Type,use_qt>::FAILURE;\n";
4364       } else {
4365         os << "return MechanicalBehaviour<" << btype << ",hypothesis,Type,false>::FAILURE;\n";
4366       }
4367       os << "}\n";
4368       os << "}\n";
4369     }
4370     if (this->mb.useQt()) {
4371       os << "return MechanicalBehaviour<" << btype << ",hypothesis,Type,use_qt>::SUCCESS;\n";
4372     } else {
4373       os << "return MechanicalBehaviour<" << btype << ",hypothesis,Type,false>::SUCCESS;\n";
4374     }
4375     os << "}\n\n";
4376   }
4377 
writeBehaviourDisabledConstructors(std::ostream & os) const4378   void BehaviourDSLCommon::writeBehaviourDisabledConstructors(std::ostream& os) const {
4379     this->checkBehaviourFile(os);
4380     os << "//! \\brief Default constructor (disabled)\n"
4381        << this->mb.getClassName() << "() =delete ;\n"
4382        << "//! \\brief Copy constructor (disabled)\n"
4383        << this->mb.getClassName() << "(const " << this->mb.getClassName() << "&) = delete;\n"
4384        << "//! \\brief Assignement operator (disabled)\n"
4385        << this->mb.getClassName() << "& operator = (const " << this->mb.getClassName() << "&) = delete;\n\n";
4386   }
4387 
writeBehaviourSetOutOfBoundsPolicy(std::ostream & os) const4388   void BehaviourDSLCommon::writeBehaviourSetOutOfBoundsPolicy(std::ostream& os) const {
4389     this->checkBehaviourFile(os);
4390     os << "/*!\n"
4391        << "* \\brief set the policy for \"out of bounds\" conditions\n"
4392        << "*/\n"
4393        << "void\nsetOutOfBoundsPolicy(const OutOfBoundsPolicy policy_value){\n"
4394        << "this->policy = policy_value;\n"
4395        << "} // end of setOutOfBoundsPolicy\n\n";
4396   }  // end of BehaviourDSLCommon::writeBehaviourSetOutOfBoundsPolicy
4397 
writeBoundsChecks(std::ostream & os,const VariableDescription & v,const std::string & n,const bool b)4398   static void writeBoundsChecks(std::ostream& os, const VariableDescription& v, const std::string& n, const bool b) {
4399     if (!v.hasBounds()) {
4400       return;
4401     }
4402     const auto& bounds = v.getBounds();
4403     if (bounds.boundsType == VariableBoundsDescription::LOWER) {
4404       os << "BoundsCheck<N>::lowerBoundCheck(\"" << n << "\",this->" << n << ","
4405          << "static_cast<real>(" << bounds.lowerBound << "),this->policy);\n";
4406       if (b) {
4407         os << "BoundsCheck<N>::lowerBoundCheck(\"" << n << "+d" << n << "\",this->" << n << "+this->d" << n << ","
4408            << "static_cast<real>(" << bounds.lowerBound << "),this->policy);\n";
4409       }
4410     } else if (bounds.boundsType == VariableBoundsDescription::UPPER) {
4411       os << "BoundsCheck<N>::upperBoundCheck(\"" << n << "\",this->" << n << ","
4412          << "static_cast<real>(" << bounds.upperBound << "),this->policy);\n";
4413       if (b) {
4414         os << "BoundsCheck<N>::upperBoundCheck(\"" << n << "+d" << n << "\",this->" << n << "+this->d" << n << ","
4415            << "static_cast<real>(" << bounds.upperBound << "),this->policy);\n";
4416       }
4417     } else if (bounds.boundsType == VariableBoundsDescription::LOWERANDUPPER) {
4418       os << "BoundsCheck<N>::lowerAndUpperBoundsChecks(\"" << n << "\",this->" << n << ","
4419          << "static_cast<real>(" << bounds.lowerBound << "),"
4420          << "static_cast<real>(" << bounds.upperBound << "),this->policy);\n";
4421       if (b) {
4422         os << "BoundsCheck<N>::lowerAndUpperBoundsChecks(\"" << n << "+d" << n << "\",this->" << n << "+this->d" << n
4423            << ","
4424            << "static_cast<real>(" << bounds.lowerBound << "),"
4425            << "static_cast<real>(" << bounds.upperBound << "),this->policy);\n";
4426       }
4427     } else {
4428       tfel::raise(
4429           "BehaviourDSLCommon::writeBoundsChecks: "
4430           "internal error (unsupported bounds type)");
4431     }
4432   }  // end of writeBoundsChecks
4433 
writeBoundsChecks(std::ostream & os,const VariableDescription & v,const bool b) const4434   void BehaviourDSLCommon::writeBoundsChecks(std::ostream& os, const VariableDescription& v, const bool b) const {
4435     if (v.arraySize == 1u) {
4436       mfront::writeBoundsChecks(os, v, v.name, b);
4437     } else {
4438       for (unsigned short i = 0; i != v.arraySize; ++i) {
4439         mfront::writeBoundsChecks(os, v, v.name + '[' + std::to_string(i) + ']', b);
4440       }
4441     }
4442   }  // end of BehaviourDSLCommon::writeBoundsChecks
4443 
writePhysicalBoundsChecks(std::ostream & os,const VariableDescription & v,const std::string & n,const bool b)4444   static void writePhysicalBoundsChecks(std::ostream& os,
4445                                         const VariableDescription& v,
4446                                         const std::string& n,
4447                                         const bool b) {
4448     if (!v.hasPhysicalBounds()) {
4449       return;
4450     }
4451     const auto& bounds = v.getPhysicalBounds();
4452     if (bounds.boundsType == VariableBoundsDescription::LOWER) {
4453       os << "BoundsCheck<N>::lowerBoundCheck(\"" << n << "\",this->" << n << ","
4454          << "static_cast<real>(" << bounds.lowerBound << "));\n";
4455       if (b) {
4456         os << "BoundsCheck<N>::lowerBoundCheck(\"" << n << "+d" << n << "\",this->" << n << "+this->d" << n << ","
4457            << "static_cast<real>(" << bounds.lowerBound << "));\n";
4458       }
4459     } else if (bounds.boundsType == VariableBoundsDescription::UPPER) {
4460       os << "BoundsCheck<N>::upperBoundCheck(\"" << n << "\",this->" << n << ","
4461          << "static_cast<real>(" << bounds.upperBound << "));\n";
4462       if (b) {
4463         os << "BoundsCheck<N>::upperBoundCheck(\"" << n << "+d" << n << "\",this->" << n << "+this->d" << n << ","
4464            << "static_cast<real>(" << bounds.upperBound << "));\n";
4465       }
4466     } else if (bounds.boundsType == VariableBoundsDescription::LOWERANDUPPER) {
4467       os << "BoundsCheck<N>::lowerAndUpperBoundsChecks(\"" << n << "\",this->" << n << ","
4468          << "static_cast<real>(" << bounds.lowerBound << "),"
4469          << "static_cast<real>(" << bounds.upperBound << "));\n";
4470       if (b) {
4471         os << "BoundsCheck<N>::lowerAndUpperBoundsChecks(\"" << n << "+d" << n << "\",this->" << n << "+this->d" << n
4472            << ","
4473            << "static_cast<real>(" << bounds.lowerBound << "),"
4474            << "static_cast<real>(" << bounds.upperBound << "));\n";
4475       }
4476     } else {
4477       tfel::raise(
4478           "BehaviourDSLCommon::writePhysicalBoundsChecks: "
4479           "internal error (unsupported bounds type)");
4480     }
4481   }  // end of writePhysicalBoundsChecks
4482 
writePhysicalBoundsChecks(std::ostream & os,const VariableDescription & v,const bool b) const4483   void BehaviourDSLCommon::writePhysicalBoundsChecks(std::ostream& os,
4484                                                      const VariableDescription& v,
4485                                                      const bool b) const {
4486     if (v.arraySize == 1u) {
4487       mfront::writePhysicalBoundsChecks(os, v, v.name, b);
4488     } else {
4489       for (unsigned short i = 0; i != v.arraySize; ++i) {
4490         mfront::writePhysicalBoundsChecks(os, v, v.name + '[' + std::to_string(i) + ']', b);
4491       }
4492     }
4493   }  // end of BehaviourDSLCommon::writePhysicalBoundsChecks
4494 
writeBehaviourCheckBounds(std::ostream & os,const Hypothesis h) const4495   void BehaviourDSLCommon::writeBehaviourCheckBounds(std::ostream& os, const Hypothesis h) const {
4496     auto write_physical_bounds = [this, &os](const VariableDescriptionContainer& c, const bool b) {
4497       for (const auto& v : c) {
4498         this->writePhysicalBoundsChecks(os, v, b);
4499       }
4500     };
4501     auto write_bounds = [this, &os](const VariableDescriptionContainer& c, const bool b) {
4502       for (const auto& v : c) {
4503         this->writeBoundsChecks(os, v, b);
4504       }
4505     };
4506     const auto& md = this->mb.getBehaviourData(h);
4507     this->checkBehaviourFile(os);
4508     os << "/*!\n"
4509        << "* \\brief check bounds\n"
4510        << "*/\n"
4511        << "void checkBounds() const{\n";
4512     write_physical_bounds(md.getMaterialProperties(), false);
4513     write_physical_bounds(md.getPersistentVariables(), false);
4514     write_physical_bounds(md.getExternalStateVariables(), true);
4515     write_physical_bounds(md.getLocalVariables(), false);
4516     write_bounds(md.getMaterialProperties(), false);
4517     write_bounds(md.getPersistentVariables(), false);
4518     write_bounds(md.getExternalStateVariables(), true);
4519     write_bounds(md.getLocalVariables(), false);
4520     os << "} // end of checkBounds\n\n";
4521   }  // end of BehaviourDSLCommon::writeBehaviourCheckBounds
4522 
getBehaviourConstructorsInitializers(const Hypothesis h) const4523   std::string BehaviourDSLCommon::getBehaviourConstructorsInitializers(const Hypothesis h) const {
4524     // variable initialisation
4525     auto init = std::string();
4526     auto append = [&init](const std::string& s) {
4527       if (s.empty()) {
4528         return;
4529       }
4530       if (!init.empty()) {
4531         init += ",\n";
4532       }
4533       init += s;
4534     };
4535     append(this->getIntegrationVariablesIncrementsInitializers(h));
4536     append(this->getLocalVariablesInitializers(h));
4537     // tangent operator blocks
4538     const auto& blocks = this->mb.getTangentOperatorBlocks();
4539     if (this->mb.hasTrivialTangentOperatorStructure()) {
4540       tfel::raise_if(
4541           ((blocks.size() != 1u) || (blocks.front().first.arraySize != 1u) ||
4542            (blocks.front().second.arraySize != 1u)),
4543           "BehaviourDSLCommon::getBehaviourConstructorsInitializers: internal error");
4544       if (this->mb.getBehaviourType() !=
4545           BehaviourDescription::STANDARDFINITESTRAINBEHAVIOUR) {
4546         append(this->mb.getTangentOperatorBlockName(blocks.front()) + "(Dt)");
4547       }
4548     } else {
4549       tfel::math::tvector<10, int> offset;
4550       tfel::fsalgo::fill<10>::exe(offset.begin(), 0);
4551       auto update_offset = [&offset](const SupportedTypes::TypeSize s1,
4552                                      const SupportedTypes::TypeSize s2) {
4553         offset[0] += s1.getScalarSize() * s2.getScalarSize();
4554         offset[1] += s1.getTVectorSize() * s2.getTVectorSize();
4555         offset[2] += s1.getStensorSize() * s2.getStensorSize();
4556         offset[3] += s1.getTensorSize() * s2.getTensorSize();
4557         offset[4] += s1.getScalarSize() * s2.getTVectorSize() +
4558                      s2.getScalarSize() * s1.getTVectorSize();
4559         offset[5] += s1.getScalarSize() * s2.getStensorSize() +
4560                      s2.getScalarSize() * s1.getStensorSize();
4561         offset[6] += s1.getScalarSize() * s2.getTensorSize() +
4562                      s2.getScalarSize() * s1.getTensorSize();
4563         offset[7] += s1.getTVectorSize() * s2.getStensorSize() +
4564                      s2.getTVectorSize() * s1.getStensorSize();
4565         offset[8] += s1.getTVectorSize() * s2.getTensorSize() +
4566                      s2.getTVectorSize() * s1.getTensorSize();
4567         offset[9] += s1.getStensorSize() * s2.getTensorSize() +
4568                      s2.getStensorSize() * s1.getTensorSize();
4569       };
4570       auto get_offset = [&offset]() -> std::string {
4571         const char* sizes[10] = {"",
4572                                  "TVectorSize*TVectorSize",
4573                                  "StensorSize*StensorSize",
4574                                  "TensorSize*TensorSize",
4575                                  "TVectorSize",
4576                                  "StensorSize",
4577                                  "TensorSize",
4578                                  "TVectorSize*StensorSize",
4579                                  "TVectorSize*TensorSize",
4580                                  "StensorSize*TensorSize"};
4581         std::string o;
4582         if (offset[0] != 0) {
4583           o += std::to_string(offset[0]);
4584         }
4585         for (int i = 1; i != 10; ++i) {
4586           if (offset[i] != 0) {
4587             if (!o.empty()) {
4588               o += "+";
4589             }
4590             if (offset[i] != 1) {
4591               o += std::to_string(offset[i]) + "*";
4592             }
4593             o += sizes[i];
4594           }
4595         }
4596         if (o.empty()) {
4597           return "0";
4598         }
4599         return o;
4600       };
4601       // write blocks
4602       for (const auto& b : blocks) {
4603         const auto& v1 = b.first;
4604         const auto& v2 = b.second;
4605         if ((v1.arraySize != 1u) || (v2.arraySize != 1u)) {
4606           break;
4607         }
4608         auto throw_unsupported_block = [&v1, &v2] {
4609           tfel::raise(
4610               "BehaviourDSLCommon::getBehaviourConstructorsInitializers:"
4611               "tangent operator blocks associated with "
4612               "the derivative of '" +
4613               displayName(v1) + "' (of type '" + v1.type + "') with respect to '" +
4614               displayName(v2) + "' (of type '" + v2.type + "') is not supported");
4615         };
4616         const auto bn = this->mb.getTangentOperatorBlockName(b);
4617         if (v1.getTypeFlag() == SupportedTypes::SCALAR) {
4618           const auto o = get_offset();
4619           if (v2.getTypeFlag() == SupportedTypes::SCALAR) {
4620             append(bn + "(Dt[" + o + "])");
4621           } else if ((v2.getTypeFlag() == SupportedTypes::STENSOR) ||
4622                      (v2.getTypeFlag() == SupportedTypes::TENSOR)) {
4623             if (o != "0") {
4624               append(bn + "(Dt.begin()+" + o + ")");
4625             } else {
4626               append(bn + "(Dt.begin())");
4627             }
4628           } else {
4629             throw_unsupported_block();
4630           }
4631         } else if (v1.getTypeFlag() == SupportedTypes::TVECTOR) {
4632           if ((v2.getTypeFlag() == SupportedTypes::SCALAR) ||
4633               (v2.getTypeFlag() == SupportedTypes::TVECTOR)) {
4634             const auto o = get_offset();
4635             if (o != "0") {
4636               append(bn + "(Dt.begin()+" + o + ")");
4637             } else {
4638               append(bn + "(Dt.begin())");
4639             }
4640           } else {
4641             throw_unsupported_block();
4642           }
4643         } else if (v1.getTypeFlag() == SupportedTypes::STENSOR) {
4644           if ((v2.getTypeFlag() == SupportedTypes::SCALAR) ||
4645               (v2.getTypeFlag() == SupportedTypes::STENSOR) ||
4646               (v2.getTypeFlag() == SupportedTypes::TENSOR)) {
4647             const auto o = get_offset();
4648             if (o != "0") {
4649               append(bn + "(Dt.begin()+" + o + ")");
4650             } else {
4651               append(bn + "(Dt.begin())");
4652             }
4653           } else {
4654             throw_unsupported_block();
4655           }
4656         } else if (v1.getTypeFlag() == SupportedTypes::TENSOR) {
4657           if ((v2.getTypeFlag() == SupportedTypes::SCALAR) ||
4658               (v2.getTypeFlag() == SupportedTypes::STENSOR) ||
4659               (v2.getTypeFlag() == SupportedTypes::TENSOR)) {
4660             const auto o = get_offset();
4661             if (o != "0") {
4662               append(bn + "(Dt.begin()+" + o + ")");
4663             } else {
4664               append(bn + "(Dt.begin())");
4665             }
4666           } else {
4667             throw_unsupported_block();
4668           }
4669         } else {
4670           throw_unsupported_block();
4671         }
4672         update_offset(v1.getTypeSize(), v2.getTypeSize());
4673       }
4674     }
4675     return init;
4676   }  // end of BehaviourDSLCommon::getBehaviourConstructorsInitializers
4677 
getLocalVariablesInitializers(const Hypothesis) const4678   std::string BehaviourDSLCommon::getLocalVariablesInitializers(const Hypothesis) const{
4679     return {};
4680   } // end of BehaviourDSLCommon::getLocalVariablesInitializers
4681 
writeBehaviourConstructors(std::ostream & os,const Hypothesis h) const4682   void BehaviourDSLCommon::writeBehaviourConstructors(std::ostream& os, const Hypothesis h) const {
4683     auto tmpnames = std::vector<std::string>{};
4684     auto write_body = [this, &os, &tmpnames, h] {
4685       os << "using namespace std;\n"
4686          << "using namespace tfel::math;\n"
4687          << "using std::vector;\n";
4688       writeMaterialLaws(os, this->mb.getMaterialLaws());
4689       this->writeBehaviourParameterInitialisation(os, h);
4690       // calling models
4691       for (const auto& m : this->mb.getModelsDescriptions()) {
4692         if (m.outputs.size() == 1) {
4693           const auto vn = m.outputs[0].name;
4694           this->writeModelCall(os, tmpnames, h, m, "d" + vn, vn, "em");
4695           os << "this->d" << vn << " -= this->" << vn << ";\n";
4696         } else {
4697           this->throwRuntimeError("BehaviourDSLCommon::writeBehaviourInitializeMethod",
4698                                   "only models with one output are supported yet");
4699         }
4700       }
4701       this->writeBehaviourLocalVariablesInitialisation(os, h);
4702     };
4703     this->checkBehaviourFile(os);
4704     // initializers
4705     const auto& init = this->getBehaviourConstructorsInitializers(h);
4706     // writing constructors
4707     os << "/*!\n"
4708        << "* \\brief Constructor\n"
4709        << "*/\n";
4710     if (this->mb.useQt()) {
4711       os << this->mb.getClassName() << "("
4712          << "const " << this->mb.getClassName() << "BehaviourData<hypothesis,Type,use_qt>& src1,\n"
4713          << "const " << this->mb.getClassName() << "IntegrationData<hypothesis,Type,use_qt>& src2)\n"
4714          << ": " << this->mb.getClassName() << "BehaviourData<hypothesis,Type,use_qt>(src1),\n"
4715          << this->mb.getClassName() << "IntegrationData<hypothesis,Type,use_qt>(src2)";
4716     } else {
4717       os << this->mb.getClassName() << "("
4718          << "const " << this->mb.getClassName() << "BehaviourData<hypothesis,Type,false>& src1,\n"
4719          << "const " << this->mb.getClassName() << "IntegrationData<hypothesis,Type,false>& src2)\n"
4720          << ": " << this->mb.getClassName() << "BehaviourData<hypothesis,Type,false>(src1),\n"
4721          << this->mb.getClassName() << "IntegrationData<hypothesis,Type,false>(src2)";
4722     }
4723     if (!init.empty()) {
4724       os << ",\n" << init;
4725     }
4726     os << "\n{\n";
4727     write_body();
4728     os << "}\n\n";
4729     // constructor specific to interfaces
4730     for (const auto& i : this->interfaces) {
4731       if (i.second->isBehaviourConstructorRequired(h, this->mb)) {
4732         i.second->writeBehaviourConstructorHeader(os, this->mb, h, init);
4733 	os << "\n{\n";
4734 	write_body();
4735 	i.second->writeBehaviourConstructorBody(os, this->mb, h);
4736 	os << "}\n\n";
4737       }
4738     }
4739   }
4740 
writeHillTensorComputation(std::ostream & out,const std::string & H,const BehaviourDescription::HillTensor & h,std::function<std::string (const MaterialPropertyInput &)> & f) const4741   void BehaviourDSLCommon::writeHillTensorComputation(
4742       std::ostream& out,
4743       const std::string& H,
4744       const BehaviourDescription::HillTensor& h,
4745       std::function<std::string(const MaterialPropertyInput&)>& f) const {
4746     auto throw_if = [this](const bool b, const std::string& m) {
4747       if (b) {
4748         this->throwRuntimeError("BehaviourDSLCommon::writeHillTensorComputation", m);
4749       }
4750     };
4751     throw_if(this->mb.getSymmetryType() == mfront::ISOTROPIC, "material is not orthotropic");
4752     for (decltype(h.c.size()) i = 0; i != h.c.size(); ++i) {
4753       this->writeMaterialPropertyCheckBoundsEvaluation(out, h.c[i], f);
4754     }
4755     if (this->mb.getOrthotropicAxesConvention() == OrthotropicAxesConvention::PIPE) {
4756       out << H << " = tfel::material::computeHillTensor<hypothesis,"
4757           << "OrthotropicAxesConvention::PIPE,stress>(";
4758     } else if (this->mb.getOrthotropicAxesConvention() == OrthotropicAxesConvention::PLATE) {
4759       out << H << " = tfel::material::computeHillTensor<hypothesis,"
4760           << "OrthotropicAxesConvention::PLATE,stress>(";
4761     } else {
4762       out << H << " = tfel::material::computeHillTensor<hypothesis,"
4763           << "OrthotropicAxesConvention::DEFAULT,stress>(";
4764     }
4765     for (decltype(h.c.size()) i = 0; i != h.c.size();) {
4766       this->writeMaterialPropertyEvaluation(out, h.c[i], f);
4767       if (++i != h.c.size()) {
4768         out << ",\n";
4769       }
4770     }
4771     out << ");\n";
4772   }  // end of BehaviourDSLCommon::writeHillTensorComputation
4773 
writeStiffnessTensorComputation(std::ostream & out,const std::string & D,std::function<std::string (const MaterialPropertyInput &)> & f) const4774   void BehaviourDSLCommon::writeStiffnessTensorComputation(
4775       std::ostream& out, const std::string& D, std::function<std::string(const MaterialPropertyInput&)>& f) const {
4776     const auto& emps = this->mb.getElasticMaterialProperties();
4777     if ((this->mb.getSymmetryType() == mfront::ISOTROPIC) && (this->mb.getElasticSymmetryType() != mfront::ISOTROPIC)) {
4778       this->throwRuntimeError("BehaviourDSLCommon::writeStiffnessTensorComputation",
4779                               "inconsistent symmetry type for the material and "
4780                               "the elastic behaviour.");
4781     }
4782     bool ua = true;
4783     if (!this->mb.hasAttribute(BehaviourDescription::requiresUnAlteredStiffnessTensor)) {
4784       const auto& mh = this->mb.getModellingHypotheses();
4785       if ((mh.find(ModellingHypothesis::PLANESTRESS) != mh.end()) ||
4786           (mh.find(ModellingHypothesis::AXISYMMETRICALGENERALISEDPLANESTRESS) != mh.end())) {
4787         this->throwRuntimeError("BehaviourDSLCommon::writeStiffnessTensorComputation",
4788                                 "For plane stress hypotheses, it is required to precise whether "
4789                                 "the expected stiffness tensor is 'Altered' (the plane stress "
4790                                 "hypothesis is taken into account) or 'UnAltered' (the stiffness "
4791                                 "tensor is the same as in plane strain). "
4792                                 "See the '@ComputeStiffnessTensor' documentation");
4793       }
4794     } else {
4795       ua = this->mb.getAttribute<bool>(BehaviourDescription::requiresUnAlteredStiffnessTensor);
4796     }
4797     if (this->mb.getElasticSymmetryType() == mfront::ISOTROPIC) {
4798       if (emps.size() != 2u) {
4799         this->throwRuntimeError("BehaviourDSLCommon::writeStiffnessTensorComputation",
4800                                 "invalid number of material properties");
4801       }
4802       this->writeMaterialPropertyCheckBoundsEvaluation(out, emps[0], f);
4803       this->writeMaterialPropertyCheckBoundsEvaluation(out, emps[1], f);
4804       if (ua) {
4805         out << "tfel::material::computeIsotropicStiffnessTensor<hypothesis,StiffnessTensorAlterationCharacteristic::"
4806                "UNALTERED"
4807             << ">(" << D << ",";
4808       } else {
4809         out << "tfel::material::computeIsotropicStiffnessTensor<hypothesis,StiffnessTensorAlterationCharacteristic::"
4810                "ALTERED"
4811             << ">(" << D << ",";
4812       }
4813       this->writeMaterialPropertyEvaluation(out, emps[0], f);
4814       out << ",\n";
4815       this->writeMaterialPropertyEvaluation(out, emps[1], f);
4816       out << ");\n";
4817     } else if (this->mb.getElasticSymmetryType() == mfront::ORTHOTROPIC) {
4818       if (emps.size() != 9u) {
4819         this->throwRuntimeError("BehaviourDSLCommon::writeStiffnessTensorComputation",
4820                                 "invalid number of material properties");
4821       }
4822       for (decltype(emps.size()) i = 0; i != emps.size(); ++i) {
4823         this->writeMaterialPropertyCheckBoundsEvaluation(out, emps[i], f);
4824       }
4825       if (ua) {
4826         if (this->mb.getOrthotropicAxesConvention() == OrthotropicAxesConvention::PIPE) {
4827           out << "tfel::material::computeOrthotropicStiffnessTensor<hypothesis,"
4828               << "StiffnessTensorAlterationCharacteristic::UNALTERED,"
4829               << "OrthotropicAxesConvention::PIPE>(" << D << ",";
4830         } else if (this->mb.getOrthotropicAxesConvention() == OrthotropicAxesConvention::PLATE) {
4831           out << "tfel::material::computeOrthotropicStiffnessTensor<hypothesis,"
4832               << "StiffnessTensorAlterationCharacteristic::UNALTERED,"
4833               << "OrthotropicAxesConvention::PLATE>(" << D << ",";
4834         } else {
4835           out << "tfel::material::computeOrthotropicStiffnessTensor<hypothesis,"
4836               << "StiffnessTensorAlterationCharacteristic::UNALTERED,"
4837               << "OrthotropicAxesConvention::DEFAULT>(" << D << ",";
4838         }
4839       } else {
4840         if (this->mb.getOrthotropicAxesConvention() == OrthotropicAxesConvention::PIPE) {
4841           out << "tfel::material::computeOrthotropicStiffnessTensor<hypothesis,"
4842               << "StiffnessTensorAlterationCharacteristic::ALTERED,"
4843               << "OrthotropicAxesConvention::PIPE>(" << D << ",";
4844         } else if (this->mb.getOrthotropicAxesConvention() == OrthotropicAxesConvention::PLATE) {
4845           out << "tfel::material::computeOrthotropicStiffnessTensor<hypothesis,"
4846               << "StiffnessTensorAlterationCharacteristic::ALTERED,"
4847               << "OrthotropicAxesConvention::PLATE>(" << D << ",";
4848         } else {
4849           out << "tfel::material::computeOrthotropicStiffnessTensor<hypothesis,"
4850               << "StiffnessTensorAlterationCharacteristic::ALTERED,"
4851               << "OrthotropicAxesConvention::DEFAULT>(" << D << ",";
4852         }
4853       }
4854       for (decltype(emps.size()) i = 0; i != emps.size();) {
4855         this->writeMaterialPropertyEvaluation(out, emps[i], f);
4856         if (++i != emps.size()) {
4857           out << ",\n";
4858         }
4859       }
4860       out << ");\n";
4861     } else {
4862       this->throwRuntimeError("BehaviourDSLCommon::writeStiffnessTensorComputation",
4863                               "unsupported elastic symmetry type");
4864     }
4865   }  // end of BehaviourDSLCommon::writeStiffnessTensorComputation
4866 
writeExternalMFrontMaterialPropertyArguments(std::ostream & out,const BehaviourDescription::MaterialProperty & m,std::function<std::string (const MaterialPropertyInput &)> & f) const4867   void BehaviourDSLCommon::writeExternalMFrontMaterialPropertyArguments(
4868       std::ostream& out,
4869       const BehaviourDescription::MaterialProperty& m,
4870       std::function<std::string(const MaterialPropertyInput&)>& f) const {
4871     const auto& cmp = m.get<BehaviourDescription::ExternalMFrontMaterialProperty>();
4872     const auto& mpd = *(cmp.mpd);
4873     out << '(';
4874     if (!mpd.inputs.empty()) {
4875       const auto& inputs = this->mb.getMaterialPropertyInputs(mpd);
4876       auto pi = std::begin(inputs);
4877       const auto pie = std::end(inputs);
4878       while (pi != pie) {
4879         out << f(*pi);
4880         if (++pi != pie) {
4881           out << ",";
4882         }
4883       }
4884     }
4885     out << ")";
4886   }
4887 
writeMaterialPropertyCheckBoundsEvaluation(std::ostream & out,const BehaviourDescription::MaterialProperty & m,std::function<std::string (const MaterialPropertyInput &)> & f) const4888   void BehaviourDSLCommon::writeMaterialPropertyCheckBoundsEvaluation(
4889       std::ostream& out,
4890       const BehaviourDescription::MaterialProperty& m,
4891       std::function<std::string(const MaterialPropertyInput&)>& f) const {
4892     if (m.is<BehaviourDescription::ExternalMFrontMaterialProperty>()) {
4893       const auto& cmp = m.get<BehaviourDescription::ExternalMFrontMaterialProperty>();
4894       const auto& mpd = *(cmp.mpd);
4895       if ((!hasBounds(mpd.inputs)) && (!(hasPhysicalBounds(mpd.inputs)))) {
4896         return;
4897       }
4898       const auto& n = MFrontMaterialPropertyInterface().getFunctionName(mpd);
4899       out << "{\n // check bounds for material property '" << n << "'\n"
4900           << "const auto " << n << "_bounds_check_status = " << n << "_checkBounds";
4901       this->writeExternalMFrontMaterialPropertyArguments(out, cmp, f);
4902       out << ";\n"
4903           << "if(" << n << "_bounds_check_status!=0){\n"
4904           << "// physical bounds\n"
4905           << "tfel::raise_if<OutOfBoundsException>(" << n << "_bounds_check_status<0,\n"
4906           << "\"" << this->mb.getClassName() << ": a variable is out of its physical bounds \"\n"
4907           << "\"when calling the material property '" << n << "'\");\n"
4908           << "} else {\n"
4909           << "// standard bounds\n"
4910           << "if(this->policy==Strict){\n"
4911           << "tfel::raise<OutOfBoundsException>(\"" << this->mb.getClassName() << ": "
4912           << "a variable is out of its bounds \"\n"
4913           << "\"when calling the material property '" << n << "'\");\n"
4914           << "} else if(this->policy==Warning){\n"
4915           << "std::cerr << \"" << this->mb.getClassName() << ": "
4916           << "a variable is out of its bounds \"\n"
4917           << "\"when calling the material property '" << n << "'\\n\";\n"
4918           << "}\n"
4919           << "}\n"
4920           << "}\n";
4921     } else if (!((m.is<BehaviourDescription::ConstantMaterialProperty>()) ||
4922                  (m.is<BehaviourDescription::AnalyticMaterialProperty>()))) {
4923       this->throwRuntimeError("BehaviourDSLCommon::writeMaterialPropertyEvaluation",
4924                               "unsupported material property type");
4925     }
4926   }  // end of BehaviourDSLCommon::writeMaterialPropertyEvaluation
4927 
writeMaterialPropertyEvaluation(std::ostream & out,const BehaviourDescription::MaterialProperty & m,std::function<std::string (const MaterialPropertyInput &)> & f) const4928   void BehaviourDSLCommon::writeMaterialPropertyEvaluation(
4929       std::ostream& out,
4930       const BehaviourDescription::MaterialProperty& m,
4931       std::function<std::string(const MaterialPropertyInput&)>& f) const {
4932     if (m.is<BehaviourDescription::ConstantMaterialProperty>()) {
4933       const auto& cmp = m.get<BehaviourDescription::ConstantMaterialProperty>();
4934       if (!cmp.name.empty()) {
4935         out << "this->" << cmp.name;
4936       } else {
4937         out << cmp.value;
4938       }
4939     } else if (m.is<BehaviourDescription::ExternalMFrontMaterialProperty>()) {
4940       const auto& cmp = m.get<BehaviourDescription::ExternalMFrontMaterialProperty>();
4941       const auto& mpd = *(cmp.mpd);
4942       out << MFrontMaterialPropertyInterface().getFunctionName(mpd);
4943       this->writeExternalMFrontMaterialPropertyArguments(out, cmp, f);
4944     } else if (m.is<BehaviourDescription::AnalyticMaterialProperty>()) {
4945       const auto& amp = m.get<BehaviourDescription::AnalyticMaterialProperty>();
4946       tfel::math::Evaluator e(amp.f);
4947       auto mi = std::map<std::string, std::string>{};
4948       for (const auto& i : this->mb.getMaterialPropertyInputs(e.getVariablesNames())) {
4949         mi[i.name] = f(i);
4950       }
4951       out << e.getCxxFormula(mi);
4952     } else if (m.empty()) {
4953       this->throwRuntimeError(
4954           "BehaviourDSLCommon::writeMaterialPropertyEvaluation",
4955           "empty material property");
4956     } else {
4957       this->throwRuntimeError(
4958           "BehaviourDSLCommon::writeMaterialPropertyEvaluation",
4959           "unsupported material property type");
4960     }
4961   }  // end of BehaviourDSLCommon::writeMaterialPropertyEvaluation
4962 
writeThermalExpansionCoefficientComputation(std::ostream & out,const BehaviourDescription::MaterialProperty & a,const std::string & T,const std::string & idx,const std::string & s) const4963   void BehaviourDSLCommon::writeThermalExpansionCoefficientComputation(std::ostream& out,
4964                                                                        const BehaviourDescription::MaterialProperty& a,
4965                                                                        const std::string& T,
4966                                                                        const std::string& idx,
4967                                                                        const std::string& s) const {
4968     auto throw_if = [this](const bool b, const std::string& m) {
4969       if (b) {
4970         this->throwRuntimeError(
4971             "BehaviourDSLCommon::"
4972             "writeThermalExpansionCoefficientComputation",
4973             m);
4974       }
4975     };
4976     out << "const thermalexpansion alpha" << s;
4977     if (!idx.empty()) {
4978       out << "_" << idx;
4979     }
4980     out << " = ";
4981     if (a.is<BehaviourDescription::ConstantMaterialProperty>()) {
4982       const auto& cmp = a.get<BehaviourDescription::ConstantMaterialProperty>();
4983       if (cmp.name.empty()) {
4984         out << cmp.value << ";\n";
4985       } else {
4986         out << "this->" << cmp.name << ";\n";
4987       }
4988     } else if (a.is<BehaviourDescription::ExternalMFrontMaterialProperty>()) {
4989       const auto& mpd = *(a.get<BehaviourDescription::ExternalMFrontMaterialProperty>().mpd);
4990       const auto inputs = this->mb.getMaterialPropertyInputs(mpd);
4991       out << MFrontMaterialPropertyInterface().getFunctionName(mpd) << '(';
4992       for (auto pi = inputs.begin(); pi != inputs.end();) {
4993         const auto c = pi->category;
4994         if (c == BehaviourDescription::MaterialPropertyInput::TEMPERATURE) {
4995           out << T;
4996         } else if ((c == BehaviourDescription::MaterialPropertyInput::MATERIALPROPERTY) ||
4997                    (c == BehaviourDescription::MaterialPropertyInput::PARAMETER)) {
4998           out << "this->" << pi->name;
4999         } else if (c == BehaviourDescription::MaterialPropertyInput::STATICVARIABLE) {
5000           out << this->mb.getClassName() << "::" << pi->name;
5001         } else {
5002           throw_if(true,
5003                    "thermal expansion coefficients must depend "
5004                    "on the temperature only");
5005         }
5006         if (++pi != inputs.end()) {
5007           out << ",";
5008         }
5009       }
5010       out << ");\n";
5011     } else if (a.is<BehaviourDescription::AnalyticMaterialProperty>()) {
5012       const auto& amp = a.get<BehaviourDescription::AnalyticMaterialProperty>();
5013       auto m = std::map<std::string, std::string>{};
5014       for (const auto& i : this->mb.getMaterialPropertyInputs(amp.getVariablesNames())) {
5015         const auto c = i.category;
5016         if (c == BehaviourDescription::MaterialPropertyInput::TEMPERATURE) {
5017           m.insert({"T", T});
5018         } else if ((c == BehaviourDescription::MaterialPropertyInput::MATERIALPROPERTY) ||
5019                    (c == BehaviourDescription::MaterialPropertyInput::PARAMETER)) {
5020           m.insert({i.name, "this->" + i.name});
5021         } else if (c == BehaviourDescription::MaterialPropertyInput::STATICVARIABLE) {
5022           m.insert({i.name, this->mb.getClassName() + "::" + i.name});
5023         } else {
5024           throw_if(true,
5025                    "thermal expansion coefficients must depend "
5026                    "on the temperature only");
5027         }
5028       }
5029       tfel::math::Evaluator ev(amp.f);
5030       out << ev.getCxxFormula(m) << ";\n";
5031     } else {
5032       throw_if(true, "unsupported material property type");
5033     }
5034   }  // end of BehaviourDSLCommon::writeThermalExpansionCoefficientComputation
5035 
writeThermalExpansionCoefficientsComputations(std::ostream & out,const BehaviourDescription::MaterialProperty & a,const std::string & suffix) const5036   void BehaviourDSLCommon::writeThermalExpansionCoefficientsComputations(
5037       std::ostream& out, const BehaviourDescription::MaterialProperty& a, const std::string& suffix) const {
5038     this->writeThermalExpansionCoefficientComputation(out, a, "this->initial_geometry_reference_temperature", "",
5039                                                       suffix + "_Ti");
5040     this->writeThermalExpansionCoefficientComputation(out, a, "this->T", "t", suffix + "_T");
5041     this->writeThermalExpansionCoefficientComputation(out, a, "this->T+this->dT", "t_dt", suffix + "_T");
5042   }  // end of writeThermalExpansionCoefficientComputation
5043 
writeThermalExpansionComputation(std::ostream & out,const std::string & t,const std::string & c,const std::string & suffix) const5044   void BehaviourDSLCommon::writeThermalExpansionComputation(std::ostream& out,
5045                                                             const std::string& t,
5046                                                             const std::string& c,
5047                                                             const std::string& suffix) const {
5048     const auto Tref = "this->thermal_expansion_reference_temperature";
5049     const auto T = (t == "t") ? "this->T" : "this->T+this->dT";
5050     if (t == "t") {
5051       out << "dl0_l0";
5052     } else {
5053       out << "dl1_l0";
5054     }
5055     out << "[" << c << "] += 1/(1+alpha" << suffix << "_Ti * (this->initial_geometry_reference_temperature-" << Tref
5056         << "))*("
5057         << "alpha" << suffix << "_T_" << t << " * (" << T << "-" << Tref << ")-"
5058         << "alpha" << suffix << "_Ti * (this->initial_geometry_reference_temperature-" << Tref << "));\n";
5059   }  // end of BehaviourDSLCommon::writeThermalExpansionComputation
5060 
writeBehaviourComputeStressFreeExpansion(std::ostream & os,const Hypothesis h) const5061   void BehaviourDSLCommon::writeBehaviourComputeStressFreeExpansion(std::ostream& os, const Hypothesis h) const {
5062     auto tmpnames = std::vector<std::string>{};
5063     auto throw_if = [this](const bool b, const std::string& m) {
5064       if (b) {
5065         this->throwRuntimeError("BehaviourDSLCommon::writeBehaviourComputeStressFreeExpansion", m);
5066       }
5067     };
5068     auto eval = [](std::ostream& out, const BehaviourDescription::MaterialProperty& mp, const std::string& c,
5069                    const bool b) {
5070       const auto& cmp = mp.get<BehaviourDescription::ConstantMaterialProperty>();
5071       const auto Tref = "this->thermal_expansion_reference_temperature";
5072       const auto i = b ? "1" : "0";
5073       const auto T = b ? "this->T+this->dT" : "this->T";
5074       if (cmp.name.empty()) {
5075         out << "dl" << i << "_l0"
5076             << "[" << c << "] += " << cmp.value << "/(1+" << cmp.value
5077             << "*(this->initial_geometry_reference_temperature-" << Tref << "))"
5078             << "*(" << T << "-this->initial_geometry_reference_temperature);\n";
5079       } else {
5080         out << "dl" << i << "_l0"
5081             << "[" << c << "] += (this->" << cmp.name << ")/(1+(this->" << cmp.name
5082             << ")*(this->initial_geometry_reference_temperature-" << Tref << "))"
5083             << "*(" << T << "-this->initial_geometry_reference_temperature);\n";
5084       }
5085     };
5086     if (!this->mb.requiresStressFreeExpansionTreatment(h)) {
5087       return;
5088     }
5089     if (this->mb.areThermalExpansionCoefficientsDefined()) {
5090       throw_if((this->mb.getBehaviourType() != BehaviourDescription::STANDARDSTRAINBASEDBEHAVIOUR) &&
5091                    (this->mb.getBehaviourType() != BehaviourDescription::STANDARDFINITESTRAINBEHAVIOUR),
5092                "only finite strain or small strain behaviour are supported");
5093       if (this->mb.getSymmetryType() == mfront::ORTHOTROPIC) {
5094         if ((this->mb.getOrthotropicAxesConvention() == OrthotropicAxesConvention::DEFAULT) &&
5095             (this->mb.getThermalExpansionCoefficients().size() == 3u)) {
5096           // in this case, only tridimensional case is supported
5097           for (const auto mh : this->mb.getDistinctModellingHypotheses()) {
5098             throw_if(mh != ModellingHypothesis::TRIDIMENSIONAL,
5099                      "an orthotropic axes convention must be choosen when "
5100                      "using @ComputeThermalExpansion keyword in behaviours "
5101                      "which shall be valid in other modelling hypothesis "
5102                      "than 'Tridimensional'.\n"
5103                      "Either restrict the validity of the behaviour to "
5104                      "'Tridimensional' (see @ModellingHypothesis) or "
5105                      "choose and orthotropic axes convention as on option "
5106                      "to the @OrthotropicBehaviour keyword");
5107           }
5108         }
5109       }
5110     }
5111     this->checkBehaviourFile(os);
5112     os << "void\n"
5113        << "computeStressFreeExpansion(std::pair<StressFreeExpansionType,StressFreeExpansionType>& dl01_l0)\n{\n";
5114     os << "using namespace std;\n";
5115     os << "using namespace tfel::math;\n";
5116     os << "using std::vector;\n";
5117     writeMaterialLaws(os, this->mb.getMaterialLaws());
5118     os << "auto& dl0_l0 = dl01_l0.first;\n";
5119     os << "auto& dl1_l0 = dl01_l0.second;\n";
5120     os << "dl0_l0 = StressFreeExpansionType(typename StressFreeExpansionType::value_type(0));\n";
5121     os << "dl1_l0 = StressFreeExpansionType(typename StressFreeExpansionType::value_type(0));\n";
5122     if (this->mb.hasCode(h, BehaviourData::ComputeStressFreeExpansion)) {
5123       os << this->mb.getCode(h, BehaviourData::ComputeStressFreeExpansion) << '\n';
5124     }
5125     if (this->mb.areThermalExpansionCoefficientsDefined()) {
5126       const auto& acs = this->mb.getThermalExpansionCoefficients();
5127       if (acs.size() == 1u) {
5128         const auto& a = acs.front();
5129         if (a.is<BehaviourDescription::ConstantMaterialProperty>()) {
5130           eval(os, a, "0", false);
5131         } else {
5132           this->writeThermalExpansionCoefficientsComputations(os, acs.front());
5133           this->writeThermalExpansionComputation(os, "t", "0");
5134         }
5135         os << "dl0_l0[1] += dl0_l0[0];\n"
5136            << "dl0_l0[2] += dl0_l0[0];\n";
5137         if (a.is<BehaviourDescription::ConstantMaterialProperty>()) {
5138           eval(os, a, "0", true);
5139         } else {
5140           this->writeThermalExpansionComputation(os, "t_dt", "0");
5141         }
5142         os << "dl1_l0[1] += dl1_l0[0];\n"
5143            << "dl1_l0[2] += dl1_l0[0];\n";
5144       } else if (acs.size() == 3u) {
5145         throw_if(this->mb.getSymmetryType() != mfront::ORTHOTROPIC, "invalid number of thermal expansion coefficients");
5146         for (size_t i = 0; i != 3; ++i) {
5147           if (!acs[i].is<BehaviourDescription::ConstantMaterialProperty>()) {
5148             this->writeThermalExpansionCoefficientsComputations(os, acs[i], std::to_string(i));
5149           }
5150         }
5151         for (size_t i = 0; i != 3; ++i) {
5152           const auto idx = std::to_string(i);
5153           if (acs[i].is<BehaviourDescription::ConstantMaterialProperty>()) {
5154             eval(os, acs[i], idx, false);
5155             eval(os, acs[i], idx, true);
5156           } else {
5157             this->writeThermalExpansionComputation(os, "t", idx, idx);
5158             this->writeThermalExpansionComputation(os, "t_dt", idx, idx);
5159           }
5160         }
5161       } else {
5162         throw_if(true, "unsupported behaviour symmetry");
5163       }
5164     }
5165     for (const auto& d : this->mb.getStressFreeExpansionDescriptions(h)) {
5166       if (d.is<BehaviourData::AxialGrowth>()) {
5167         throw_if((this->mb.getBehaviourType() != BehaviourDescription::STANDARDSTRAINBASEDBEHAVIOUR) &&
5168                      (this->mb.getBehaviourType() != BehaviourDescription::STANDARDFINITESTRAINBEHAVIOUR),
5169                  "only finite strain or small strain behaviour are supported");
5170         throw_if(this->mb.getSymmetryType() != mfront::ORTHOTROPIC,
5171                  "axial growth is only supported for orthotropic behaviours");
5172         const auto& s = d.get<BehaviourData::AxialGrowth>();
5173         throw_if(s.sfe.is<BehaviourData::NullExpansion>(), "null swelling is not supported here");
5174         // The z-axis is supposed to be aligned with the second
5175         // direction of orthotropy.
5176         if (s.sfe.is<BehaviourData::SFED_ESV>()) {
5177           const auto ev = s.sfe.get<BehaviourData::SFED_ESV>().vname;
5178           os << "dl0_l0[1]+=this->" << ev << ";\n"
5179              << "dl0_l0[0]+=real(1)/std::sqrt(1+this->" << ev << ")-real(1);\n"
5180              << "dl0_l0[2]+=real(1)/std::sqrt(1+this->" << ev << ")-real(1);\n"
5181              << "dl1_l0[1]+=this->" << ev << "+this->d" << ev << ";\n"
5182              << "dl1_l0[0]+=real(1)/std::sqrt(1+this->" << ev << "+this->d" << ev << ")-real(1);\n"
5183              << "dl1_l0[2]+=real(1)/std::sqrt(1+this->" << ev << "+this->d" << ev << ")-real(1);\n";
5184         } else if (s.sfe.is<std::shared_ptr<ModelDescription>>()) {
5185           const auto& md = *(s.sfe.get<std::shared_ptr<ModelDescription>>());
5186           throw_if(md.outputs.size() != 1u, "invalid number of outputs for model '" + md.className + "'");
5187           const auto vs = md.className + "_" + md.outputs[0].name;
5188           os << "dl0_l0[1]+=this->" << vs << ";\n"
5189              << "dl0_l0[0]+=real(1)/std::sqrt(1+this->" << vs << ")-real(1);\n"
5190              << "dl0_l0[2]+=real(1)/std::sqrt(1+this->" << vs << ")-real(1);\n";
5191           this->writeModelCall(os, tmpnames, h, md, vs, vs, "sfeh");
5192           os << "dl1_l0[1]+=this->" << vs << ";\n"
5193              << "dl1_l0[0]+=real(1)/std::sqrt(1+this->" << vs << ")-real(1);\n"
5194              << "dl1_l0[2]+=real(1)/std::sqrt(1+this->" << vs << ")-real(1);\n";
5195         } else {
5196           throw_if(true, "internal error, unsupported stress free expansion");
5197         }
5198       } else if (d.is<BehaviourData::Relocation>()) {
5199         throw_if((this->mb.getBehaviourType() != BehaviourDescription::STANDARDSTRAINBASEDBEHAVIOUR) &&
5200                      (this->mb.getBehaviourType() != BehaviourDescription::STANDARDFINITESTRAINBEHAVIOUR),
5201                  "only finite strain or small strain behaviour are supported");
5202         const auto& s = d.get<BehaviourData::Relocation>();
5203         throw_if(s.sfe.is<BehaviourData::NullExpansion>(), "null swelling is not supported here");
5204         if (s.sfe.is<BehaviourData::SFED_ESV>()) {
5205           const auto ev = s.sfe.get<BehaviourData::SFED_ESV>().vname;
5206           if ((h == ModellingHypothesis::AXISYMMETRICALGENERALISEDPLANESTRESS) ||
5207               (h == ModellingHypothesis::AXISYMMETRICALGENERALISEDPLANESTRAIN)) {
5208             os << "dl0_l0[0]+=this->" << ev << "/2;\n"
5209                << "dl0_l0[2]+=this->" << ev << "/2;\n"
5210                << "dl1_l0[0]+=(this->" << ev << "+this->d" << ev << ")/2;\n"
5211                << "dl1_l0[2]+=(this->" << ev << "+this->d" << ev << ")/2;\n";
5212           }
5213           if ((h == ModellingHypothesis::GENERALISEDPLANESTRAIN) || (h == ModellingHypothesis::PLANESTRAIN) ||
5214               (h == ModellingHypothesis::PLANESTRESS)) {
5215             os << "dl0_l0[0]+=this->" << ev << "/2;\n"
5216                << "dl0_l0[1]+=this->" << ev << "/2;\n"
5217                << "dl1_l0[0]+=(this->" << ev << "+this->d" << ev << ")/2;\n"
5218                << "dl1_l0[1]+=(this->" << ev << "+this->d" << ev << ")/2;\n";
5219           }
5220         } else if (s.sfe.is<std::shared_ptr<ModelDescription>>()) {
5221           const auto& md = *(s.sfe.get<std::shared_ptr<ModelDescription>>());
5222           throw_if(md.outputs.size() != 1u, "invalid number of outputs for model '" + md.className + "'");
5223           const auto vs = md.className + "_" + md.outputs[0].name;
5224           if ((h == ModellingHypothesis::AXISYMMETRICALGENERALISEDPLANESTRESS) ||
5225               (h == ModellingHypothesis::AXISYMMETRICALGENERALISEDPLANESTRAIN)) {
5226             os << "dl0_l0[0]+=(this->" << vs << ")/2;\n"
5227                << "dl0_l0[2]+=(this->" << vs << ")/2;\n";
5228           }
5229           this->writeModelCall(os, tmpnames, h, md, vs, vs, "sfeh");
5230           if ((h == ModellingHypothesis::GENERALISEDPLANESTRAIN) || (h == ModellingHypothesis::PLANESTRAIN) ||
5231               (h == ModellingHypothesis::PLANESTRESS)) {
5232             os << "dl0_l0[0]+=(this->" << vs << ")/2;\n"
5233                << "dl0_l0[1]+=(this->" << vs << ")/2;\n";
5234           }
5235         } else {
5236           throw_if(true, "internal error, unsupported stress free expansion");
5237         }
5238       } else if (d.is<BehaviourData::OrthotropicStressFreeExpansion>()) {
5239         using StressFreeExpansionHandler = BehaviourData::StressFreeExpansionHandler;
5240         const auto& s = d.get<BehaviourData::OrthotropicStressFreeExpansion>();
5241         auto write = [this, &os, &tmpnames, throw_if, h](const StressFreeExpansionHandler& sfe, const char* const c) {
5242           if (sfe.is<BehaviourData::SFED_ESV>()) {
5243             const auto& ev = sfe.get<BehaviourData::SFED_ESV>().vname;
5244             os << "dl0_l0[" << c << "]+=this->" << ev << ";\n";
5245             os << "dl1_l0[" << c << "]+=this->" << ev << "+this->d" << ev << ";\n";
5246           } else if (sfe.is<std::shared_ptr<ModelDescription>>()) {
5247             const auto& md = *(sfe.get<std::shared_ptr<ModelDescription>>());
5248             throw_if(md.outputs.size() != 1u, "invalid number of outputs for model '" + md.className + "'");
5249             const auto vs = md.className + "_" + md.outputs[0].name;
5250             os << "dl0_l0[" << c << "]+=this->" << vs << ";\n";
5251             this->writeModelCall(os, tmpnames, h, md, vs, vs, "sfeh");
5252             os << "dl1_l0[" << c << "]+=this->" << vs << ";\n";
5253           } else if (!sfe.is<BehaviourData::NullExpansion>()) {
5254             throw_if(true, "internal error, unsupported stress free expansion");
5255           }
5256         };
5257         throw_if((this->mb.getBehaviourType() != BehaviourDescription::STANDARDSTRAINBASEDBEHAVIOUR) &&
5258                      (this->mb.getBehaviourType() != BehaviourDescription::STANDARDFINITESTRAINBEHAVIOUR),
5259                  "only finite strain or small strain behaviour are supported");
5260         throw_if(this->mb.getSymmetryType() != mfront::ORTHOTROPIC,
5261                  "orthotropic stress free expansion is only supported "
5262                  "for orthotropic behaviours");
5263         throw_if(s.sfe0.is<BehaviourData::NullExpansion>() && s.sfe1.is<BehaviourData::NullExpansion>() &&
5264                      s.sfe2.is<BehaviourData::NullExpansion>(),
5265                  "null swelling is not supported here");
5266         write(s.sfe0, "0");
5267         write(s.sfe1, "1");
5268         write(s.sfe2, "2");
5269       } else if (d.is<BehaviourData::OrthotropicStressFreeExpansionII>()) {
5270         const auto& s = d.get<BehaviourData::OrthotropicStressFreeExpansionII>();
5271         const auto& ev = s.esv.vname;
5272         throw_if((this->mb.getBehaviourType() != BehaviourDescription::STANDARDSTRAINBASEDBEHAVIOUR) &&
5273                      (this->mb.getBehaviourType() != BehaviourDescription::STANDARDFINITESTRAINBEHAVIOUR),
5274                  "only finite strain or small strain behaviour are supported");
5275         throw_if(this->mb.getSymmetryType() != mfront::ORTHOTROPIC,
5276                  "orthotropic stress free expansion is only supported "
5277                  "for orthotropic behaviours");
5278         os << "dl0_l0[0]+=this->" << ev << "[0];\n"
5279            << "dl0_l0[1]+=this->" << ev << "[1];\n"
5280            << "dl0_l0[2]+=this->" << ev << "[2];\n"
5281            << "dl1_l0[0]+=this->" << ev << "[0]+this->d" << ev << "[0];\n"
5282            << "dl1_l0[1]+=this->" << ev << "[1]+this->d" << ev << "[1];\n"
5283            << "dl1_l0[2]+=this->" << ev << "[2]+this->d" << ev << "[2];\n";
5284       } else if (d.is<BehaviourData::IsotropicStressFreeExpansion>()) {
5285         throw_if((this->mb.getBehaviourType() != BehaviourDescription::STANDARDSTRAINBASEDBEHAVIOUR) &&
5286                      (this->mb.getBehaviourType() != BehaviourDescription::STANDARDFINITESTRAINBEHAVIOUR),
5287                  "only finite strain or small strain behaviour are supported");
5288         const auto& s = d.get<BehaviourData::IsotropicStressFreeExpansion>();
5289         throw_if(s.sfe.is<BehaviourData::NullExpansion>(), "null swelling is not supported here");
5290         if (s.sfe.is<BehaviourData::SFED_ESV>()) {
5291           const auto ev = s.sfe.get<BehaviourData::SFED_ESV>().vname;
5292           os << "dl0_l0[0]+=this->" << ev << ";\n"
5293              << "dl0_l0[1]+=this->" << ev << ";\n"
5294              << "dl0_l0[2]+=this->" << ev << ";\n"
5295              << "dl1_l0[0]+=this->" << ev << "+this->d" << ev << ";\n"
5296              << "dl1_l0[1]+=this->" << ev << "+this->d" << ev << ";\n"
5297              << "dl1_l0[2]+=this->" << ev << "+this->d" << ev << ";\n";
5298         } else if (s.sfe.is<std::shared_ptr<ModelDescription>>()) {
5299           const auto& md = *(s.sfe.get<std::shared_ptr<ModelDescription>>());
5300           throw_if(md.outputs.size() != 1u, "invalid number of outputs for model '" + md.className + "'");
5301           const auto vs = md.className + "_" + md.outputs[0].name;
5302           os << "dl0_l0[0]+=this->" << vs << ";\n"
5303              << "dl0_l0[1]+=this->" << vs << ";\n"
5304              << "dl0_l0[2]+=this->" << vs << ";\n";
5305           this->writeModelCall(os, tmpnames, h, md, vs, vs, "sfeh");
5306           os << "dl1_l0[0]+=this->" << vs << ";\n"
5307              << "dl1_l0[1]+=this->" << vs << ";\n"
5308              << "dl1_l0[2]+=this->" << vs << ";\n";
5309         } else {
5310           throw_if(true, "internal error, unsupported stress free expansion");
5311         }
5312       } else if (d.is<BehaviourData::VolumeSwellingStressFreeExpansion>()) {
5313         throw_if((this->mb.getBehaviourType() != BehaviourDescription::STANDARDSTRAINBASEDBEHAVIOUR) &&
5314                      (this->mb.getBehaviourType() != BehaviourDescription::STANDARDFINITESTRAINBEHAVIOUR),
5315                  "only finite strain or small strain behaviour are supported");
5316         const auto& s = d.get<BehaviourData::VolumeSwellingStressFreeExpansion>();
5317         throw_if(s.sfe.is<BehaviourData::NullExpansion>(), "null swelling is not supported here");
5318         if (s.sfe.is<BehaviourData::SFED_ESV>()) {
5319           const auto ev = s.sfe.get<BehaviourData::SFED_ESV>().vname;
5320           os << "dl0_l0[0]+=this->" << ev << "/3;\n"
5321              << "dl0_l0[1]+=this->" << ev << "/3;\n"
5322              << "dl0_l0[2]+=this->" << ev << "/3;\n"
5323              << "dl1_l0[0]+=(this->" << ev << "+this->d" << ev << ")/3;\n"
5324              << "dl1_l0[1]+=(this->" << ev << "+this->d" << ev << ")/3;\n"
5325              << "dl1_l0[2]+=(this->" << ev << "+this->d" << ev << ")/3;\n";
5326         } else if (s.sfe.is<std::shared_ptr<ModelDescription>>()) {
5327           const auto& md = *(s.sfe.get<std::shared_ptr<ModelDescription>>());
5328           throw_if(md.outputs.size() != 1u, "invalid number of outputs for model '" + md.className + "'");
5329           const auto vs = md.className + "_" + md.outputs[0].name;
5330           os << "dl0_l0[0]+=this->" << vs << "/3;\n"
5331              << "dl0_l0[1]+=this->" << vs << "/3;\n"
5332              << "dl0_l0[2]+=this->" << vs << "/3;\n";
5333           this->writeModelCall(os, tmpnames, h, md, vs, vs, "sfeh");
5334           os << "dl1_l0[0]+=this->" << vs << "/3;\n"
5335              << "dl1_l0[1]+=this->" << vs << "/3;\n"
5336              << "dl1_l0[2]+=this->" << vs << "/3;\n";
5337         } else {
5338           throw_if(true, "internal error, unsupported stress free expansion");
5339         }
5340       } else {
5341         throw_if(true,
5342                  "internal error, unsupported stress "
5343                  "free expansion description");
5344       }
5345     }
5346     if (this->mb.getSymmetryType() == mfront::ORTHOTROPIC) {
5347       if (this->mb.getOrthotropicAxesConvention() == OrthotropicAxesConvention::PIPE) {
5348         os << "tfel::material::convertStressFreeExpansionStrain<hypothesis,tfel::material::OrthotropicAxesConvention::"
5349               "PIPE>(dl0_l0);\n"
5350            << "tfel::material::convertStressFreeExpansionStrain<hypothesis,tfel::material::OrthotropicAxesConvention::"
5351               "PIPE>(dl1_l0);\n";
5352       } else if (this->mb.getOrthotropicAxesConvention() == OrthotropicAxesConvention::PLATE) {
5353         os << "tfel::material::convertStressFreeExpansionStrain<hypothesis,tfel::material::OrthotropicAxesConvention::"
5354               "PLATE>(dl0_l0);\n"
5355            << "tfel::material::convertStressFreeExpansionStrain<hypothesis,tfel::material::OrthotropicAxesConvention::"
5356               "PLATE>(dl1_l0);\n";
5357       } else {
5358         throw_if(this->mb.getOrthotropicAxesConvention() != OrthotropicAxesConvention::DEFAULT,
5359                  "internal error, unsupported orthotropic axes convention");
5360         for (const auto mh : this->mb.getDistinctModellingHypotheses()) {
5361           throw_if(mh != ModellingHypothesis::TRIDIMENSIONAL,
5362                    "an orthotropic axes convention must be choosen when "
5363                    "defining a stress free expansion in behaviours "
5364                    "which shall be valid in other modelling hypothesis "
5365                    "than 'Tridimensional'.\n"
5366                    "Either restrict the validity of the behaviour to "
5367                    "'Tridimensional' (see @ModellingHypothesis) or "
5368                    "choose and orthotropic axes convention as on option "
5369                    "to the @OrthotropicBehaviour keyword");
5370         }
5371       }
5372     }
5373     os << "}\n\n";
5374   }  // end of BehaviourDSLCommon::writeBehaviourComputeStressFreeExpansion
5375 
writeBehaviourInitializeMethod(std::ostream & os,const Hypothesis h) const5376   void BehaviourDSLCommon::writeBehaviourInitializeMethod(std::ostream& os, const Hypothesis h) const {
5377     this->checkBehaviourFile(os);
5378     os << "/*!\n"
5379        << " * \\ brief initialize the behaviour with user code\n"
5380        << " */\n"
5381        << "void initialize(){\n"
5382        << "using namespace std;\n"
5383        << "using namespace tfel::math;\n"
5384        << "using std::vector;\n";
5385     writeMaterialLaws(os, this->mb.getMaterialLaws());
5386     if (this->mb.hasCode(h, BehaviourData::BeforeInitializeLocalVariables)) {
5387       if (this->mb.getAttribute(BehaviourData::profiling, false)) {
5388         writeStandardPerformanceProfilingBegin(os, this->mb.getClassName(),
5389                                                BehaviourData::BeforeInitializeLocalVariables, "binit");
5390       }
5391       os << this->mb.getCodeBlock(h, BehaviourData::BeforeInitializeLocalVariables).code << '\n';
5392       if (this->mb.getAttribute(BehaviourData::profiling, false)) {
5393         writeStandardPerformanceProfilingEnd(os);
5394       }
5395     }
5396     if (this->mb.hasCode(h, BehaviourData::InitializeLocalVariables)) {
5397       if (this->mb.getAttribute(BehaviourData::profiling, false)) {
5398         writeStandardPerformanceProfilingBegin(os, this->mb.getClassName(), BehaviourData::InitializeLocalVariables,
5399                                                "init");
5400       }
5401       os << this->mb.getCodeBlock(h, BehaviourData::InitializeLocalVariables).code << '\n';
5402       if (this->mb.getAttribute(BehaviourData::profiling, false)) {
5403         writeStandardPerformanceProfilingEnd(os);
5404       }
5405     }
5406     if (this->mb.hasCode(h, BehaviourData::AfterInitializeLocalVariables)) {
5407       if (this->mb.getAttribute(BehaviourData::profiling, false)) {
5408         writeStandardPerformanceProfilingBegin(os, this->mb.getClassName(),
5409                                                BehaviourData::AfterInitializeLocalVariables, "ainit");
5410       }
5411       os << this->mb.getCodeBlock(h, BehaviourData::AfterInitializeLocalVariables).code << '\n';
5412       if (this->mb.getAttribute(BehaviourData::profiling, false)) {
5413         writeStandardPerformanceProfilingEnd(os);
5414       }
5415     }
5416     this->writeBehaviourParserSpecificInitializeMethodPart(os, h);
5417     os << "}\n\n";
5418   }  // end of void BehaviourDSLCommon::writeBehaviourInitializeMethod
5419 
writeBehaviourLocalVariablesInitialisation(std::ostream & os,const Hypothesis h) const5420   void BehaviourDSLCommon::writeBehaviourLocalVariablesInitialisation(std::ostream& os, const Hypothesis h) const {
5421     const auto& md = this->mb.getBehaviourData(h);
5422     this->checkBehaviourFile(os);
5423     for (const auto& v : md.getLocalVariables()) {
5424       if (this->mb.useDynamicallyAllocatedVector(v.arraySize)) {
5425         os << "this->" << v.name << ".resize(" << v.arraySize << ");\n";
5426       }
5427     }
5428   }
5429 
writeBehaviourParameterInitialisation(std::ostream & os,const Hypothesis h) const5430   void BehaviourDSLCommon::writeBehaviourParameterInitialisation(
5431       std::ostream& os, const Hypothesis h) const {
5432     constexpr const auto uh = ModellingHypothesis::UNDEFINEDHYPOTHESIS;
5433     this->checkBehaviourFile(os);
5434     const auto& d = this->mb.getBehaviourData(h);
5435     for (const auto& p : d.getParameters()) {
5436       if ((h == uh) || (this->mb.hasParameter(uh, p.name))) {
5437         if (p.arraySize == 1u) {
5438           os << "this->" << p.name << " = " << this->mb.getClassName()
5439              << "ParametersInitializer::get()." << p.name << ";\n";
5440         } else {
5441           os << "tfel::fsalgo::copy<" << p.arraySize << ">::exe("
5442              << this->mb.getClassName() << "ParametersInitializer::get()."
5443              << p.name << ".begin(),this->" << p.name << ".begin());\n";
5444         }
5445       } else {
5446         if (p.arraySize == 1u) {
5447           os << "this->" << p.name << " = " << this->mb.getClassName()
5448              << ModellingHypothesis::toString(h)
5449              << "ParametersInitializer::get()." << p.name << ";\n";
5450         } else {
5451           os << "tfel::fsalgo::copy<" << p.arraySize << ">::exe("
5452              << this->mb.getClassName() << ModellingHypothesis::toString(h)
5453              << "ParametersInitializer::get()." << p.name << ".begin(),this->"
5454              << p.name << ".begin());\n";
5455         }
5456       }
5457     }
5458   }  // end of BehaviourDSLCommon::writeBehaviourParameterInitialisation
5459 
writeBehaviourDataMainVariablesSetters(std::ostream & os) const5460   void BehaviourDSLCommon::writeBehaviourDataMainVariablesSetters(std::ostream& os) const {
5461     this->checkBehaviourDataFile(os);
5462     for (const auto& i : this->interfaces) {
5463       i.second->writeBehaviourDataMainVariablesSetters(os, this->mb);
5464       os << '\n';
5465     }
5466   }  // end of BehaviourDSLCommon::writeBehaviourDataMainVariablesSetters
5467 
writeIntegrationDataMainVariablesSetters(std::ostream & os) const5468   void BehaviourDSLCommon::writeIntegrationDataMainVariablesSetters(std::ostream& os) const {
5469     this->checkIntegrationDataFile(os);
5470     for (const auto& i : this->interfaces) {
5471       i.second->writeIntegrationDataMainVariablesSetters(os, this->mb);
5472       os << '\n';
5473     }
5474   }  // end of BehaviourDSLCommon::writeIntegrationDataMainVariablesSetters
5475 
writeBehaviourGetModellingHypothesis(std::ostream & os) const5476   void BehaviourDSLCommon::writeBehaviourGetModellingHypothesis(std::ostream& os) const {
5477     this->checkBehaviourFile(os);
5478     os << "/*!\n"
5479        << "* \\return the modelling hypothesis\n"
5480        << "*/\n"
5481        << "constexpr ModellingHypothesis::Hypothesis\ngetModellingHypothesis() const{\n"
5482        << "return hypothesis;\n"
5483        << "} // end of getModellingHypothesis\n\n";
5484   }  // end of BehaviourDSLCommon::writeBehaviourGetModellingHypothesis();
5485 
writeBehaviourLocalVariables(std::ostream & os,const Hypothesis h) const5486   void BehaviourDSLCommon::writeBehaviourLocalVariables(std::ostream& os, const Hypothesis h) const {
5487     this->checkBehaviourFile(os);
5488     const auto& md = this->mb.getBehaviourData(h);
5489     this->writeVariablesDeclarations(os, md.getLocalVariables(), "", "", this->fd.fileName, false);
5490     os << '\n';
5491   }
5492 
writeBehaviourIntegrationVariables(std::ostream & os,const Hypothesis h) const5493   void BehaviourDSLCommon::writeBehaviourIntegrationVariables(std::ostream& os, const Hypothesis h) const {
5494     this->checkBehaviourFile(os);
5495     const auto& md = this->mb.getBehaviourData(h);
5496     for (const auto& v : md.getIntegrationVariables()) {
5497       if (!md.isStateVariableName(v.name)) {
5498         if (md.isMemberUsedInCodeBlocks(v.name)) {
5499           this->writeVariableDeclaration(os, v, "", "", this->fd.fileName, false);
5500         }
5501       }
5502     }
5503     os << '\n';
5504   }  // end od BehaviourDSLCommon::writeBehaviourIntegrationVariables
5505 
writeBehaviourParameters(std::ostream & os,const Hypothesis h) const5506   void BehaviourDSLCommon::writeBehaviourParameters(std::ostream& os, const Hypothesis h) const {
5507     this->checkBehaviourFile(os);
5508     const auto& d = this->mb.getBehaviourData(h);
5509     for (const auto& v : d.getParameters()) {
5510       if (!getDebugMode()) {
5511         if (v.lineNumber != 0u) {
5512           os << "#line " << v.lineNumber << " \"" << this->fd.fileName << "\"\n";
5513         }
5514       }
5515       if (v.arraySize == 1) {
5516         os << v.type << " " << v.name << ";\n";
5517       } else {
5518         os << "tfel::math::tvector<" << v.arraySize << "," << v.type << "> " << v.name << ";\n";
5519       }
5520     }
5521     os << '\n';
5522   }
5523 
writeBehaviourPolicyVariable(std::ostream & os) const5524   void BehaviourDSLCommon::writeBehaviourPolicyVariable(std::ostream& os) const {
5525     this->checkBehaviourFile(os);
5526     os << "//! policy for treating out of bounds conditions\n"
5527        << "OutOfBoundsPolicy policy = None;\n";
5528   }  // end of BehaviourDSLCommon::writeBehaviourPolicyVariable
5529 
writeBehaviourStaticVariables(std::ostream & os,const Hypothesis h) const5530   void BehaviourDSLCommon::writeBehaviourStaticVariables(std::ostream& os, const Hypothesis h) const {
5531     const auto& md = this->mb.getBehaviourData(h);
5532     this->checkBehaviourFile(os);
5533     for (const auto& v : md.getStaticVariables()) {
5534       if (!getDebugMode()) {
5535         if (v.lineNumber != 0u) {
5536           os << "#line " << v.lineNumber << " \"" << this->fd.fileName << "\"\n";
5537         }
5538       }
5539       if (v.type == "int") {
5540         os << "static constexpr " << v.type << " " << v.name << " = " << v.value << ";\n";
5541       } else {
5542         os << "static const " << v.type << " " << v.name << ";\n";
5543       }
5544     }
5545     os << '\n';
5546   }
5547 
writeBehaviourIntegrationVariablesIncrements(std::ostream & os,const Hypothesis h) const5548   void BehaviourDSLCommon::writeBehaviourIntegrationVariablesIncrements(std::ostream& os, const Hypothesis h) const {
5549     const auto& md = this->mb.getBehaviourData(h);
5550     this->checkBehaviourFile(os);
5551     this->writeVariablesDeclarations(os, md.getIntegrationVariables(), "d", "", this->fd.fileName,
5552                                      this->useStateVarTimeDerivative);
5553     os << '\n';
5554   }
5555 
writeBehaviourOutputOperator(std::ostream & os,const Hypothesis h) const5556   void BehaviourDSLCommon::writeBehaviourOutputOperator(std::ostream& os, const Hypothesis h) const {
5557     const auto& md = this->mb.getBehaviourData(h);
5558     this->checkBehaviourFile(os);
5559     if (h == ModellingHypothesis::UNDEFINEDHYPOTHESIS) {
5560       if (this->mb.useQt()) {
5561         os << "template<ModellingHypothesis::Hypothesis hypothesis,typename Type,bool use_qt>\n"
5562            << "std::ostream&\n"
5563            << "operator <<(std::ostream& os,"
5564            << "const " << this->mb.getClassName() << "<hypothesis,Type,use_qt>& b)\n";
5565       } else {
5566         os << "template<ModellingHypothesis::Hypothesis hypothesis,typename Type>\n"
5567            << "std::ostream&\n"
5568            << "operator <<(std::ostream& os,"
5569            << "const " << this->mb.getClassName() << "<hypothesis,Type,false>& b)\n";
5570       }
5571     } else {
5572       if (this->mb.useQt()) {
5573         os << "template<typename Type,bool use_qt>\n"
5574            << "std::ostream&\n"
5575            << "operator <<(std::ostream& os,"
5576            << "const " << this->mb.getClassName()
5577            << "<ModellingHypothesis::" << ModellingHypothesis::toUpperCaseString(h) << ",Type,use_qt>& b)\n";
5578       } else {
5579         os << "template<typename Type>\n"
5580            << "std::ostream&\n"
5581            << "operator <<(std::ostream& os,"
5582            << "const " << this->mb.getClassName()
5583            << "<ModellingHypothesis::" << ModellingHypothesis::toUpperCaseString(h) << ",Type,false>& b)\n";
5584       }
5585     }
5586     os << "{\n";
5587     for (const auto& v : this->mb.getMainVariables()) {
5588       if (Gradient::isIncrementKnown(v.first)) {
5589         os << "os << \"" << displayName(v.first) << " : \" << b."
5590            << v.first.name << " << '\\n';\n";
5591         if (getUnicodeOutputOption()) {
5592           os << "os << \"\u0394" << displayName(v.first) << " : \" << b.d"
5593              << v.first.name << " << '\\n';\n";
5594         } else {
5595           os << "os << \"d" << displayName(v.first) << " : \" << b.d"
5596              << v.first.name << " << '\\n';\n";
5597         }
5598       } else {
5599         if (getUnicodeOutputOption()) {
5600           os << "os << \"" << displayName(v.first) << "\u2080 : \" << b."
5601              << v.first.name << "0 << '\\n';\n"
5602              << "os << \"" << displayName(v.first) << "\u2081 : \" << b."
5603              << v.first.name << "1 << '\\n';\n";
5604         } else {
5605           os << "os << \"" << displayName(v.first) << "0 : \" << b."
5606              << v.first.name << "0 << '\\n';\n"
5607              << "os << \"" << displayName(v.first) << "1 : \" << b."
5608              << v.first.name << "1 << '\\n';\n";
5609         }
5610       }
5611       os << "os << \"" << displayName(v.second) << " : \" << b."
5612          << v.second.name << " << '\\n';\n";
5613     }
5614     if (getUnicodeOutputOption()) {
5615       os << "os << \"\u0394t : \" << b.dt << '\\n';\n";
5616     } else {
5617       os << "os << \"dt : \" << b.dt << '\\n';\n";
5618     }
5619     for (const auto& v : md.getMaterialProperties()) {
5620       os << "os << \"" << displayName(v) << " : \" << b." << v.name
5621          << " << '\\n';\n";
5622       }
5623       for (const auto& v : md.getStateVariables()) {
5624         os << "os << \"" << displayName(v) << " : \" << b." << v.name
5625            << " << '\\n';\n";
5626         if (getUnicodeOutputOption()) {
5627           os << "os << \"\u0394" << displayName(v) << " : \" << b.d" << v.name
5628              << " << '\\n';\n";
5629         } else {
5630           os << "os << \"d" << displayName(v) << " : \" << b.d" << v.name
5631              << " << '\\n';\n";
5632         }
5633       }
5634       for (const auto& v : md.getAuxiliaryStateVariables()) {
5635         os << "os << \"" << displayName(v) << " : \" << b." << v.name
5636            << " << '\\n';\n";
5637       }
5638       for (const auto& v : md.getExternalStateVariables()) {
5639         os << "os << \"" << displayName(v) << " : \" << b." << v.name
5640            << " << '\\n';\n";
5641         if (getUnicodeOutputOption()) {
5642           os << "os << \"\u0394" << displayName(v) << " : \" << b.d" << v.name
5643              << " << '\\n';\n";
5644         } else {
5645           os << "os << \"d" << displayName(v) << " : \" << b.d" << v.name
5646              << " << '\\n';\n";
5647         }
5648       }
5649       for (const auto& v : md.getLocalVariables()) {
5650 #pragma message("BehaviourDSLCommon: handle LocalDataStructure properly")
5651       if ((v.type.size() >= 7) && (v.type.substr(0, 7) != "struct{")) {
5652         os << "os << \"" << displayName(v) << " : \" << b." << v.name
5653            << " << '\\n';\n";
5654       }
5655     }
5656     for (const auto& v : md.getParameters()) {
5657       os << "os << \"" << displayName(v) << " : \" << b." << v.name
5658          << " << '\\n';\n";
5659     }
5660     os << "return os;\n"
5661        << "}\n\n";
5662   }
5663 
writeBehaviourDestructor(std::ostream & os) const5664   void BehaviourDSLCommon::writeBehaviourDestructor(std::ostream& os) const {
5665     this->checkBehaviourFile(os);
5666     os << "//!\n"
5667        << "~" << this->mb.getClassName() << "()\n"
5668        << " override = default;\n\n";
5669   }
5670 
writeBehaviourUpdateExternalStateVariables(std::ostream & os,const Hypothesis h) const5671   void BehaviourDSLCommon::writeBehaviourUpdateExternalStateVariables(std::ostream& os, const Hypothesis h) const {
5672     const auto& md = this->mb.getBehaviourData(h);
5673     this->checkBehaviourFile(os);
5674     os << "void updateExternalStateVariables(){\n";
5675     for (const auto& v : this->mb.getMainVariables()) {
5676       if (Gradient::isIncrementKnown(v.first)) {
5677         os << "this->" << v.first.name << "  += this->d" << v.first.name << ";\n";
5678       } else {
5679         os << "this->" << v.first.name << "0  = this->" << v.first.name << "1;\n";
5680       }
5681     }
5682     for (const auto& v : md.getExternalStateVariables()) {
5683       os << "this->" << v.name << " += this->d" << v.name << ";\n";
5684     }
5685     os << "}\n\n";
5686   }
5687 
writeBehaviourIncludes(std::ostream & os) const5688   void BehaviourDSLCommon::writeBehaviourIncludes(std::ostream& os) const {
5689     this->checkBehaviourFile(os);
5690     os << "#include<string>\n"
5691        << "#include<iostream>\n"
5692        << "#include<limits>\n"
5693        << "#include<stdexcept>\n"
5694        << "#include<algorithm>\n\n"
5695        << "#include\"TFEL/Raise.hxx\"\n"
5696        << "#include\"TFEL/PhysicalConstants.hxx\"\n"
5697        << "#include\"TFEL/Config/TFELConfig.hxx\"\n"
5698        << "#include\"TFEL/Config/TFELTypes.hxx\"\n"
5699        << "#include\"TFEL/Metaprogramming/StaticAssert.hxx\"\n"
5700        << "#include\"TFEL/TypeTraits/IsFundamentalNumericType.hxx\"\n"
5701        << "#include\"TFEL/TypeTraits/IsReal.hxx\"\n"
5702        << "#include\"TFEL/Math/General/IEEE754.hxx\"\n";
5703     if(!this->mb.hasTrivialTangentOperatorStructure()){
5704       os << "#include\"TFEL/Math/Vector/TVectorView.hxx\"\n"
5705 	 << "#include\"TFEL/Math/Matrix/TMatrixView.hxx\"\n";
5706     }
5707     os << "#include\"TFEL/Material/MaterialException.hxx\"\n"
5708        << "#include\"TFEL/Material/MechanicalBehaviour.hxx\"\n"
5709        << "#include\"TFEL/Material/MechanicalBehaviourTraits.hxx\"\n"
5710        << "#include\"TFEL/Material/OutOfBoundsPolicy.hxx\"\n"
5711        << "#include\"TFEL/Material/BoundsCheck.hxx\"\n"
5712        << "#include\"TFEL/Material/IsotropicPlasticity.hxx\"\n"
5713        << "#include\"TFEL/Material/Lame.hxx\"\n"
5714        << "#include\"TFEL/Material/Hosford1972YieldCriterion.hxx\"\n";
5715     if (this->mb.getSymmetryType() == ORTHOTROPIC) {
5716       os << "#include\"TFEL/Material/OrthotropicPlasticity.hxx\"\n"
5717          << "#include\"TFEL/Material/OrthotropicStressLinearTransformation.hxx\"\n"
5718          << "#include\"TFEL/Material/Hill.hxx\"\n"
5719          << "#include\"TFEL/Material/Barlat2004YieldCriterion.hxx\"\n"
5720          << "#include\"TFEL/Material/OrthotropicAxesConvention.hxx\"\n";
5721     }
5722     if (this->mb.getAttribute(BehaviourDescription::computesStiffnessTensor, false)) {
5723       os << "#include\"TFEL/Material/StiffnessTensor.hxx\"\n";
5724     }
5725     if ((this->mb.isStrainMeasureDefined()) &&
5726 	(this->mb.getStrainMeasure() == BehaviourDescription::HENCKY)) {
5727       os << "#include\"TFEL/Material/LogarithmicStrainComputeAxialStrainIncrementElasticPrediction.hxx\"\n";
5728     }
5729     if (this->mb.getAttribute<bool>(BehaviourData::profiling, false)) {
5730       os << "#include\"MFront/BehaviourProfiler.hxx\"\n";
5731     }
5732     os << "#include\"" << this->getBehaviourDataFileName() << "\"\n"
5733        << "#include\"" << this->getIntegrationDataFileName() << "\"\n";
5734     os << '\n';
5735   }
5736 
writeBehaviourAdditionalMembers(std::ostream & os,const Hypothesis h) const5737   void BehaviourDSLCommon::writeBehaviourAdditionalMembers(std::ostream& os, const Hypothesis h) const {
5738     this->checkBehaviourFile(os);
5739     const auto& m = this->mb.getMembers(h);
5740     if (!m.empty()) {
5741       os << m << "\n\n";
5742     }
5743   }
5744 
writeBehaviourPrivate(std::ostream & os,const Hypothesis h) const5745   void BehaviourDSLCommon::writeBehaviourPrivate(std::ostream& os, const Hypothesis h) const {
5746     this->checkBehaviourFile(os);
5747     const auto& c = this->mb.getPrivateCode(h);
5748     if (!c.empty()) {
5749       os << c << "\n\n";
5750     }
5751   }  // end of void BehaviourDSLCommon::writeBehaviourPrivate
5752 
writeBehaviourStandardTFELTypedefs(std::ostream & os) const5753   void BehaviourDSLCommon::writeBehaviourStandardTFELTypedefs(std::ostream& os) const {
5754     using namespace tfel::material;
5755     this->checkBehaviourFile(os);
5756     const auto btype = this->mb.getBehaviourTypeFlag();
5757     os << "static " << constexpr_c << " unsigned short TVectorSize = N;\n"
5758        << "typedef tfel::math::StensorDimeToSize<N> StensorDimeToSize;\n"
5759        << "static " << constexpr_c << " unsigned short StensorSize = "
5760        << "StensorDimeToSize::value;\n"
5761        << "typedef tfel::math::TensorDimeToSize<N> TensorDimeToSize;\n"
5762        << "static " << constexpr_c << " unsigned short TensorSize = "
5763        << "TensorDimeToSize::value;\n\n";
5764     this->writeStandardTFELTypedefs(os);
5765     os << '\n' << "public :\n\n";
5766     const auto qt = this->mb.useQt() ? "use_qt" : "false";
5767     os << "typedef " << this->mb.getClassName() << "BehaviourData<hypothesis,Type," << qt << "> BehaviourData;\n"
5768        << "typedef " << this->mb.getClassName() << "IntegrationData<hypothesis,Type," << qt << "> IntegrationData;\n"
5769        << "typedef typename MechanicalBehaviour<" << btype << ",hypothesis,Type," << qt << ">::SMFlag SMFlag;\n"
5770        << "typedef typename MechanicalBehaviour<" << btype << ",hypothesis,Type," << qt << ">::SMType SMType;\n"
5771        << "using MechanicalBehaviour<" << btype << ",hypothesis,Type," << qt << ">::ELASTIC;\n"
5772        << "using MechanicalBehaviour<" << btype << ",hypothesis,Type," << qt << ">::SECANTOPERATOR;\n"
5773        << "using MechanicalBehaviour<" << btype << ",hypothesis,Type," << qt << ">::TANGENTOPERATOR;\n"
5774        << "using MechanicalBehaviour<" << btype << ",hypothesis,Type," << qt << ">::CONSISTENTTANGENTOPERATOR;\n"
5775        << "using MechanicalBehaviour<" << btype << ",hypothesis,Type," << qt << ">::NOSTIFFNESSREQUESTED;\n";
5776     if ((this->mb.getBehaviourType() == BehaviourDescription::STANDARDSTRAINBASEDBEHAVIOUR) ||
5777         (this->mb.getBehaviourType() == BehaviourDescription::COHESIVEZONEMODEL)) {
5778       os << "using MechanicalBehaviour<" << btype << ",hypothesis,Type," << qt << ">::STANDARDTANGENTOPERATOR;\n";
5779     } else if (this->mb.getBehaviourType() == BehaviourDescription::STANDARDFINITESTRAINBEHAVIOUR) {
5780       for (const auto& toflag : getFiniteStrainBehaviourTangentOperatorFlags()) {
5781         os << "using MechanicalBehaviour<" << btype << ",hypothesis,Type," << qt
5782            << ">::" << convertFiniteStrainBehaviourTangentOperatorFlagToString(toflag) << ";\n";
5783       }
5784     }
5785     os << "using IntegrationResult = typename MechanicalBehaviour<" << btype << ",hypothesis,Type," << qt
5786        << ">::IntegrationResult;\n\n"
5787        << "using MechanicalBehaviour<" << btype << ",hypothesis,Type," << qt << ">::SUCCESS;\n"
5788        << "using MechanicalBehaviour<" << btype << ",hypothesis,Type," << qt << ">::FAILURE;\n"
5789        << "using MechanicalBehaviour<" << btype << ",hypothesis,Type," << qt << ">::UNRELIABLE_RESULTS;\n\n";
5790     if ((this->mb.getBehaviourType() == BehaviourDescription::STANDARDSTRAINBASEDBEHAVIOUR) ||
5791         (this->mb.getBehaviourType() == BehaviourDescription::STANDARDFINITESTRAINBEHAVIOUR)) {
5792       os << "using StressFreeExpansionType = " << this->mb.getStressFreeExpansionType() << ";\n\n";
5793     }
5794   }  // end of BehaviourDSLCommon::writeBehaviourStandardTFELTypedefs
5795 
writeBehaviourTraits(std::ostream & os) const5796   void BehaviourDSLCommon::writeBehaviourTraits(std::ostream& os) const {
5797     constexpr const auto uh = ModellingHypothesis::UNDEFINEDHYPOTHESIS;
5798     this->checkBehaviourFile(os);
5799     const auto& ah = ModellingHypothesis::getModellingHypotheses();
5800     // writing partial specialisations
5801     if (this->mb.getModellingHypotheses().size() >= 4u) {
5802       // on définit toutes les hypothèses par défaut
5803       this->writeBehaviourTraitsSpecialisation(os, uh, true);
5804       // unsupported hypothesis
5805       for (const auto h : ah) {
5806         if (this->mb.isModellingHypothesisSupported(h)) {
5807           if (this->mb.hasSpecialisedMechanicalData(h)) {
5808             this->writeBehaviourTraitsSpecialisation(os, h, true);
5809           }
5810         } else {
5811           this->writeBehaviourTraitsSpecialisation(os, h, false);
5812         }
5813       }
5814     } else {
5815       // on exclut toutes les hypothèses par défaut
5816       this->writeBehaviourTraitsSpecialisation(os, uh, false);
5817       // unsupported hypothesis
5818       for (const auto h : this->mb.getModellingHypotheses()) {
5819         this->writeBehaviourTraitsSpecialisation(os, h, true);
5820       }
5821     }
5822   }
5823 
writeBehaviourTraitsSpecialisation(std::ostream & os,const Hypothesis h,const bool b) const5824   void BehaviourDSLCommon::writeBehaviourTraitsSpecialisation(std::ostream& os,
5825                                                               const Hypothesis h,
5826                                                               const bool b) const {
5827     SupportedTypes::TypeSize coefSize;
5828     SupportedTypes::TypeSize stateVarsSize;
5829     SupportedTypes::TypeSize externalStateVarsSize;
5830     SupportedTypes::TypeSize externalStateVarsSize2;
5831     if (b) {
5832       const auto& d = this->mb.getBehaviourData(h);
5833       for (const auto& m : d.getMaterialProperties()) {
5834         coefSize += this->getTypeSize(m.type, m.arraySize);
5835       }
5836       for (const auto& v : d.getPersistentVariables()) {
5837         stateVarsSize += this->getTypeSize(v.type, v.arraySize);
5838       }
5839       for (const auto& v : d.getExternalStateVariables()) {
5840         externalStateVarsSize += this->getTypeSize(v.type, v.arraySize);
5841       }
5842       externalStateVarsSize2 = externalStateVarsSize;
5843       externalStateVarsSize2 -= SupportedTypes::TypeSize(1, 0, 0, 0);
5844     }
5845     os << "/*!\n"
5846        << "* Partial specialisation for " << this->mb.getClassName() << ".\n"
5847        << "*/\n";
5848     if (h == ModellingHypothesis::UNDEFINEDHYPOTHESIS) {
5849       if (this->mb.useQt()) {
5850         os << "template<ModellingHypothesis::Hypothesis hypothesis,typename Type,bool use_qt>\n"
5851            << "class MechanicalBehaviourTraits<" << this->mb.getClassName() << "<hypothesis,Type,use_qt> >\n";
5852       } else {
5853         os << "template<ModellingHypothesis::Hypothesis hypothesis,typename Type>\n"
5854            << "class MechanicalBehaviourTraits<" << this->mb.getClassName() << "<hypothesis,Type,false> >\n";
5855       }
5856     } else {
5857       if (this->mb.useQt()) {
5858         os << "template<typename Type,bool use_qt>\n"
5859            << "class MechanicalBehaviourTraits<" << this->mb.getClassName()
5860            << "<ModellingHypothesis::" << ModellingHypothesis::toUpperCaseString(h) << ",Type,use_qt> >\n";
5861       } else {
5862         os << "template<typename Type>\n"
5863            << "class MechanicalBehaviourTraits<" << this->mb.getClassName()
5864            << "<ModellingHypothesis::" << ModellingHypothesis::toUpperCaseString(h) << ",Type,false> >\n";
5865       }
5866     }
5867     os << "{\n";
5868     if (b) {
5869       if (h == ModellingHypothesis::UNDEFINEDHYPOTHESIS) {
5870         os << "static " << constexpr_c << " unsigned short N = "
5871            << "ModellingHypothesisToSpaceDimension<hypothesis>::value;\n";
5872       } else {
5873         os << "static " << constexpr_c << " unsigned short N = ModellingHypothesisToSpaceDimension<"
5874            << "ModellingHypothesis::" << ModellingHypothesis::toUpperCaseString(h) << ">::value;\n";
5875       }
5876       os << "static " << constexpr_c << " unsigned short TVectorSize = N;\n"
5877          << "typedef tfel::math::StensorDimeToSize<N> StensorDimeToSize;\n"
5878          << "static " << constexpr_c << " unsigned short StensorSize = "
5879          << "StensorDimeToSize::value;\n"
5880          << "typedef tfel::math::TensorDimeToSize<N> TensorDimeToSize;\n"
5881          << "static " << constexpr_c << " unsigned short TensorSize = "
5882          << "TensorDimeToSize::value;\n";
5883     }
5884     os << "public:\n";
5885     if (b) {
5886       os << "static " << constexpr_c << " bool is_defined = true;\n";
5887     } else {
5888       os << "static " << constexpr_c << " bool is_defined = false;\n";
5889     }
5890     if (this->mb.useQt()) {
5891       os << "static " << constexpr_c << " bool use_quantities = use_qt;\n";
5892     } else {
5893       os << "static " << constexpr_c << " bool use_quantities = false;\n";
5894     }
5895     if (this->mb.getSymmetryType() == mfront::ORTHOTROPIC) {
5896       os << "//! orthotropic axes convention\n";
5897       if (this->mb.getOrthotropicAxesConvention() == OrthotropicAxesConvention::DEFAULT) {
5898         os << "static " << constexpr_c << " OrthotropicAxesConvention oac = OrthotropicAxesConvention::DEFAULT;\n";
5899       } else if (this->mb.getOrthotropicAxesConvention() == OrthotropicAxesConvention::PIPE) {
5900         os << "static " << constexpr_c << " OrthotropicAxesConvention oac = OrthotropicAxesConvention::PIPE;\n";
5901       } else if (this->mb.getOrthotropicAxesConvention() == OrthotropicAxesConvention::PLATE) {
5902         os << "static " << constexpr_c << " OrthotropicAxesConvention oac = OrthotropicAxesConvention::PLATE;\n";
5903       } else {
5904         this->throwRuntimeError("BehaviourDSLCommon::writeBehaviourTraitsSpecialisation",
5905                                 "internal error : unsupported orthotropic axes convention");
5906       }
5907     }
5908     if ((b) && (this->mb.requiresStressFreeExpansionTreatment(h))) {
5909       os << "static " << constexpr_c << " bool hasStressFreeExpansion = true;\n";
5910     } else {
5911       os << "static " << constexpr_c << " bool hasStressFreeExpansion = false;\n";
5912     }
5913     if (this->mb.areThermalExpansionCoefficientsDefined()) {
5914       os << "static " << constexpr_c << " bool handlesThermalExpansion = true;\n";
5915     } else {
5916       os << "static " << constexpr_c << " bool handlesThermalExpansion = false;\n";
5917     }
5918     if (b) {
5919       os << "static " << constexpr_c << " unsigned short dimension = N;\n";
5920     } else {
5921       os << "static " << constexpr_c << " unsigned short dimension = 0u;\n";
5922     }
5923     os << "typedef Type NumType;\n"
5924        << "static " << constexpr_c << " unsigned short material_properties_nb = " << coefSize << ";\n"
5925        << "static " << constexpr_c << " unsigned short internal_variables_nb  = " << stateVarsSize << ";\n"
5926        << "static " << constexpr_c << " unsigned short external_variables_nb  = " << externalStateVarsSize << ";\n"
5927        << "static " << constexpr_c << " unsigned short external_variables_nb2 = " << externalStateVarsSize2 << ";\n"
5928        << "static " << constexpr_c << " bool hasConsistentTangentOperator = ";
5929     if (b) {
5930       if (this->mb.getAttribute<bool>(h, BehaviourData::hasConsistentTangentOperator, false)) {
5931         os << "true;\n";
5932       } else {
5933         os << "false;\n";
5934       }
5935     } else {
5936       os << "false;\n";
5937     }
5938     os << "static " << constexpr_c << " bool isConsistentTangentOperatorSymmetric = ";
5939     if (b) {
5940       if (this->mb.getAttribute<bool>(h, BehaviourData::isConsistentTangentOperatorSymmetric, false)) {
5941         os << "true;\n";
5942       } else {
5943         os << "false;\n";
5944       }
5945     } else {
5946       os << "false;\n";
5947     }
5948     os << "static " << constexpr_c << " bool hasPredictionOperator = ";
5949     if (b) {
5950       if (this->mb.getAttribute<bool>(h, BehaviourData::hasPredictionOperator, false)) {
5951         os << "true;\n";
5952       } else {
5953         os << "false;\n";
5954       }
5955     } else {
5956       os << "false;\n";
5957     }
5958     os << "static " << constexpr_c << " bool hasAPrioriTimeStepScalingFactor = ";
5959     if (b) {
5960       if (this->mb.getAttribute<bool>(h, BehaviourData::hasAPrioriTimeStepScalingFactor, false)) {
5961         os << "true;\n";
5962       } else {
5963         os << "false;\n";
5964       }
5965     } else {
5966       os << "false;\n";
5967     }
5968     // internal enery
5969     os << "static " << constexpr_c << " bool hasComputeInternalEnergy = ";
5970     if (b) {
5971       if (this->mb.hasCode(h, BehaviourData::ComputeInternalEnergy)) {
5972         os << "true;\n";
5973       } else {
5974         os << "false;\n";
5975       }
5976     } else {
5977       os << "false;\n";
5978     }
5979     // dissipated energy
5980     os << "static " << constexpr_c << " bool hasComputeDissipatedEnergy = ";
5981     if (b) {
5982       if (this->mb.hasCode(h, BehaviourData::ComputeDissipatedEnergy)) {
5983         os << "true;\n";
5984       } else {
5985         os << "false;\n";
5986       }
5987     } else {
5988       os << "false;\n";
5989     }
5990     // name of the class
5991     os << "/*!\n"
5992        << "* \\return the name of the class.\n"
5993        << "*/\n"
5994        << "static const char* getName(){\n"
5995        << "return \"" << this->mb.getClassName() << "\";\n"
5996        << "}\n\n"
5997        << "};\n\n";
5998   }
5999 
writeBehaviourParserSpecificInheritanceRelationship(std::ostream & os) const6000   void BehaviourDSLCommon::writeBehaviourParserSpecificInheritanceRelationship(std::ostream& os) const { os << '\n'; }
6001 
writeBehaviourParserSpecificTypedefs(std::ostream &) const6002   void BehaviourDSLCommon::writeBehaviourParserSpecificTypedefs(std::ostream&) const {
6003     // Empty member meant to be overriden in Child if necessary
6004   }
6005 
writeBehaviourParserSpecificMembers(std::ostream &,const Hypothesis) const6006   void BehaviourDSLCommon::writeBehaviourParserSpecificMembers(std::ostream&, const Hypothesis) const {
6007     // Empty member meant to be overriden in Child if necessary
6008   }
6009 
writeBehaviourParserSpecificIncludes(std::ostream &) const6010   void BehaviourDSLCommon::writeBehaviourParserSpecificIncludes(std::ostream&) const {
6011     // Empty member meant to be overriden in Child if necessary
6012   }
6013 
writeBehaviourParametersInitializers(std::ostream & os) const6014   void BehaviourDSLCommon::writeBehaviourParametersInitializers(std::ostream& os) const {
6015     if (!this->mb.hasParameters()) {
6016       return;
6017     }
6018     auto mh = this->mb.getDistinctModellingHypotheses();
6019     mh.insert(ModellingHypothesis::UNDEFINEDHYPOTHESIS);
6020     for (const auto h : mh) {
6021       if (this->mb.hasParameters(h)) {
6022         this->writeBehaviourParametersInitializer(os, h);
6023       }
6024     }
6025   }  // end of BehaviourDSLCommon::writeBehaviourParametersInitializers
6026 
writeBehaviourParametersInitializer(std::ostream & os,const Hypothesis h) const6027   void BehaviourDSLCommon::writeBehaviourParametersInitializer(std::ostream& os, const Hypothesis h) const {
6028     const auto& md = this->mb.getBehaviourData(h);
6029     const auto& params = md.getParameters();
6030     std::string cname(this->mb.getClassName());
6031     if (h != ModellingHypothesis::UNDEFINEDHYPOTHESIS) {
6032       cname += ModellingHypothesis::toString(h);
6033     }
6034     cname += "ParametersInitializer";
6035     bool rp = false;
6036     bool ip = false;
6037     bool up = false;
6038     bool rp2 = false;
6039     bool ip2 = false;
6040     bool up2 = false;
6041     this->checkBehaviourFile(os);
6042     os << "struct " << cname << '\n'
6043        << "{\n"
6044        << "static " << cname << "&\n"
6045        << "get();\n\n";
6046     for (const auto& p : params) {
6047       if (p.type == "int") {
6048         ip = true;
6049         if ((h == ModellingHypothesis::UNDEFINEDHYPOTHESIS) ||
6050             ((h != ModellingHypothesis::UNDEFINEDHYPOTHESIS) &&
6051              (!this->mb.hasParameter(ModellingHypothesis::UNDEFINEDHYPOTHESIS, p.name)))) {
6052           ip2 = true;
6053           os << "int " << p.name << ";\n";
6054         }
6055       } else if (p.type == "ushort") {
6056         up = true;
6057         if ((h == ModellingHypothesis::UNDEFINEDHYPOTHESIS) ||
6058             ((h != ModellingHypothesis::UNDEFINEDHYPOTHESIS) &&
6059              (!this->mb.hasParameter(ModellingHypothesis::UNDEFINEDHYPOTHESIS, p.name)))) {
6060           up2 = true;
6061           os << "unsigned short " << p.name << ";\n";
6062         }
6063       } else {
6064         const auto f = SupportedTypes::getTypeFlag(p.type);
6065         if (f != SupportedTypes::SCALAR) {
6066           this->throwRuntimeError("BehaviourDSLCommon::writeBehaviourParametersInitializer",
6067                                   "invalid type for parameter '" + p.name + "' ('" + p.type + "')");
6068         }
6069         rp = true;
6070         if ((h == ModellingHypothesis::UNDEFINEDHYPOTHESIS) ||
6071             ((h != ModellingHypothesis::UNDEFINEDHYPOTHESIS) &&
6072              (!this->mb.hasParameter(ModellingHypothesis::UNDEFINEDHYPOTHESIS, p.name)))) {
6073           rp2 = true;
6074           if (p.arraySize == 1) {
6075             os << "double " << p.name << ";\n";
6076           } else {
6077             os << "tfel::math::tvector<" << p.arraySize << ",double> " << p.name << ";\n";
6078           }
6079         }
6080       }
6081     }
6082     if (!params.empty()) {
6083       os << '\n';
6084     }
6085     if (rp) {
6086       os << "void set(const char* const,const double);\n\n";
6087     }
6088     if (ip) {
6089       os << "void set(const char* const,const int);\n\n";
6090     }
6091     if (up) {
6092       os << "void set(const char* const,const unsigned short);\n\n";
6093     }
6094     if (rp2) {
6095       os << "/*!\n"
6096          << " * \\brief convert a string to double\n"
6097          << " * \\param[in] p : parameter\n"
6098          << " * \\param[in] v : value\n"
6099          << " */\n"
6100          << "static double getDouble(const std::string&,const std::string&);\n";
6101     }
6102     if (ip2) {
6103       os << "/*!\n"
6104          << " * \\brief convert a string to int\n"
6105          << " * \\param[in] p : parameter\n"
6106          << " * \\param[in] v : value\n"
6107          << " */\n"
6108          << "static int getInt(const std::string&,const std::string&);\n";
6109     }
6110     if (up2) {
6111       os << "/*!\n"
6112          << " * \\brief convert a string to unsigned short\n"
6113          << " * \\param[in] p : parameter\n"
6114          << " * \\param[in] v : value\n"
6115          << " */\n"
6116          << "static unsigned short getUnsignedShort(const std::string&,const std::string&);\n";
6117     }
6118     os << "private :\n\n"
6119        << cname << "();\n\n"
6120        << cname << "(const " << cname << "&);\n\n"
6121        << cname << "&\n"
6122        << "operator=(const " << cname << "&);\n"
6123        << "/*!\n"
6124        << " * \\brief read the parameters from the given file\n"
6125        << " * \\param[out] pi : parameters initializer\n"
6126        << " * \\param[in]  fn : file name\n"
6127        << " */\n"
6128        << "static void readParameters(" << cname << "&,const char* const);\n"
6129        << "};\n\n";
6130   }  // end of BehaviourDSLCommon::writeBehaviourParametersInitializer
6131 
writeBehaviourParserSpecificInitializeMethodPart(std::ostream &,const Hypothesis) const6132   void BehaviourDSLCommon::writeBehaviourParserSpecificInitializeMethodPart(std::ostream&, const Hypothesis) const {
6133     // Empty member meant to be overriden in Child if necessary
6134   }
6135 
writeBehaviourFileBegin(std::ostream & os) const6136   void BehaviourDSLCommon::writeBehaviourFileBegin(std::ostream& os) const {
6137     this->checkBehaviourFile(os);
6138     this->writeBehaviourFileHeader(os);
6139     this->writeBehaviourFileHeaderBegin(os);
6140     this->writeBehaviourIncludes(os);
6141     this->writeBehaviourParserSpecificIncludes(os);
6142     this->writeIncludes(os);
6143     // includes specific to interfaces
6144     for (const auto& i : this->interfaces) {
6145       i.second->writeInterfaceSpecificIncludes(os, this->mb);
6146     }
6147     this->writeNamespaceBegin(os);
6148     this->writeBehaviourParametersInitializers(os);
6149     this->writeBehaviourForwardDeclarations(os);
6150     this->writeBehaviourProfiler(os);
6151   }  // end of BehaviourDSLCommon::writeBehaviourFileBegin
6152 
writeBehaviourProfiler(std::ostream & os) const6153   void BehaviourDSLCommon::writeBehaviourProfiler(std::ostream& os) const {
6154     if (this->mb.getAttribute(BehaviourData::profiling, false)) {
6155       this->checkBehaviourFile(os);
6156       os << "/*!\n"
6157          << " * " << this->mb.getClassName() << " profiler\n"
6158          << " */\n"
6159          << "struct " << this->mb.getClassName() << "Profiler\n"
6160          << "{\n"
6161          << "//! return the profiler associated with the behaviour\n"
6162          << "static mfront::BehaviourProfiler& getProfiler();\n"
6163          << "}; // end of struct " << this->mb.getClassName() << "Profiler\n\n";
6164     }
6165   }  // end of BehaviourDSLCommon::writeBehaviourProfiler
6166 
writeBehaviourClass(std::ostream & os,const Hypothesis h) const6167   void BehaviourDSLCommon::writeBehaviourClass(std::ostream& os, const Hypothesis h) const {
6168     this->checkBehaviourFile(os);
6169     this->writeBehaviourClassBegin(os, h);
6170     this->writeBehaviourStandardTFELTypedefs(os);
6171     os << "private :\n\n";
6172     this->writeBehaviourParserSpecificTypedefs(os);
6173     this->writeBehaviourStaticVariables(os, h);
6174     this->writeBehaviourIntegrationVariables(os, h);
6175     this->writeBehaviourIntegrationVariablesIncrements(os, h);
6176     this->writeBehaviourLocalVariables(os, h);
6177     this->writeBehaviourParameters(os, h);
6178     this->writeBehaviourTangentOperator(os);
6179     this->writeBehaviourParserSpecificMembers(os, h);
6180     this->writeBehaviourUpdateIntegrationVariables(os, h);
6181     this->writeBehaviourUpdateStateVariables(os, h);
6182     this->writeBehaviourUpdateAuxiliaryStateVariables(os, h);
6183     this->writeBehaviourAdditionalMembers(os, h);
6184     this->writeBehaviourPrivate(os, h);
6185     this->writeBehaviourDisabledConstructors(os);
6186     // from this point, all is public
6187     os << "public:\n\n";
6188     this->writeBehaviourConstructors(os, h);
6189     this->writeBehaviourComputeStressFreeExpansion(os, h);
6190     this->writeBehaviourInitializeMethod(os, h);
6191     this->writeBehaviourSetOutOfBoundsPolicy(os);
6192     this->writeBehaviourGetModellingHypothesis(os);
6193     this->writeBehaviourCheckBounds(os, h);
6194     this->writeBehaviourComputePredictionOperator(os, h);
6195     this->writeBehaviourGetTimeStepScalingFactor(os);
6196     this->writeBehaviourComputeAPrioriTimeStepScalingFactor(os);
6197     this->writeBehaviourIntegrator(os, h);
6198     this->writeBehaviourComputeAPosterioriTimeStepScalingFactor(os);
6199     this->writeBehaviourComputeInternalEnergy(os, h);
6200     this->writeBehaviourComputeDissipatedEnergy(os, h);
6201     this->writeBehaviourComputeTangentOperator(os, h);
6202     this->writeBehaviourGetTangentOperator(os);
6203     this->writeBehaviourUpdateExternalStateVariables(os, h);
6204     this->writeBehaviourDestructor(os);
6205     this->checkBehaviourFile(os);
6206     os << "private:\n\n";
6207     this->writeBehaviourComputeAPrioriTimeStepScalingFactorII(os, h);
6208     this->writeBehaviourComputeAPosterioriTimeStepScalingFactorII(os, h);
6209     this->writeBehaviourPolicyVariable(os);
6210     this->writeBehaviourClassEnd(os);
6211     this->writeBehaviourOutputOperator(os, h);
6212   }
6213 
writeBehaviourFileEnd(std::ostream & os) const6214   void BehaviourDSLCommon::writeBehaviourFileEnd(std::ostream& os) const {
6215     this->checkBehaviourFile(os);
6216     this->writeBehaviourTraits(os);
6217     this->writeNamespaceEnd(os);
6218     this->writeBehaviourFileHeaderEnd(os);
6219   }  // end of BehaviourDSLCommon::writeBehaviourFileBegin
6220 
hasUserDefinedPredictionOperatorCode(const BehaviourDescription & mb,const tfel::material::ModellingHypothesis::Hypothesis h)6221   static bool hasUserDefinedPredictionOperatorCode(const BehaviourDescription& mb,
6222                                                    const tfel::material::ModellingHypothesis::Hypothesis h) {
6223     using tfel::material::getFiniteStrainBehaviourTangentOperatorFlags;
6224     if (mb.getBehaviourType() == BehaviourDescription::STANDARDFINITESTRAINBEHAVIOUR) {
6225       // all available tangent operators for finite strain behaviours
6226       const auto tos = getFiniteStrainBehaviourTangentOperatorFlags();
6227       // search tangent operators defined by the user
6228       for (const auto& t : tos) {
6229         const auto ktype = convertFiniteStrainBehaviourTangentOperatorFlagToString(t);
6230         if (mb.hasCode(h, std::string(BehaviourData::ComputePredictionOperator) + '-' + ktype)) {
6231           return true;
6232         }
6233       }
6234     } else {
6235       if (mb.hasCode(h, BehaviourData::ComputePredictionOperator)) {
6236         return true;
6237       }
6238     }
6239     return false;
6240   }  // end of BehaviourDSLCommon::hasUserDefinedTangentOperatorCode
6241 
writeBehaviourComputePredictionOperator(std::ostream & os,const Hypothesis h) const6242   void BehaviourDSLCommon::writeBehaviourComputePredictionOperator(std::ostream& os, const Hypothesis h) const {
6243     using namespace std;
6244     using namespace tfel::material;
6245     const auto btype = this->mb.getBehaviourTypeFlag();
6246     if ((!this->mb.getAttribute<bool>(h, BehaviourData::hasPredictionOperator, false)) &&
6247         (this->mb.hasCode(h, BehaviourData::ComputePredictionOperator))) {
6248       this->throwRuntimeError("BehaviourDSLCommon::writeBehaviourComputePredictionOperator : ",
6249                               "attribute 'hasPredictionOperator' is set but no associated code defined");
6250     }
6251     if (!hasUserDefinedPredictionOperatorCode(this->mb, h)) {
6252       os << "IntegrationResult computePredictionOperator(const SMFlag,const SMType) override{\n"
6253          << "tfel::raise(\"" << this->mb.getClassName() << "::computePredictionOperator: \"\n"
6254          << "\"unsupported prediction operator flag\");\n"
6255          << "}\n\n";
6256       return;
6257     }
6258     if (this->mb.getBehaviourType() == BehaviourDescription::STANDARDFINITESTRAINBEHAVIOUR) {
6259       // all available tangent operators for finite strain behaviours
6260       const auto tos(getFiniteStrainBehaviourTangentOperatorFlags());
6261       // all known converters
6262       const auto converters =
6263           FiniteStrainBehaviourTangentOperatorConversion::getAvailableFiniteStrainBehaviourTangentOperatorConversions();
6264       // tangent operators defined by the user
6265       vector<FiniteStrainBehaviourTangentOperatorBase::Flag> ktos;
6266       for (const auto& t : tos) {
6267         const auto ktype = convertFiniteStrainBehaviourTangentOperatorFlagToString(t);
6268         if (this->mb.hasCode(h, std::string(BehaviourData::ComputePredictionOperator) + '-' + ktype)) {
6269           ktos.push_back(t);
6270         }
6271       }
6272       if (!ktos.empty()) {
6273         // computing all the conversion paths starting from user defined ones
6274         vector<FiniteStrainBehaviourTangentOperatorConversionPath> paths;
6275         for (const auto& k : ktos) {
6276           const auto kpaths =
6277               FiniteStrainBehaviourTangentOperatorConversionPath::getConversionsPath(k, ktos, converters);
6278           paths.insert(paths.end(), kpaths.begin(), kpaths.end());
6279         }
6280         for (const auto& t : tos) {
6281           const auto ktype = convertFiniteStrainBehaviourTangentOperatorFlagToString(t);
6282           if (std::find(ktos.begin(), ktos.end(), t) != ktos.end()) {
6283             os << "IntegrationResult\ncomputePredictionOperator_" << ktype << "(const SMType smt){\n"
6284                << "using namespace std;\n"
6285                << "using namespace tfel::math;\n"
6286                << "using std::vector;\n";
6287             writeMaterialLaws(os, this->mb.getMaterialLaws());
6288             os << this->mb.getCode(h, std::string(BehaviourData::ComputePredictionOperator) + "-" + ktype) << '\n'
6289                << "return SUCCESS;\n"
6290                << "}\n\n";
6291           } else {
6292             if ((h ==
6293                  ModellingHypothesis::AXISYMMETRICALGENERALISEDPLANESTRESS) ||
6294                 (h == ModellingHypothesis::PLANESTRESS)) {
6295               os << "IntegrationResult computePredictionOperator_" << ktype << "(const SMType){\n"
6296                  << "tfel::raise(\"" << this->mb.getClassName() << "::computePredictionOperator_" << ktype << ": \"\n"
6297                  << "\"computing the prediction operator '" << ktype << "' is not supported\");\n"
6298                  << "}\n\n";
6299             } else {
6300               const auto path =
6301                   FiniteStrainBehaviourTangentOperatorConversionPath::
6302                       getShortestPath(paths, t);
6303               if (path.empty()) {
6304                 os << "IntegrationResult computePredictionOperator_" << ktype
6305                    << "(const SMType){\n"
6306                    << "tfel::raise(\"" << this->mb.getClassName()
6307                    << "::computePredictionOperator_" << ktype << ": \"\n"
6308                    << "\"computing the prediction operator '" << ktype
6309                    << "' is not supported\");\n"
6310                    << "}\n\n";
6311               } else {
6312                 os << "IntegrationResult computePredictionOperator_" << ktype
6313                    << "(const SMType smt){\n";
6314                 auto pc = path.begin();
6315                 os << "using namespace tfel::math;\n";
6316                 os << "// computing "
6317                    << convertFiniteStrainBehaviourTangentOperatorFlagToString(
6318                           pc->from())
6319                    << '\n';
6320                 const auto k =
6321                     convertFiniteStrainBehaviourTangentOperatorFlagToString(
6322                         pc->from());
6323                 os << "this->computePredictionOperator_" << k << "(smt);\n"
6324                    << "const "
6325                    << getFiniteStrainBehaviourTangentOperatorFlagType(
6326                           pc->from())
6327                    << "<N,stress>"
6328                    << " tangentOperator_"
6329                    << convertFiniteStrainBehaviourTangentOperatorFlagToString(
6330                           pc->from())
6331                    << " = this->Dt.template get<"
6332                    << getFiniteStrainBehaviourTangentOperatorFlagType(
6333                           pc->from())
6334                    << "<N,stress> >();\n";
6335                 for (; pc != path.end();) {
6336                   const auto converter = *pc;
6337                   if (++pc == path.end()) {
6338                     os << converter.getFinalConversion() << '\n';
6339                   } else {
6340                     os << converter.getIntermediateConversion() << '\n';
6341                   }
6342                 }
6343                 os << "return SUCCESS;\n"
6344                    << "}\n\n";
6345               }
6346             }
6347           }
6348         }
6349         os << "IntegrationResult computePredictionOperator(const SMFlag smflag,const SMType smt) override{\n"
6350            << "using namespace std;\n"
6351            << "switch(smflag){\n";
6352         for (const auto& t : tos) {
6353           const auto ktype = convertFiniteStrainBehaviourTangentOperatorFlagToString(t);
6354           os << "case " << ktype << ":\n"
6355              << "return this->computePredictionOperator_" << ktype << "(smt);\n";
6356         }
6357         os << "}\n"
6358            << "tfel::raise(\"" << this->mb.getClassName() << "::computePredictionOperator: \"\n"
6359            << "\"unsupported prediction operator flag\");\n"
6360            << "}\n\n";
6361       }
6362     } else {
6363       os << "IntegrationResult\n"
6364          << "computePredictionOperator(const SMFlag smflag,const SMType smt) override{\n"
6365          << "using namespace std;\n"
6366          << "using namespace tfel::math;\n"
6367          << "using std::vector;\n";
6368       writeMaterialLaws(os, this->mb.getMaterialLaws());
6369       if ((this->mb.getBehaviourType() == BehaviourDescription::STANDARDSTRAINBASEDBEHAVIOUR) ||
6370           (this->mb.getBehaviourType() == BehaviourDescription::COHESIVEZONEMODEL)||
6371 	  (this->mb.getBehaviourType() == BehaviourDescription::GENERALBEHAVIOUR)) {
6372         if (mb.useQt()) {
6373           os << "tfel::raise_if(smflag!=MechanicalBehaviour<" << btype
6374              << ",hypothesis,Type,use_qt>::STANDARDTANGENTOPERATOR,\n"
6375              << "\"invalid prediction operator flag\");\n";
6376         } else {
6377           os << "tfel::raise_if(smflag!=MechanicalBehaviour<" << btype
6378              << ",hypothesis,Type,false>::STANDARDTANGENTOPERATOR,\n"
6379              << "\"invalid prediction operator flag\");\n";
6380         }
6381       }
6382       os << this->mb.getCode(h, BehaviourData::ComputePredictionOperator)
6383          << "return SUCCESS;\n"
6384          << "}\n\n";
6385     }
6386   }  // end of BehaviourDSLCommon::writeBehaviourComputePredictionOperator
6387 
writeBehaviourComputeTangentOperator(std::ostream & os,const Hypothesis h) const6388   void BehaviourDSLCommon::writeBehaviourComputeTangentOperator(std::ostream& os, const Hypothesis h) const {
6389     using namespace tfel::material;
6390     if (this->mb.getBehaviourType() == BehaviourDescription::STANDARDFINITESTRAINBEHAVIOUR) {
6391       // all available tangent operators for finite strain behaviours
6392       const auto tos(getFiniteStrainBehaviourTangentOperatorFlags());
6393       // all known converters
6394       const auto converters =
6395           FiniteStrainBehaviourTangentOperatorConversion::getAvailableFiniteStrainBehaviourTangentOperatorConversions();
6396       // tangent operators defined by the user
6397       std::vector<FiniteStrainBehaviourTangentOperatorBase::Flag> ktos;
6398       for (const auto& t : tos) {
6399         const auto ktype = convertFiniteStrainBehaviourTangentOperatorFlagToString(t);
6400         if (this->mb.hasCode(h, std::string(BehaviourData::ComputeTangentOperator) + '-' + ktype)) {
6401           ktos.push_back(t);
6402         }
6403       }
6404       if (!ktos.empty()) {
6405         // computing all the conversion paths starting from user defined ones
6406         std::vector<FiniteStrainBehaviourTangentOperatorConversionPath> paths;
6407         for (const auto& k : ktos) {
6408           const auto kpaths =
6409               FiniteStrainBehaviourTangentOperatorConversionPath::getConversionsPath(k, ktos, converters);
6410           paths.insert(paths.end(), kpaths.begin(), kpaths.end());
6411         }
6412         for (const auto& t : tos) {
6413           const auto ktype = convertFiniteStrainBehaviourTangentOperatorFlagToString(t);
6414           if (find(ktos.begin(), ktos.end(), t) != ktos.end()) {
6415             os << "bool computeConsistentTangentOperator_" << ktype << "(const SMType smt){\n"
6416                << "using namespace std;\n"
6417                << "using namespace tfel::math;\n"
6418                << "using std::vector;\n";
6419             writeMaterialLaws(os, this->mb.getMaterialLaws());
6420             this->writeBehaviourComputeTangentOperatorBody(
6421                 os, h, std::string(BehaviourData::ComputeTangentOperator) +
6422                            "-" + ktype);
6423             os << "}\n\n";
6424           } else {
6425             if ((h ==
6426                  ModellingHypothesis::AXISYMMETRICALGENERALISEDPLANESTRESS) ||
6427                 (h == ModellingHypothesis::PLANESTRESS)) {
6428               os << "bool computeConsistentTangentOperator_" << ktype
6429                  << "(const SMType){\n"
6430                  << "tfel::raise(\"" << this->mb.getClassName()
6431                  << "::computeConsistentTangentOperator_" << ktype << ": \"\n"
6432                  << "\"computing the tangent operator '" << ktype
6433                  << "' is not supported\");\n"
6434                  << "}\n\n";
6435             } else {
6436               const auto path =
6437                   FiniteStrainBehaviourTangentOperatorConversionPath::
6438                       getShortestPath(paths, t);
6439               if (path.empty()) {
6440                 os << "bool computeConsistentTangentOperator_" << ktype
6441                    << "(const SMType){\n"
6442                    << "tfel::raise(\"" << this->mb.getClassName()
6443                    << "::computeConsistentTangentOperator_" << ktype << ": \"\n"
6444                    << "\"computing the tangent operator '" << ktype
6445                    << "' is not supported\");\n"
6446                    << "}\n\n";
6447               } else {
6448                 os << "bool computeConsistentTangentOperator_" << ktype
6449                    << "(const SMType smt){\n";
6450                 auto pc = path.begin();
6451                 os << "using namespace tfel::math;\n";
6452                 os << "// computing "
6453                    << convertFiniteStrainBehaviourTangentOperatorFlagToString(
6454                           pc->from())
6455                    << '\n';
6456                 const auto k =
6457                     convertFiniteStrainBehaviourTangentOperatorFlagToString(
6458                         pc->from());
6459                 os << "this->computeConsistentTangentOperator_" << k
6460                    << "(smt);\n"
6461                    << "const "
6462                    << getFiniteStrainBehaviourTangentOperatorFlagType(
6463                           pc->from())
6464                    << "<N,stress>"
6465                    << " tangentOperator_"
6466                    << convertFiniteStrainBehaviourTangentOperatorFlagToString(
6467                           pc->from())
6468                    << " = this->Dt.template get<"
6469                    << getFiniteStrainBehaviourTangentOperatorFlagType(
6470                           pc->from())
6471                    << "<N,stress> >();\n";
6472                 for (; pc != path.end();) {
6473                   const auto converter = *pc;
6474                   if (++pc == path.end()) {
6475                     os << converter.getFinalConversion() << '\n';
6476                   } else {
6477                     os << converter.getIntermediateConversion() << '\n';
6478                   }
6479                 }
6480                 os << "return true;\n"
6481                    << "}\n\n";
6482               }
6483             }
6484           }
6485         }
6486         os << "bool computeConsistentTangentOperator(const SMFlag smflag,const SMType smt){\n"
6487            << "switch(smflag){\n";
6488         for (const auto& t : tos) {
6489           const auto ktype = convertFiniteStrainBehaviourTangentOperatorFlagToString(t);
6490           os << "case " << ktype << ":\n"
6491              << "return this->computeConsistentTangentOperator_" << ktype << "(smt);\n";
6492         }
6493         os << "}\n"
6494            << "tfel::raise(\"" << this->mb.getClassName() << "::computeConsistentTangentOperator: \"\n"
6495            << "\"unsupported tangent operator flag\");\n"
6496            << "}\n\n";
6497       }
6498     } else {
6499       if (this->mb.hasCode(h, BehaviourData::ComputeTangentOperator)) {
6500         os << "bool computeConsistentTangentOperator(const SMType smt){\n"
6501            << "using namespace std;\n"
6502            << "using namespace tfel::math;\n"
6503            << "using std::vector;\n";
6504         writeMaterialLaws(os, this->mb.getMaterialLaws());
6505         this->writeBehaviourComputeTangentOperatorBody(
6506             os, h, BehaviourData::ComputeTangentOperator);
6507         os << "}\n\n";
6508       }
6509     }
6510   }  // end of BehaviourDSLCommon::writeBehaviourComputeTangentOperator
6511 
writeBehaviourComputeTangentOperatorBody(std::ostream & os,const Hypothesis h,const std::string & n) const6512   void BehaviourDSLCommon::writeBehaviourComputeTangentOperatorBody(
6513       std::ostream& os, const Hypothesis h, const std::string& n) const {
6514     os << this->mb.getCode(h, n) << '\n' << "return true;\n";
6515   } // end of BehaviourDSLCommon::writeBehaviourComputeTangentOperatorBody
6516 
writeBehaviourGetTangentOperator(std::ostream & os) const6517   void BehaviourDSLCommon::writeBehaviourGetTangentOperator(std::ostream& os) const {
6518     this->checkBehaviourFile(os);
6519     os << "const TangentOperator& getTangentOperator() const{\n"
6520        << "return this->Dt;\n"
6521        << "}\n\n";
6522   }  // end of BehaviourDSLCommon::writeBehaviourComputeTangentOperator()
6523 
writeBehaviourGetTimeStepScalingFactor(std::ostream & os) const6524   void BehaviourDSLCommon::writeBehaviourGetTimeStepScalingFactor(std::ostream& os) const {
6525     this->checkBehaviourFile(os);
6526     os << "real getMinimalTimeStepScalingFactor() const override{\n"
6527           "  return this->minimal_time_step_scaling_factor;\n"
6528           "}\n\n";
6529   }
6530 
writeBehaviourComputeAPrioriTimeStepScalingFactor(std::ostream & os) const6531   void BehaviourDSLCommon::writeBehaviourComputeAPrioriTimeStepScalingFactor(std::ostream& os) const {
6532     this->checkBehaviourFile(os);
6533     os << "std::pair<bool,real>\n"
6534           "computeAPrioriTimeStepScalingFactor(const real current_time_step_scaling_factor) const override{\n"
6535           "const auto time_scaling_factor = this->computeAPrioriTimeStepScalingFactorII();\n"
6536           "return {time_scaling_factor.first,\n"
6537           "        std::min(std::min(std::max(time_scaling_factor.second,\n"
6538           "                                   this->minimal_time_step_scaling_factor),\n"
6539           "                          this->maximal_time_step_scaling_factor),\n"
6540           "                  current_time_step_scaling_factor)};\n"
6541           "}\n\n";
6542   }  // end of BehaviourDSLCommon::writeBehaviourComputeAPrioriTimeStepScalingFactor
6543 
writeBehaviourComputeAPrioriTimeStepScalingFactorII(std::ostream & os,const Hypothesis h) const6544   void BehaviourDSLCommon::writeBehaviourComputeAPrioriTimeStepScalingFactorII(std::ostream& os,
6545                                                                                const Hypothesis h) const {
6546     this->checkBehaviourFile(os);
6547     os << "std::pair<bool,real> computeAPrioriTimeStepScalingFactorII() const{\n";
6548     if (this->mb.hasCode(h, BehaviourData::APrioriTimeStepScalingFactor)) {
6549       os << "using namespace std;\n"
6550          << "using namespace tfel::math;\n"
6551          << "using std::vector;\n";
6552       writeMaterialLaws(os, this->mb.getMaterialLaws());
6553       os << this->mb.getCode(h, BehaviourData::APrioriTimeStepScalingFactor) << '\n';
6554     }
6555     os << "return {true,this->maximal_time_step_scaling_factor};\n"
6556        << "}\n\n";
6557   }
6558 
writeBehaviourComputeAPosterioriTimeStepScalingFactor(std::ostream & os) const6559   void BehaviourDSLCommon::writeBehaviourComputeAPosterioriTimeStepScalingFactor(std::ostream& os) const {
6560     this->checkBehaviourFile(os);
6561     os << "std::pair<bool,real>\n"
6562           "computeAPosterioriTimeStepScalingFactor(const real current_time_step_scaling_factor) const override{\n"
6563           "const auto time_scaling_factor = this->computeAPosterioriTimeStepScalingFactorII();\n"
6564           "return {time_scaling_factor.first,\n"
6565           "        std::min(std::min(std::max(time_scaling_factor.second,\n"
6566           "                                   this->minimal_time_step_scaling_factor),\n"
6567           "                          this->maximal_time_step_scaling_factor),\n"
6568           "                 current_time_step_scaling_factor)};\n"
6569           "}\n\n";
6570   }  // end of BehaviourDSLCommon::writeBehaviourComputeAPosterioriTimeStepScalingFactor
6571 
writeBehaviourComputeAPosterioriTimeStepScalingFactorII(std::ostream & os,const Hypothesis h) const6572   void BehaviourDSLCommon::writeBehaviourComputeAPosterioriTimeStepScalingFactorII(std::ostream& os,
6573                                                                                    const Hypothesis h) const {
6574     this->checkBehaviourFile(os);
6575     os << "std::pair<bool,real> computeAPosterioriTimeStepScalingFactorII() const{\n";
6576     if (this->mb.hasCode(h, BehaviourData::APosterioriTimeStepScalingFactor)) {
6577       os << "using namespace std;\n"
6578          << "using namespace tfel::math;\n"
6579          << "using std::vector;\n";
6580       writeMaterialLaws(os, this->mb.getMaterialLaws());
6581       os << this->mb.getCode(h, BehaviourData::APosterioriTimeStepScalingFactor) << '\n';
6582     }
6583     os << "return {true,this->maximal_time_step_scaling_factor};\n"
6584        << "}\n\n";
6585   }  // end of BehaviourDSLCommon::writeBehaviourComputeAPosterioriTimeStepScalingFactor
6586 
writeBehaviourTangentOperator(std::ostream & os) const6587   void BehaviourDSLCommon::writeBehaviourTangentOperator(
6588       std::ostream& os) const {
6589     this->checkBehaviourFile(os);
6590     if (!this->mb.hasTangentOperator()) {
6591       return;
6592     }
6593     const auto& blocks = this->mb.getTangentOperatorBlocks();
6594     os << "//! Tangent operator;\n"
6595        << "TangentOperator Dt;\n";
6596     if (this->mb.hasTrivialTangentOperatorStructure()) {
6597       tfel::raise_if(
6598           ((blocks.size() != 1u) || (blocks.front().first.arraySize != 1u) ||
6599            (blocks.front().second.arraySize != 1u)),
6600           "BehaviourDSLCommon::writeBehaviourTangentOperator: internal error");
6601       if (this->mb.getBehaviourType() !=
6602           BehaviourDescription::STANDARDFINITESTRAINBEHAVIOUR) {
6603         os << "//! alias to the tangent operator;\n"
6604            << "TangentOperator& "
6605            << this->mb.getTangentOperatorBlockName(blocks.front()) << ";\n";
6606       }
6607       return;
6608     }
6609     // write blocks
6610     for (const auto& b : blocks) {
6611       const auto& v1 = b.first;
6612       const auto& v2 = b.second;
6613       if ((v1.arraySize != 1u) || (v2.arraySize != 1u)) {
6614         break;
6615       }
6616       auto throw_unsupported_block = [&v1, &v2] {
6617         tfel::raise(
6618             "BehaviourDSLCommon::writeBehaviourTangentOperator:"
6619             "tangent operator blocks associated with "
6620             "the derivative of '" +  //
6621             displayName(v1) + "' (of type '" + v1.type + "') with respect to '" +  //
6622             displayName(v2) + "' (of type '" + v2.type + "') is not supported");
6623       };
6624       const auto bn = this->mb.getTangentOperatorBlockName(b);
6625       if (v1.getTypeFlag() == SupportedTypes::SCALAR) {
6626         if (v2.getTypeFlag() == SupportedTypes::SCALAR) {
6627           os << "real& " << bn << ";\n";
6628         } else if (v2.getTypeFlag() == SupportedTypes::STENSOR) {
6629           os << "tfel::math::StensorView<N,real> " << bn << ";\n";
6630         } else if (v2.getTypeFlag() == SupportedTypes::TENSOR) {
6631           os << "tfel::math::TensorView<N,real> " << bn << ";\n";
6632         } else {
6633           throw_unsupported_block();
6634         }
6635       } else if (v1.getTypeFlag() == SupportedTypes::TVECTOR) {
6636         if (v2.getTypeFlag() == SupportedTypes::SCALAR) {
6637           os << "tfel::math::TVectorView<N,real> " << bn << ";\n";
6638         } else if (v2.getTypeFlag() == SupportedTypes::TVECTOR) {
6639           os << "tfel::math::TMatrixView<N,N,real> " << bn << ";\n";
6640         } else {
6641           throw_unsupported_block();
6642         }
6643       } else if (v1.getTypeFlag() == SupportedTypes::STENSOR) {
6644         if (v2.getTypeFlag() == SupportedTypes::SCALAR) {
6645           os << "tfel::math::StensorView<N,real> " << bn << ";\n";
6646         } else if (v2.getTypeFlag() == SupportedTypes::STENSOR) {
6647           os << "tfel::math::ST2toST2View<N,real> " << bn << ";\n";
6648         } else if (v2.getTypeFlag() == SupportedTypes::TENSOR) {
6649           os << "tfel::math::ST2toT2View<N,real> " << bn << ";\n";
6650         } else {
6651           throw_unsupported_block();
6652         }
6653       } else if (v1.getTypeFlag() == SupportedTypes::TENSOR) {
6654         if (v2.getTypeFlag() == SupportedTypes::SCALAR) {
6655           os << "tfel::math::TensorView<N,real> " << bn << ";\n";
6656         } else if (v2.getTypeFlag() == SupportedTypes::STENSOR) {
6657           os << "tfel::math::T2toST2View<N,real> " << bn << ";\n";
6658         } else if (v2.getTypeFlag() == SupportedTypes::TENSOR) {
6659           os << "tfel::math::T2toT2View<N,real> " << bn << ";\n";
6660         } else {
6661           throw_unsupported_block();
6662         }
6663       } else {
6664         throw_unsupported_block();
6665       }
6666     }
6667   }  // end of BehaviourDSLCommon::writeBehaviourTangentOperator()
6668 
checkIntegrationDataFile(std::ostream & os) const6669   void BehaviourDSLCommon::checkIntegrationDataFile(std::ostream& os) const {
6670     if ((!os) || (!os.good())) {
6671       this->throwRuntimeError(
6672           "BehaviourDSLCommon::checkIntegrationDataOutputFile",
6673           "output file is not valid");
6674     }
6675   }
6676 
writeIntegrationDataFileHeader(std::ostream & os) const6677   void BehaviourDSLCommon::writeIntegrationDataFileHeader(std::ostream& os) const {
6678     this->checkIntegrationDataFile(os);
6679     os << "/*!\n";
6680     os << "* \\file   " << this->getIntegrationDataFileName() << '\n';
6681     os << "* \\brief  "
6682        << "this file implements the " << this->mb.getClassName() << "IntegrationData"
6683        << " class.\n";
6684     os << "*         File generated by ";
6685     os << MFrontHeader::getVersionName() << " ";
6686     os << "version " << MFrontHeader::getVersionNumber();
6687     os << '\n';
6688     if (!this->fd.authorName.empty()) {
6689       os << "* \\author " << this->fd.authorName << '\n';
6690     }
6691     if (!this->fd.date.empty()) {
6692       os << "* \\date   " << this->fd.date << '\n';
6693     }
6694     os << " */\n\n";
6695   }
6696 
writeIntegrationDataFileHeaderBegin(std::ostream & os) const6697   void BehaviourDSLCommon::writeIntegrationDataFileHeaderBegin(std::ostream& os) const {
6698     this->checkIntegrationDataFile(os);
6699     os << "#ifndef LIB_TFELMATERIAL_" << makeUpperCase(this->mb.getClassName()) << "_INTEGRATION_DATA_HXX\n"
6700        << "#define LIB_TFELMATERIAL_" << makeUpperCase(this->mb.getClassName()) << "_INTEGRATION_DATA_HXX\n\n";
6701   }
6702 
writeIntegrationDataFileHeaderEnd(std::ostream & os) const6703   void BehaviourDSLCommon::writeIntegrationDataFileHeaderEnd(std::ostream& os) const {
6704     this->checkIntegrationDataFile(os);
6705     os << "#endif /* LIB_TFELMATERIAL_" << makeUpperCase(this->mb.getClassName()) << "_INTEGRATION_DATA_HXX */\n";
6706   }
6707 
writeIntegrationDataStandardTFELIncludes(std::ostream & os) const6708   void BehaviourDSLCommon::writeIntegrationDataStandardTFELIncludes(std::ostream& os) const {
6709     bool b1 = false;
6710     bool b2 = false;
6711     this->checkIntegrationDataFile(os);
6712     os << "#include<string>\n"
6713        << "#include<iostream>\n"
6714        << "#include<limits>\n"
6715        << "#include<stdexcept>\n"
6716        << "#include<algorithm>\n\n"
6717        << "#include\"TFEL/Raise.hxx\"\n"
6718        << "#include\"TFEL/PhysicalConstants.hxx\"\n"
6719        << "#include\"TFEL/Config/TFELConfig.hxx\"\n"
6720        << "#include\"TFEL/Config/TFELTypes.hxx\"\n"
6721        << "#include\"TFEL/Metaprogramming/StaticAssert.hxx\"\n"
6722        << "#include\"TFEL/TypeTraits/IsFundamentalNumericType.hxx\"\n"
6723        << "#include\"TFEL/TypeTraits/IsScalar.hxx\"\n"
6724        << "#include\"TFEL/TypeTraits/IsReal.hxx\"\n"
6725        << "#include\"TFEL/TypeTraits/Promote.hxx\"\n"
6726        << "#include\"TFEL/Math/General/IEEE754.hxx\"\n";
6727     this->mb.requiresTVectorOrVectorIncludes(b1, b2);
6728     if (b1) {
6729       os << "#include\"TFEL/Math/tvector.hxx\"\n"
6730          << "#include\"TFEL/Math/Vector/tvectorIO.hxx\"\n";
6731     }
6732     if (b2) {
6733       os << "#include\"TFEL/Math/vector.hxx\"\n";
6734     }
6735     os << "#include\"TFEL/Math/stensor.hxx\"\n"
6736        << "#include\"TFEL/Math/st2tost2.hxx\"\n";
6737     if (this->mb.getBehaviourType() == BehaviourDescription::STANDARDFINITESTRAINBEHAVIOUR) {
6738       os << "#include\"TFEL/Math/tensor.hxx\"\n"
6739          << "#include\"TFEL/Math/t2tot2.hxx\"\n"
6740          << "#include\"TFEL/Math/t2tost2.hxx\"\n"
6741          << "#include\"TFEL/Math/st2tot2.hxx\"\n";
6742     }
6743   }
6744 
writeIntegrationDataDefaultMembers(std::ostream & os) const6745   void BehaviourDSLCommon::writeIntegrationDataDefaultMembers(std::ostream& os) const {
6746     this->checkIntegrationDataFile(os);
6747     os << "protected: \n\n";
6748     for (const auto& v : this->mb.getMainVariables()) {
6749       if (Gradient::isIncrementKnown(v.first)) {
6750         os << "/*!\n"
6751            << " * \\brief " << v.first.name << " increment\n"
6752            << " */\n"
6753            << v.first.type << " d" << v.first.name << ";\n\n";
6754       } else {
6755         os << "/*!\n"
6756            << " * \\brief " << v.first.name << " at the end of the time step\n"
6757            << " */\n"
6758            << v.first.type << " " << v.first.name << "1;\n\n";
6759       }
6760     }
6761     os << "/*!\n"
6762        << " * \\brief time increment\n"
6763        << " */\n"
6764        << "time dt;\n\n";
6765   }
6766 
writeIntegrationDataStandardTFELTypedefs(std::ostream & os) const6767   void BehaviourDSLCommon::writeIntegrationDataStandardTFELTypedefs(std::ostream& os) const {
6768     this->checkIntegrationDataFile(os);
6769     os << "static " << constexpr_c << " unsigned short TVectorSize = N;\n"
6770        << "typedef tfel::math::StensorDimeToSize<N> StensorDimeToSize;\n"
6771        << "static " << constexpr_c << " unsigned short StensorSize = "
6772        << "StensorDimeToSize::value;\n"
6773        << "typedef tfel::math::TensorDimeToSize<N> TensorDimeToSize;\n"
6774        << "static " << constexpr_c << " unsigned short TensorSize = "
6775        << "TensorDimeToSize::value;\n\n";
6776     this->writeStandardTFELTypedefs(os);
6777     os << '\n';
6778   }
6779 
writeIntegrationDataDisabledConstructors(std::ostream & os) const6780   void BehaviourDSLCommon::writeIntegrationDataDisabledConstructors(std::ostream& os) const {
6781     this->checkIntegrationDataFile(os);
6782   }
6783 
writeIntegrationDataConstructors(std::ostream & os,const Hypothesis h) const6784   void BehaviourDSLCommon::writeIntegrationDataConstructors(std::ostream& os, const Hypothesis h) const {
6785     const auto& md = this->mb.getBehaviourData(h);
6786     this->checkIntegrationDataFile(os);
6787     os << "/*!\n"
6788        << "* \\brief Default constructor\n"
6789        << "*/\n"
6790        << this->mb.getClassName() << "IntegrationData()\n"
6791        << "{}\n\n"
6792        << "/*!\n"
6793        << "* \\brief Copy constructor\n"
6794        << "*/\n"
6795        << this->mb.getClassName() << "IntegrationData(const " << this->mb.getClassName() << "IntegrationData& src)\n"
6796        << ": ";
6797     for (const auto& v : this->mb.getMainVariables()) {
6798       if (Gradient::isIncrementKnown(v.first)) {
6799         os << "d" << v.first.name << "(src.d" << v.first.name << "),\n";
6800       } else {
6801         os << v.first.name << "1(src." << v.first.name << "1),\n";
6802       }
6803     }
6804     os << "dt(src.dt)";
6805     for (const auto& v : md.getExternalStateVariables()) {
6806       os << ",\nd" << v.name << "(src.d" << v.name << ")";
6807     }
6808     os << "\n{}\n\n";
6809     // Creating constructor for external interfaces
6810     for (const auto& i : this->interfaces) {
6811       if (i.second->isBehaviourConstructorRequired(h, this->mb)) {
6812         i.second->writeIntegrationDataConstructor(os, h, this->mb);
6813       }
6814     }
6815   }
6816 
writeIntegrationDataScaleOperators(std::ostream & os,const Hypothesis h) const6817   void BehaviourDSLCommon::writeIntegrationDataScaleOperators(std::ostream& os, const Hypothesis h) const {
6818     const auto& md = this->mb.getBehaviourData(h);
6819     bool iknown = true;
6820     for (const auto& v : this->mb.getMainVariables()) {
6821       iknown = Gradient::isIncrementKnown(v.first);
6822     }
6823     this->checkIntegrationDataFile(os);
6824     os << "/*\n"
6825        << "* \\brief scale the integration data by a scalar.\n"
6826        << "*/\n"
6827        << "template<typename Scal>\n"
6828        << "typename std::enable_if<\n"
6829        << "tfel::typetraits::IsFundamentalNumericType<Scal>::cond&&\n"
6830        << "tfel::typetraits::IsScalar<Scal>::cond&&\n"
6831        << "tfel::typetraits::IsReal<Scal>::cond&&\n"
6832        << "std::is_same<Type,"
6833        << "typename tfel::typetraits::Promote"
6834        << "<Type,Scal>::type>::value,\n"
6835        << this->mb.getClassName() << "IntegrationData&\n"
6836        << ">::type\n";
6837     if (!iknown) {
6838       if (this->mb.useQt()) {
6839         os << "scale(const " << this->mb.getClassName()
6840            << "BehaviourData<hypothesis,Type,use_qt>& behaviourData, const Scal time_scaling_factor){\n";
6841       } else {
6842         os << "scale(const " << this->mb.getClassName()
6843            << "BehaviourData<hypothesis,Type,false>& behaviourData, const Scal time_scaling_factor){\n";
6844       }
6845     } else {
6846       if (this->mb.useQt()) {
6847         os << "scale(const " << this->mb.getClassName()
6848            << "BehaviourData<hypothesis,Type,use_qt>&, const Scal time_scaling_factor){\n";
6849       } else {
6850         os << "scale(const " << this->mb.getClassName()
6851            << "BehaviourData<hypothesis,Type,false>&, const Scal time_scaling_factor){\n";
6852       }
6853     }
6854     os << "this->dt   *= time_scaling_factor;\n";
6855     for (const auto& v : this->mb.getMainVariables()) {
6856       if (Gradient::isIncrementKnown(v.first)) {
6857         os << "this->d" << v.first.name << " *= time_scaling_factor;\n";
6858       } else {
6859         os << "this->" << v.first.name << "1 = (1-time_scaling_factor)*(behaviourData." << v.first.name
6860            << "0)+time_scaling_factor*(this->" << v.first.name << "1);\n";
6861       }
6862     }
6863     for (const auto& v : md.getExternalStateVariables()) {
6864       os << "this->d" << v.name << " *= time_scaling_factor;\n";
6865     }
6866     os << "return *this;\n"
6867        << "}\n\n";
6868   }  // end of BehaviourDSLCommon::writeIntegrationDataScaleOpeartors
6869 
writeIntegrationDataUpdateDrivingVariablesMethod(std::ostream & os) const6870   void BehaviourDSLCommon::writeIntegrationDataUpdateDrivingVariablesMethod(std::ostream& os) const {
6871     bool iknown = true;
6872     for (const auto& v : this->mb.getMainVariables()) {
6873       iknown = Gradient::isIncrementKnown(v.first);
6874     }
6875     this->checkIntegrationDataFile(os);
6876     os << "/*!\n"
6877        << "* \\brief update the driving variable in case of substepping.\n"
6878        << "*/\n"
6879        << this->mb.getClassName() << "IntegrationData&\n";
6880     if (!iknown) {
6881       if (this->mb.useQt()) {
6882         os << "updateDrivingVariables(const " << this->mb.getClassName()
6883            << "BehaviourData<hypothesis,Type,use_qt>& behaviourData){\n";
6884       } else {
6885         os << "updateDrivingVariables(const " << this->mb.getClassName()
6886            << "BehaviourData<hypothesis,Type,false>& behaviourData){\n";
6887       }
6888     } else {
6889       if (this->mb.useQt()) {
6890         os << "updateDrivingVariables(const " << this->mb.getClassName()
6891            << "BehaviourData<hypothesis,Type,use_qt>&){\n";
6892       } else {
6893         os << "updateDrivingVariables(const " << this->mb.getClassName()
6894            << "BehaviourData<hypothesis,Type,false>&){\n";
6895       }
6896     }
6897     for (const auto& v : this->mb.getMainVariables()) {
6898       if (!Gradient::isIncrementKnown(v.first)) {
6899         os << "this->" << v.first.name << "1 += "
6900            << "this->" << v.first.name << "1 - (behaviourData."
6901            << v.first.name << "0);\n";
6902       }
6903     }
6904     os << "return *this;\n"
6905        << "}\n\n";
6906   }  // end of BehaviourDSLCommon::writeIntegrationUpdateDrivingVariablesMethod
6907 
writeIntegrationDataClassHeader(std::ostream & os) const6908   void BehaviourDSLCommon::writeIntegrationDataClassHeader(std::ostream& os) const {
6909     this->checkIntegrationDataFile(os);
6910     os << "/*!\n"
6911        << "* \\class " << this->mb.getClassName() << "IntegrationData\n"
6912        << "* \\brief This class implements the " << this->mb.getClassName() << "IntegrationData"
6913        << " behaviour.\n"
6914        << "* \\param unsigned short N, space dimension.\n"
6915        << "* \\param typename Type, numerical type.\n"
6916        << "* \\param bool use_qt, conditional saying if quantities are use.\n";
6917     if (!this->fd.authorName.empty()) {
6918       os << "* \\author " << this->fd.authorName << '\n';
6919     }
6920     if (!this->fd.date.empty()) {
6921       os << "* \\date   " << this->fd.date << '\n';
6922     }
6923     os << "*/\n";
6924   }
6925 
writeIntegrationDataForwardDeclarations(std::ostream & os) const6926   void BehaviourDSLCommon::writeIntegrationDataForwardDeclarations(std::ostream& os) const {
6927     this->checkIntegrationDataFile(os);
6928     os << "//! \\brief forward declaration\n"
6929        << "template<ModellingHypothesis::Hypothesis hypothesis,typename Type,bool use_qt>\n"
6930        << "class " << this->mb.getClassName() << "IntegrationData;\n\n";
6931     if (this->mb.useQt()) {
6932       os << "//! \\brief forward declaration\n"
6933          << "template<ModellingHypothesis::Hypothesis hypothesis,typename Type,bool use_qt>\n"
6934          << "std::ostream&\n operator <<(std::ostream&,"
6935          << "const " << this->mb.getClassName() << "IntegrationData<hypothesis,Type,use_qt>&);\n\n";
6936     } else {
6937       os << "//! \\brief forward declaration\n"
6938          << "template<ModellingHypothesis::Hypothesis hypothesis,typename Type>\n"
6939          << "std::ostream&\n operator <<(std::ostream&,"
6940          << "const " << this->mb.getClassName() << "IntegrationData<hypothesis,Type,false>&);\n\n";
6941     }
6942     // maintenant, il faut déclarer toutes les spécialisations partielles...
6943     const auto& mh = this->mb.getModellingHypotheses();
6944     for (const auto& h : mh) {
6945       if (this->mb.hasSpecialisedMechanicalData(h)) {
6946         if (this->mb.useQt()) {
6947           os << "//! \\brief forward declaration\n"
6948              << "template<typename Type,bool use_qt>\n"
6949              << "std::ostream&\n operator <<(std::ostream&,"
6950              << "const " << this->mb.getClassName()
6951              << "IntegrationData<ModellingHypothesis::" << ModellingHypothesis::toUpperCaseString(h)
6952              << ",Type,use_qt>&);\n\n";
6953         } else {
6954           os << "//! \\brief forward declaration\n"
6955              << "template<typename Type>\n"
6956              << "std::ostream&\n operator <<(std::ostream&,"
6957              << "const " << this->mb.getClassName()
6958              << "IntegrationData<ModellingHypothesis::" << ModellingHypothesis::toUpperCaseString(h)
6959              << ",Type,false>&);\n\n";
6960         }
6961       }
6962     }
6963   }
6964 
writeIntegrationDataClassBegin(std::ostream & os,const Hypothesis h) const6965   void BehaviourDSLCommon::writeIntegrationDataClassBegin(std::ostream& os, const Hypothesis h) const {
6966     this->checkIntegrationDataFile(os);
6967     if (h == ModellingHypothesis::UNDEFINEDHYPOTHESIS) {
6968       if (this->mb.useQt()) {
6969         os << "template<ModellingHypothesis::Hypothesis hypothesis,typename Type,bool use_qt>\n";
6970         os << "class " << this->mb.getClassName() << "IntegrationData\n";
6971       } else {
6972         os << "template<ModellingHypothesis::Hypothesis hypothesis,typename Type>\n";
6973         os << "class " << this->mb.getClassName() << "IntegrationData<hypothesis,Type,false>\n";
6974       }
6975     } else {
6976       if (this->mb.useQt()) {
6977         os << "template<typename Type,bool use_qt>\n";
6978         os << "class " << this->mb.getClassName()
6979            << "IntegrationData<ModellingHypothesis::" << ModellingHypothesis::toUpperCaseString(h) << ",Type,use_qt>\n";
6980       } else {
6981         os << "template<typename Type>\n";
6982         os << "class " << this->mb.getClassName()
6983            << "IntegrationData<ModellingHypothesis::" << ModellingHypothesis::toUpperCaseString(h) << ",Type,false>\n";
6984       }
6985     }
6986     os << "{\n\n";
6987     if (h != ModellingHypothesis::UNDEFINEDHYPOTHESIS) {
6988       os << "static " << constexpr_c << " ModellingHypothesis::Hypothesis hypothesis = "
6989          << "ModellingHypothesis::" << ModellingHypothesis::toUpperCaseString(h) << ";\n";
6990     }
6991     os << "static " << constexpr_c << " unsigned short N = ModellingHypothesisToSpaceDimension<hypothesis>::value;\n";
6992     os << "TFEL_STATIC_ASSERT(N==1||N==2||N==3);\n";
6993     os << "TFEL_STATIC_ASSERT(tfel::typetraits::"
6994        << "IsFundamentalNumericType<Type>::cond);\n";
6995     os << "TFEL_STATIC_ASSERT(tfel::typetraits::IsReal<Type>::cond);\n\n";
6996     os << "friend std::ostream& operator<< <>(std::ostream&,const ";
6997     os << this->mb.getClassName() << "IntegrationData&);\n\n";
6998   }
6999 
writeIntegrationDataOutputOperator(std::ostream & os,const Hypothesis h) const7000   void BehaviourDSLCommon::writeIntegrationDataOutputOperator(std::ostream& os, const Hypothesis h) const {
7001     const auto& md = this->mb.getBehaviourData(h);
7002     this->checkBehaviourFile(os);
7003     if (h == ModellingHypothesis::UNDEFINEDHYPOTHESIS) {
7004       if (this->mb.useQt()) {
7005         os << "template<ModellingHypothesis::Hypothesis hypothesis,typename Type,bool use_qt>\n";
7006         os << "std::ostream&\n";
7007         os << "operator <<(std::ostream& os,";
7008         os << "const " << this->mb.getClassName() << "IntegrationData<hypothesis,Type,use_qt>& b)\n";
7009       } else {
7010         os << "template<ModellingHypothesis::Hypothesis hypothesis,typename Type>\n";
7011         os << "std::ostream&\n";
7012         os << "operator <<(std::ostream& os,";
7013         os << "const " << this->mb.getClassName() << "IntegrationData<hypothesis,Type,false>& b)\n";
7014       }
7015     } else {
7016       if (this->mb.useQt()) {
7017         os << "template<typename Type,bool use_qt>\n";
7018         os << "std::ostream&\n";
7019         os << "operator <<(std::ostream& os,";
7020         os << "const " << this->mb.getClassName()
7021            << "IntegrationData<ModellingHypothesis::" << ModellingHypothesis::toUpperCaseString(h)
7022            << ",Type,use_qt>& b)\n";
7023       } else {
7024         os << "template<typename Type>\n";
7025         os << "std::ostream&\n";
7026         os << "operator <<(std::ostream& os,";
7027         os << "const " << this->mb.getClassName()
7028            << "IntegrationData<ModellingHypothesis::" << ModellingHypothesis::toUpperCaseString(h)
7029            << ",Type,false>& b)\n";
7030       }
7031     }
7032     os << "{\n";
7033     for (const auto& v : this->mb.getMainVariables()) {
7034       if (Gradient::isIncrementKnown(v.first)) {
7035         if (getUnicodeOutputOption()) {
7036           os << "os << \"\u0394" << displayName(v.first) << " : \" << b.d"
7037              << v.first.name << " << '\\n';\n";
7038         } else {
7039           os << "os << \"d" << displayName(v.first) << " : \" << b.d"
7040              << v.first.name << " << '\\n';\n";
7041         }
7042       } else {
7043         if (getUnicodeOutputOption()) {
7044           os << "os << \"" << displayName(v.first) << "\u2081 : \" << b."
7045              << v.first.name << "1 << '\\n';\n";
7046         } else {
7047           os << "os << \"" << displayName(v.first) << "1 : \" << b."
7048              << v.first.name << "1 << '\\n';\n";
7049         }
7050       }
7051       os << "os << \"" << displayName(v.second) << " : \" << b."
7052          << v.second.name << " << '\\n';\n";
7053     }
7054     if (getUnicodeOutputOption()) {
7055       os << "os << \"\u0394t : \" << b.dt << '\\n';\n";
7056     } else {
7057       os << "os << \"dt : \" << b.dt << '\\n';\n";
7058     }
7059     for (const auto& ev : md.getExternalStateVariables()) {
7060       if (getUnicodeOutputOption()) {
7061         os << "os << \"\u0394" << displayName(ev) << " : \" << b.d" << ev.name
7062            << " << '\\n';\n";
7063       } else {
7064         os << "os << \"d" << displayName(ev) << " : \" << b.d" << ev.name
7065            << " << '\\n';\n";
7066       }
7067     }
7068     os << "return os;\n";
7069     os << "}\n\n";
7070   }  // end of BehaviourDSLCommon::writeIntegrationDataOutputOperator
7071 
writeIntegrationDataClassEnd(std::ostream & os) const7072   void BehaviourDSLCommon::writeIntegrationDataClassEnd(std::ostream& os) const {
7073     this->checkIntegrationDataFile(os);
7074     os << "}; // end of " << this->mb.getClassName() << "IntegrationData"
7075        << "class\n\n";
7076   }
7077 
writeIntegrationDataExternalStateVariables(std::ostream & os,const Hypothesis h) const7078   void BehaviourDSLCommon::writeIntegrationDataExternalStateVariables(std::ostream& os, const Hypothesis h) const {
7079     const auto& md = this->mb.getBehaviourData(h);
7080     this->checkIntegrationDataFile(os);
7081     this->writeVariablesDeclarations(os, md.getExternalStateVariables(), "d", "", this->fd.fileName, false);
7082   }
7083 
writeIntegrationDataFileBegin(std::ostream & os) const7084   void BehaviourDSLCommon::writeIntegrationDataFileBegin(std::ostream& os) const {
7085     this->checkIntegrationDataFile(os);
7086     this->writeIntegrationDataFileHeader(os);
7087     this->writeIntegrationDataFileHeaderBegin(os);
7088     this->writeIntegrationDataStandardTFELIncludes(os);
7089     this->writeIncludes(os);
7090     // includes specific to interfaces
7091     for (const auto& i : this->interfaces) {
7092       i.second->writeInterfaceSpecificIncludes(os, this->mb);
7093     }
7094     this->writeNamespaceBegin(os);
7095     this->writeIntegrationDataForwardDeclarations(os);
7096   }  // end of BehaviourDSLCommon::writeIntegrationDataFile
7097 
writeIntegrationDataClass(std::ostream & os,const Hypothesis h) const7098   void BehaviourDSLCommon::writeIntegrationDataClass(std::ostream& os, const Hypothesis h) const {
7099     this->checkIntegrationDataFile(os);
7100     this->writeIntegrationDataClassBegin(os, h);
7101     this->writeIntegrationDataStandardTFELTypedefs(os);
7102     this->writeIntegrationDataDefaultMembers(os);
7103     this->writeIntegrationDataExternalStateVariables(os, h);
7104     this->writeIntegrationDataDisabledConstructors(os);
7105     os << "public:\n\n";
7106     this->writeIntegrationDataConstructors(os, h);
7107     this->writeIntegrationDataMainVariablesSetters(os);
7108     this->writeIntegrationDataScaleOperators(os, h);
7109     this->writeIntegrationDataUpdateDrivingVariablesMethod(os);
7110     this->writeIntegrationDataClassEnd(os);
7111     this->writeIntegrationDataOutputOperator(os, h);
7112   }
7113 
writeIntegrationDataFileEnd(std::ostream & os) const7114   void BehaviourDSLCommon::writeIntegrationDataFileEnd(std::ostream& os) const {
7115     this->checkIntegrationDataFile(os);
7116     this->writeNamespaceEnd(os);
7117     this->writeIntegrationDataFileHeaderEnd(os);
7118   }  // end of BehaviourDSLCommon::writeIntegrationDataFileEnd
7119 
checkSrcFile(std::ostream & os) const7120   void BehaviourDSLCommon::checkSrcFile(std::ostream& os) const {
7121     if ((!os) || (!os.good())) {
7122       this->throwRuntimeError("BehaviourDSLCommon::checkSrcFile", "output file is not valid");
7123     }
7124   }
7125 
writeSrcFileHeader(std::ostream & os) const7126   void BehaviourDSLCommon::writeSrcFileHeader(std::ostream& os) const {
7127     this->checkSrcFile(os);
7128     os << "/*!\n"
7129        << "* \\file   " << this->getSrcFileName() << '\n'
7130        << "* \\brief  "
7131        << "this file implements the " << this->mb.getClassName() << " Behaviour.\n"
7132        << "*         File generated by " << MFrontHeader::getVersionName() << " "
7133        << "version " << MFrontHeader::getVersionNumber() << '\n';
7134     if (!this->fd.authorName.empty()) {
7135       os << "* \\author " << this->fd.authorName << '\n';
7136     }
7137     if (!this->fd.date.empty()) {
7138       os << "* \\date   " << this->fd.date << '\n';
7139     }
7140     os << " */\n\n";
7141     if (this->mb.hasParameters()) {
7142       os << "#include<string>\n"
7143          << "#include<cstring>\n"
7144          << "#include<sstream>\n"
7145          << "#include<fstream>\n"
7146          << "#include<stdexcept>\n\n";
7147     }
7148     os << "#include\"TFEL/Raise.hxx\"\n"
7149        << "#include\"" << this->getBehaviourDataFileName() << "\"\n"
7150        << "#include\"" << this->getIntegrationDataFileName() << "\"\n"
7151        << "#include\"" << this->getBehaviourFileName() << "\"\n\n";
7152   }  // end of BehaviourDSLCommon::writeSrcFileHeader()
7153 
writeSrcFileStaticVariables(std::ostream & os,const Hypothesis h) const7154   void BehaviourDSLCommon::writeSrcFileStaticVariables(std::ostream& os, const Hypothesis h) const {
7155     const auto& md = this->mb.getBehaviourData(h);
7156     const auto m = "tfel::material::ModellingHypothesis::" + ModellingHypothesis::toUpperCaseString(h);
7157     this->checkSrcFile(os);
7158     for (const auto& v : md.getStaticVariables()) {
7159       if (v.type == "int") {
7160         continue;
7161       }
7162       if (this->mb.useQt()) {
7163         os << "template<>\n";
7164         os << "const " << this->mb.getClassName() << "<" << m << ",float,true>::" << v.type << '\n'
7165            << this->mb.getClassName() << "<" << m << ",float,true>::" << v.name << " = " << this->mb.getClassName()
7166            << "<" << m << ",float,true>::" << v.type << "(static_cast<float>(" << v.value << "));\n\n";
7167       }
7168       os << "template<>\n";
7169       os << "const " << this->mb.getClassName() << "<" << m << ",float,false>::" << v.type << '\n'
7170          << this->mb.getClassName() << "<" << m << ",float,false>::" << v.name << " = " << this->mb.getClassName()
7171          << "<" << m << ",float,false>::" << v.type << "(static_cast<float>(" << v.value << "));\n\n";
7172       if (this->mb.useQt()) {
7173         os << "template<>\n";
7174         os << "const " << this->mb.getClassName() << "<" << m << ",double,true>::" << v.type << '\n'
7175            << this->mb.getClassName() << "<" << m << ",double,true>::" << v.name << " = " << this->mb.getClassName()
7176            << "<" << m << ",double,true>::" << v.type << "(static_cast<double>(" << v.value << "));\n\n";
7177       }
7178       os << "template<>\n";
7179       os << "const " << this->mb.getClassName() << "<" << m << ",double,false>::" << v.type << '\n'
7180          << this->mb.getClassName() << "<" << m << ",double,false>::" << v.name << " = " << this->mb.getClassName()
7181          << "<" << m << ",double,false>::" << v.type << "(static_cast<double>(" << v.value << "));\n\n";
7182       if (this->mb.useQt()) {
7183         os << "template<>\n";
7184         os << "const " << this->mb.getClassName() << "<" << m << ",long double,true>::" << v.type << '\n'
7185            << this->mb.getClassName() << "<" << m << ",long double,true>::" << v.name << " = "
7186            << this->mb.getClassName() << "<" << m << ",long double,true>::" << v.type << "(static_cast<long double>("
7187            << v.value << "));\n\n";
7188       }
7189       os << "template<>\n";
7190       os << "const " << this->mb.getClassName() << "<" << m << ",long double,false>::" << v.type << '\n'
7191          << this->mb.getClassName() << "<" << m << ",long double,false>::" << v.name << " = " << this->mb.getClassName()
7192          << "<" << m << ",long double,false>::" << v.type << "(static_cast<long double>(" << v.value << "));\n\n";
7193     }
7194   }  // end of BehaviourDSLCommon::writeSrcFileStaticVariables
7195 
writeSrcFileUserDefinedCode(std::ostream & os) const7196   void BehaviourDSLCommon::writeSrcFileUserDefinedCode(std::ostream& os) const {
7197     this->checkSrcFile(os);
7198     const auto& s = this->mb.getSources();
7199     if (!s.empty()) {
7200       os << s << "\n\n";
7201     }
7202   }  // end of BehaviourDSLCommon::writeSrcFileUserDefinedCode
7203 
writeSrcFileParametersInitializers(std::ostream & os) const7204   void BehaviourDSLCommon::writeSrcFileParametersInitializers(std::ostream& os) const {
7205     if (!this->mb.hasParameters()) {
7206       return;
7207     }
7208     auto hs = this->mb.getDistinctModellingHypotheses();
7209     hs.insert(ModellingHypothesis::UNDEFINEDHYPOTHESIS);
7210     for (const auto& h : hs) {
7211       if (this->mb.hasParameters(h)) {
7212         this->writeSrcFileParametersInitializer(os, h);
7213       }
7214     }
7215   }  // end of BehaviourDSLCommon::writeSrcFileParametersInitializer
7216 
BehaviourDSLCommon_writeConverter(std::ostream & f,const std::string & cname,const std::string & type,const std::string & type2)7217   static void BehaviourDSLCommon_writeConverter(std::ostream& f,
7218                                                 const std::string& cname,
7219                                                 const std::string& type,
7220                                                 const std::string& type2) {
7221     f << type << '\n'
7222       << cname << "::get" << type2 << "(const std::string& n,\n"
7223       << "const std::string& v)\n"
7224       << "{\n"
7225       << type << " value;\n"
7226       << "std::istringstream converter(v);\n"
7227       << "converter >> value;\n"
7228       << "tfel::raise_if(!converter||(!converter.eof()),\n"
7229       << "\"" << cname << "::get" << type2 << ": \"\n"
7230       << "\"can't convert '\"+v+\"' to " << type << " "
7231       << "for parameter '\"+ n+\"'\");\n"
7232       << "return value;\n"
7233       << "}\n\n";
7234   }
7235 
writeSrcFileParametersInitializer(std::ostream & os,const Hypothesis h) const7236   void BehaviourDSLCommon::writeSrcFileParametersInitializer(std::ostream& os, const Hypothesis h) const {
7237     this->checkBehaviourFile(os);
7238     // treating the default case
7239     bool rp = false;   // real    parameter found
7240     bool ip = false;   // integer parameter found
7241     bool up = false;   // unsigned short parameter found
7242     bool rp2 = false;  // real    parameter found
7243     bool ip2 = false;  // integer parameter found
7244     bool up2 = false;  // unsigned short parameter found
7245     std::string cname(this->mb.getClassName());
7246     if (h != ModellingHypothesis::UNDEFINEDHYPOTHESIS) {
7247       cname += ModellingHypothesis::toString(h);
7248     }
7249     cname += "ParametersInitializer";
7250     std::string dcname(this->mb.getClassName() + "ParametersInitializer");
7251     os << cname << "&\n"
7252        << cname << "::get()\n"
7253        << "{\n"
7254        << "static " << cname << " i;\n"
7255        << "return i;\n"
7256        << "}\n\n";
7257     os << cname << "::" << cname << "()\n"
7258        << "{\n";
7259     for (const auto& p : this->mb.getBehaviourData(h).getParameters()) {
7260       if (p.type == "int") {
7261         ip = true;
7262         if ((h == ModellingHypothesis::UNDEFINEDHYPOTHESIS) ||
7263             ((h != ModellingHypothesis::UNDEFINEDHYPOTHESIS) &&
7264              (!this->mb.hasParameter(ModellingHypothesis::UNDEFINEDHYPOTHESIS, p.name)))) {
7265           ip2 = true;
7266           os << "this->" << p.name << " = " << this->mb.getIntegerParameterDefaultValue(h, p.name) << ";\n";
7267         }
7268       } else if (p.type == "ushort") {
7269         up = true;
7270         if ((h == ModellingHypothesis::UNDEFINEDHYPOTHESIS) ||
7271             ((h != ModellingHypothesis::UNDEFINEDHYPOTHESIS) &&
7272              (!this->mb.hasParameter(ModellingHypothesis::UNDEFINEDHYPOTHESIS, p.name)))) {
7273           up2 = true;
7274           os << "this->" << p.name << " = " << this->mb.getUnsignedShortParameterDefaultValue(h, p.name) << ";\n";
7275         }
7276       } else {
7277         const auto f = SupportedTypes::getTypeFlag(p.type);
7278         if (f != SupportedTypes::SCALAR) {
7279           this->throwRuntimeError("BehaviourDSLCommon::writeSrcFileParametersInitializer",
7280                                   "unsupported parameter type '" + p.type +
7281                                       "' "
7282                                       "for parameter '" +
7283                                       p.name + "'");
7284         }
7285         rp = true;
7286         if ((h == ModellingHypothesis::UNDEFINEDHYPOTHESIS) ||
7287             ((h != ModellingHypothesis::UNDEFINEDHYPOTHESIS) &&
7288              (!this->mb.hasParameter(ModellingHypothesis::UNDEFINEDHYPOTHESIS, p.name)))) {
7289           rp2 = true;
7290           if (p.arraySize == 1u) {
7291             os << "this->" << p.name << " = " << this->mb.getFloattingPointParameterDefaultValue(h, p.name) << ";\n";
7292           } else {
7293             for (unsigned short i = 0; i != p.arraySize; ++i) {
7294               os << "this->" << p.name << "[" << i
7295                  << "] = " << this->mb.getFloattingPointParameterDefaultValue(h, p.name, i) << ";\n";
7296             }
7297           }
7298         }
7299       }
7300     }
7301     os << "// Reading parameters from a file\n";
7302     os << cname << "::readParameters(*this,\"" << getParametersFileName(this->mb)
7303        << "\");\n";
7304     if (h != ModellingHypothesis::UNDEFINEDHYPOTHESIS) {
7305       os << cname << "::readParameters(*this,\""
7306          << getParametersFileName(this->mb, h) << "\");\n";
7307     }
7308     os << "}\n\n";
7309     auto write_if = [&os](bool& b) {
7310       if (b) {
7311         os << "if(";
7312         b = false;
7313       } else {
7314         os << "} else if(";
7315       }
7316     };
7317     if (rp) {
7318       os << "void\n"
7319          << cname << "::set(const char* const key,\nconst double v)"
7320          << "{\n"
7321          << "using namespace std;\n";
7322       bool first = true;
7323       for (const auto& p : this->mb.getBehaviourData(h).getParameters()) {
7324         if ((p.type == "int") || (p.type == "ushort")) {
7325           continue;
7326         }
7327         const auto f = SupportedTypes::getTypeFlag(p.type);
7328         if (f != SupportedTypes::SCALAR) {
7329           this->throwRuntimeError("BehaviourDSLCommon::writeSrcFileParametersInitializer",
7330                                   "unsupported parameter type '" + p.type +
7331                                       "' "
7332                                       "for parameter '" +
7333                                       p.name + "'");
7334         }
7335         if (p.arraySize == 1u) {
7336           write_if(first);
7337           os << "::strcmp(\"" + this->mb.getExternalName(h, p.name) + "\",key)==0){\n";
7338           if ((h == ModellingHypothesis::UNDEFINEDHYPOTHESIS) ||
7339               ((h != ModellingHypothesis::UNDEFINEDHYPOTHESIS) &&
7340                (!this->mb.hasParameter(ModellingHypothesis::UNDEFINEDHYPOTHESIS, p.name)))) {
7341             os << "this->" << p.name << " = v;\n";
7342           } else {
7343             os << dcname << "::get().set(\"" << this->mb.getExternalName(h, p.name) << "\",v);\n";
7344           }
7345         } else {
7346           for (unsigned short i = 0; i != p.arraySize; ++i) {
7347             write_if(first);
7348             const auto vn = p.name + '[' + std::to_string(i) + ']';
7349             const auto en = this->mb.getExternalName(h, p.name) + '[' + std::to_string(i) + ']';
7350             os << "::strcmp(\"" + en + "\",key)==0){\n";
7351             if ((h == ModellingHypothesis::UNDEFINEDHYPOTHESIS) ||
7352                 ((h != ModellingHypothesis::UNDEFINEDHYPOTHESIS) &&
7353                  (!this->mb.hasParameter(ModellingHypothesis::UNDEFINEDHYPOTHESIS, p.name)))) {
7354               os << "this->" << vn << " = v;\n";
7355             } else {
7356               os << dcname << "::get().set(\"" << en << "\",v);\n";
7357             }
7358           }
7359         }
7360       }
7361       os << "} else {\n";
7362       os << "tfel::raise(\"" << cname << "::set: \"\n"
7363          << "\" no parameter named "
7364          << "'\"+std::string(key)+\"'\");\n"
7365          << "}\n"
7366          << "}\n\n";
7367     }
7368     if (ip) {
7369       os << "void\n"
7370          << cname << "::set(const char* const key,\nconst int v)"
7371          << "{\n"
7372          << "using namespace std;\n";
7373       bool first = true;
7374       for (const auto& p : this->mb.getBehaviourData(h).getParameters()) {
7375         if (p.type == "int") {
7376           write_if(first);
7377           os << "::strcmp(\"" + this->mb.getExternalName(h, p.name) + "\",key)==0){\n";
7378           if ((h == ModellingHypothesis::UNDEFINEDHYPOTHESIS) ||
7379               ((h != ModellingHypothesis::UNDEFINEDHYPOTHESIS) &&
7380                (!this->mb.hasParameter(ModellingHypothesis::UNDEFINEDHYPOTHESIS, p.name)))) {
7381             os << "this->" << p.name << " = v;\n";
7382           } else {
7383             os << dcname << "::get().set(\"" << this->mb.getExternalName(h, p.name) << "\",v);\n";
7384           }
7385         }
7386       }
7387       os << "} else {\n";
7388       os << "tfel::raise(\"" << cname << "::set: \"\n"
7389          << "\"no parameter named "
7390          << "'\"+std::string(key)+\"'\");\n"
7391          << "}\n"
7392          << "}\n\n";
7393     }
7394     if (up) {
7395       os << "void\n"
7396          << cname << "::set(const char* const key,\nconst unsigned short v)"
7397          << "{\n"
7398          << "using namespace std;\n";
7399       bool first = true;
7400       for (const auto& p : this->mb.getBehaviourData(h).getParameters()) {
7401         if (p.type == "ushort") {
7402           write_if(first);
7403           os << "::strcmp(\"" + this->mb.getExternalName(h, p.name) + "\",key)==0){\n";
7404           if ((h == ModellingHypothesis::UNDEFINEDHYPOTHESIS) ||
7405               ((h != ModellingHypothesis::UNDEFINEDHYPOTHESIS) &&
7406                (!this->mb.hasParameter(ModellingHypothesis::UNDEFINEDHYPOTHESIS, p.name)))) {
7407             os << "this->" << p.name << " = v;\n";
7408           } else {
7409             os << dcname << "::get().set(\"" << this->mb.getExternalName(h, p.name) << "\",v);\n";
7410           }
7411         }
7412       }
7413       os << "} else {\n";
7414       os << "tfel::raise(\"" << cname << "::set: \"\n"
7415          << "\"no parameter named '\"+std::string(key)+\"'\");\n"
7416          << "}\n"
7417          << "}\n\n";
7418     }
7419     if (rp2) {
7420       BehaviourDSLCommon_writeConverter(os, cname, "double", "Double");
7421     }
7422     if (ip2) {
7423       BehaviourDSLCommon_writeConverter(os, cname, "int", "Int");
7424     }
7425     if (up2) {
7426       BehaviourDSLCommon_writeConverter(os, cname, "unsigned short", "UnsignedShort");
7427     }
7428     os << "void\n" << cname << "::readParameters(" << cname << "&";
7429     if (rp2 || ip2 || up2) {
7430       os << " pi";
7431     }
7432     os << ",const char* const fn)"
7433        << "{\n"
7434        << "auto tokenize = [](const std::string& line){\n"
7435        << "std::istringstream tokenizer(line);\n"
7436        << "std::vector<std::string> tokens;\n"
7437        << "std::copy(std::istream_iterator<std::string>(tokenizer),\n"
7438        << "std::istream_iterator<std::string>(),\n"
7439        << "std::back_inserter(tokens));\n"
7440        << "return tokens;\n"
7441        << "};\n"
7442        << "std::ifstream f(fn);\n"
7443        << "if(!f){\n"
7444        << "return;\n"
7445        << "}\n"
7446        << "size_t ln = 1u;\n"
7447        << "while(!f.eof()){\n"
7448        << "auto line = std::string{};\n"
7449        << "std::getline(f,line);\n"
7450        << "auto tokens = tokenize(line);\n"
7451        << "auto throw_if = [ln,line,fn](const bool c,const std::string& m){\n"
7452        << "tfel::raise_if(c,\"" << cname << "::readParameters: \"\n"
7453        << "\"error at line '\"+std::to_string(ln)+\"' \"\n"
7454        << "\"while reading parameter file '\"+std::string(fn)+\"'\"\n"
7455        << "\"(\"+m+\")\");\n"
7456        << "};\n"
7457        << "if(tokens.empty()){\n"
7458        << "continue;\n"
7459        << "}\n"
7460        << "if(tokens[0][0]=='#'){\n"
7461        << "continue;\n"
7462        << "}\n"
7463        << "throw_if(tokens.size()!=2u,\"invalid number of tokens\");\n";
7464     bool first = true;
7465     for (const auto& p : this->mb.getBehaviourData(h).getParameters()) {
7466       const auto b = ((h == ModellingHypothesis::UNDEFINEDHYPOTHESIS) ||
7467                       ((h != ModellingHypothesis::UNDEFINEDHYPOTHESIS) &&
7468                        (!this->mb.hasParameter(ModellingHypothesis::UNDEFINEDHYPOTHESIS, p.name))));
7469       auto write = [this, &os, &p, &b, &dcname, &cname](const std::string& vn, const std::string& en) {
7470         os << "\"" << en << "\"==tokens[0]){\n";
7471         if (b) {
7472           os << "pi." << vn << " = ";
7473           if (p.type == "int") {
7474             os << cname << "::getInt(tokens[0],tokens[1]);\n";
7475           } else if (p.type == "ushort") {
7476             os << cname << "::getUnsignedShort(tokens[0],tokens[1]);\n";
7477           } else {
7478             const auto f = SupportedTypes::getTypeFlag(p.type);
7479             if (f != SupportedTypes::SCALAR) {
7480               this->throwRuntimeError("BehaviourDSLCommon::writeSrcFileParametersInitializer",
7481                                       "invalid parameter type '" + p.type + "'");
7482             }
7483             os << cname << "::getDouble(tokens[0],tokens[1]);\n";
7484           }
7485         } else {
7486           os << dcname << "::get().set(\"" << en << "\",\n";
7487           if (p.type == "int") {
7488             os << dcname << "::getInt(tokens[0],tokens[1])";
7489           } else if (p.type == "ushort") {
7490             os << dcname << "::getUnsignedShort(tokens[0],tokens[1])";
7491           } else {
7492             const auto f = SupportedTypes::getTypeFlag(p.type);
7493             if (f != SupportedTypes::SCALAR) {
7494               this->throwRuntimeError("BehaviourDSLCommon::writeSrcFileParametersInitializer",
7495                                       "invalid parameter type '" + p.type + "'");
7496             }
7497             os << dcname << "::getDouble(tokens[0],tokens[1])";
7498           }
7499           os << ");\n";
7500         }
7501       };
7502       if (p.arraySize == 1u) {
7503         write_if(first);
7504         write(p.name, this->mb.getExternalName(h, p.name));
7505       } else {
7506         for (unsigned short i = 0; i != p.arraySize; ++i) {
7507           const auto vn = p.name + '[' + std::to_string(i) + ']';
7508           const auto en = this->mb.getExternalName(h, p.name) + '[' + std::to_string(i) + ']';
7509           write_if(first);
7510           write(vn, en);
7511         }
7512       }
7513     }
7514     os << "} else {\n"
7515        << "throw_if(true,\"invalid parameter '\"+tokens[0]+\"'\");\n"
7516        << "}\n"
7517        << "}\n"
7518        << "}\n\n";
7519   }  // end of BehaviourDSLCommon::writeSrcFileParametersInitializer
7520 
writeSrcFileBehaviourProfiler(std::ostream & os) const7521   void BehaviourDSLCommon::writeSrcFileBehaviourProfiler(std::ostream& os) const {
7522     if (this->mb.getAttribute(BehaviourData::profiling, false)) {
7523       this->checkSrcFile(os);
7524       os << "mfront::BehaviourProfiler&\n"
7525          << this->mb.getClassName() << "Profiler::getProfiler()\n"
7526          << "{\n"
7527          << "static mfront::BehaviourProfiler profiler(\"" << this->mb.getClassName() << "\");\n;"
7528          << "return profiler;\n"
7529          << "}\n\n";
7530     }
7531   }  // end of BehaviourDSLCommon::writeSrcFileBehaviourProfiler
7532 
writeSrcFile(std::ostream & os) const7533   void BehaviourDSLCommon::writeSrcFile(std::ostream& os) const {
7534     this->writeSrcFileHeader(os);
7535     this->writeSrcFileUserDefinedCode(os);
7536     this->writeNamespaceBegin(os);
7537     this->writeSrcFileBehaviourProfiler(os);
7538     this->writeSrcFileParametersInitializers(os);
7539     // modelling hypotheses handled by the behaviour
7540     const auto& mh = this->mb.getModellingHypotheses();
7541     for (const auto& h : mh) {
7542       this->writeSrcFileStaticVariables(os, h);
7543     }
7544     this->writeNamespaceEnd(os);
7545   }  // end of BehaviourDSLCommon::writeSrcFile
7546 
predictionOperatorVariableModifier(const Hypothesis h,const std::string & var,const bool addThisPtr)7547   std::string BehaviourDSLCommon::predictionOperatorVariableModifier(const Hypothesis h,
7548                                                                      const std::string& var,
7549                                                                      const bool addThisPtr) {
7550     if (this->mb.isIntegrationVariableIncrementName(h, var)) {
7551       this->throwRuntimeError("BehaviourDSLCommon::predictionOperatorVariableModifier : ",
7552                               "integration variable '" + var + "' can't be used in @PredictionOperator");
7553     }
7554     if (addThisPtr) {
7555       return "(this->" + var + ")";
7556     }
7557     return var;
7558   }  // end of BehaviourDSLCommon::predictionOperatorVariableModifier
7559 
treatProfiling()7560   void BehaviourDSLCommon::treatProfiling() {
7561     const auto b = this->readBooleanValue("BehaviourDSLCommon::treatProfiling");
7562     this->readSpecifiedToken("BehaviourDSLCommon::treatProfiling", ";");
7563     this->mb.setAttribute(BehaviourData::profiling, b, false);
7564   }  // end of BehaviourDSLCommon::treatProfiling
7565 
treatPredictionOperator()7566   void BehaviourDSLCommon::treatPredictionOperator() {
7567     using namespace std;
7568     using namespace tfel::material;
7569     using namespace tfel::utilities;
7570     CodeBlockOptions o;
7571     this->readCodeBlockOptions(o, true);
7572     if (this->mb.getBehaviourType() == BehaviourDescription::STANDARDFINITESTRAINBEHAVIOUR) {
7573       bool found = false;
7574       if (o.untreated.size() != 1u) {
7575         ostringstream msg;
7576         msg << "tangent operator type is undefined. Valid tanget operator type are :\n";
7577         for (const auto& to : getFiniteStrainBehaviourTangentOperatorFlags()) {
7578           msg << "- " << convertFiniteStrainBehaviourTangentOperatorFlagToString(to) << " : "
7579               << getFiniteStrainBehaviourTangentOperatorDescription(to) << '\n';
7580         }
7581         this->throwRuntimeError("BehaviourDSLCommon::treatPredictionOperator", msg.str());
7582       }
7583       if (o.untreated[0].flag != Token::Standard) {
7584         this->throwRuntimeError("BehaviourDSLCommon::treatPredictionOperator",
7585                                 "invalid option '" + o.untreated[0].value + "'");
7586       }
7587       const auto& ktype = o.untreated[0].value;
7588       for (const auto& to : getFiniteStrainBehaviourTangentOperatorFlags()) {
7589         if (ktype == convertFiniteStrainBehaviourTangentOperatorFlagToString(to)) {
7590           found = true;
7591           break;
7592         }
7593       }
7594       if (!found) {
7595         ostringstream msg;
7596         msg << "invalid tangent operator type '" + ktype + "'. Valid tanget operator type are :\n";
7597         for (const auto& to : getFiniteStrainBehaviourTangentOperatorFlags()) {
7598           msg << "- " << convertFiniteStrainBehaviourTangentOperatorFlagToString(to) << " : "
7599               << getFiniteStrainBehaviourTangentOperatorDescription(to) << '\n';
7600         }
7601         this->throwRuntimeError("BehaviourDSLCommon::treatPredictionOperator", msg.str());
7602       }
7603       const auto po = std::string(BehaviourData::ComputePredictionOperator) + "-" + ktype;
7604       this->readCodeBlock(*this, o, po, &BehaviourDSLCommon::predictionOperatorVariableModifier, true);
7605       for (const auto& h : o.hypotheses) {
7606         if (!this->mb.hasAttribute(h, BehaviourData::hasPredictionOperator)) {
7607           this->mb.setAttribute(h, BehaviourData::hasPredictionOperator, true);
7608         }
7609       }
7610     } else {
7611       this->treatUnsupportedCodeBlockOptions(o);
7612       this->readCodeBlock(*this, o, BehaviourData::ComputePredictionOperator,
7613                           &BehaviourDSLCommon::predictionOperatorVariableModifier, true);
7614       for (const auto& h : o.hypotheses) {
7615         this->mb.setAttribute(h, BehaviourData::hasPredictionOperator, true);
7616       }
7617     }
7618   }  // end of BehaviourDSLCommon::treatPredictionOperator
7619 
treatParameter()7620   void BehaviourDSLCommon::treatParameter() {
7621     auto throw_if = [this](const bool b, const std::string& m) {
7622       if (b) {
7623         this->throwRuntimeError("BehaviourDSLCommon::treatParameter", m);
7624       }
7625     };
7626     std::set<Hypothesis> mh;
7627     this->readHypothesesList(mh);
7628     auto endOfTreatment = false;
7629     while ((this->current != this->tokens.end()) && (!endOfTreatment)) {
7630       const auto vtype = [this, throw_if]() -> std::string {
7631         const auto v = this->current->value;
7632         if (SupportedTypes::isSupportedType(v)) {
7633           throw_if(SupportedTypes::getTypeFlag(v) != SupportedTypes::SCALAR,
7634                    "invalid parameter type");
7635           ++(this->current);
7636           return v;
7637         }
7638         return "real";
7639       }();
7640       this->checkNotEndOfFile("BehaviourDSLCommon::treatParameter");
7641       const auto sname = this->current->value;
7642       const auto vname = tfel::unicode::getMangledString(sname);
7643       throw_if(!isValidIdentifier(vname),
7644                "variable given is not valid (read "
7645                "'" +
7646                    sname + "').");
7647       const auto lineNumber = this->current->line;
7648       ++(this->current);
7649       this->checkNotEndOfFile("BehaviourDSLCommon::treatParameter");
7650       const auto arraySize = this->readArrayOfVariablesSize(sname, true);
7651       this->checkNotEndOfFile("BehaviourDSLCommon::treatParameter");
7652       if ((this->current->value == "=") || (this->current->value == "{") ||
7653           (this->current->value == "(")) {
7654         std::string ci;  // closing initializer
7655         if (this->current->value == "{") {
7656           ci = "}";
7657         }
7658         if (this->current->value == "(") {
7659           throw_if(arraySize != 1u,
7660                    "invalid initalisation syntax for "
7661                    "the default values of an array of parameters.\n"
7662                    "Unexpected token '" +
7663                        current->value + "'");
7664           ci = ")";
7665         }
7666         ++(this->current);
7667         this->checkNotEndOfFile("BehaviourDSLCommon::treatParameter");
7668         if (arraySize != 1u) {
7669           if (ci != "}") {
7670             this->readSpecifiedToken("BehaviourDSLCommon::treatParameter", "{");
7671           }
7672           --(this->current);
7673           const auto r = this->readArrayOfDouble("BehaviourDSLCommon::treatParameter");
7674           throw_if(
7675               r.size() != arraySize,
7676               "number of values given does not match the numberf of parameters "
7677               "(" +
7678                   std::to_string(r.size()) + " vs +" +
7679                   std::to_string(arraySize) + ").\n");
7680           for (const auto& h : mh) {
7681             VariableDescription p;
7682             if (vname == sname) {
7683               p = VariableDescription(vtype, vname, arraySize, lineNumber);
7684             } else {
7685               p = VariableDescription(vtype, sname, vname, arraySize,
7686                                       lineNumber);
7687             }
7688             p.description = this->currentComment;
7689             this->mb.addParameter(h, p);
7690             for (decltype(r.size()) i = 0; i != r.size(); ++i) {
7691               this->mb.setParameterDefaultValue(h, vname, i, r[i]);
7692             }
7693           }
7694         } else {
7695           double value;
7696           std::istringstream converter(this->current->value);
7697           converter >> value;
7698           if (!converter || (!converter.eof())) {
7699             this->throwRuntimeError(
7700                 "BehaviourDSLCommon::treatParameter",
7701                 "could not read default value for parameter '" + sname + "'");
7702           }
7703           ++(this->current);
7704           this->checkNotEndOfFile("BehaviourDSLCommon::treatParameter");
7705           if (!ci.empty()) {
7706             this->readSpecifiedToken("BehaviourDSLCommon::treatParameter", ci);
7707           }
7708           for (const auto& h : mh) {
7709             VariableDescription p;
7710             if (vname == sname) {
7711               p = VariableDescription(vtype, vname, 1u, lineNumber);
7712             } else {
7713               p = VariableDescription(vtype, sname, vname, 1u, lineNumber);
7714             }
7715             p.description = this->currentComment;
7716             this->mb.addParameter(h, p);
7717             this->mb.setParameterDefaultValue(h, vname, value);
7718           }
7719         }
7720       } else {
7721         throw_if(arraySize != 1,
7722                  "default values of parameters array "
7723                  "must be defined with the array. "
7724                  "Unexpected token '" +
7725                      current->value + "'");
7726         for (const auto& h : mh) {
7727           VariableDescription p;
7728           if (vname == sname) {
7729             p = VariableDescription(vtype, vname, 1u, lineNumber);
7730           } else {
7731             p = VariableDescription(vtype, sname, vname, 1u, lineNumber);
7732           }
7733           p.description = this->currentComment;
7734           this->mb.addParameter(h, p);
7735         }
7736       }
7737       if (this->current->value == ",") {
7738         ++(this->current);
7739       } else if (this->current->value == ";") {
7740         endOfTreatment = true;
7741         ++(this->current);
7742       } else {
7743         throw_if(true, "',' or ';' expected after '" + sname + "', read '" +
7744                            this->current->value + "'");
7745       }
7746     }
7747     if (!endOfTreatment) {
7748       --(this->current);
7749       throw_if(true, "expected ';' before end of file");
7750     }
7751   }  // end of BehaviourDSLCommon::treatParameter
7752 
treatInitLocalVariables()7753   void BehaviourDSLCommon::treatInitLocalVariables() {
7754     this->readCodeBlock(*this, BehaviourData::InitializeLocalVariables,
7755                         &BehaviourDSLCommon::standardModifier, true, true);
7756   }  // end of BehaviourDSLCommon:treatInitLocalVariables
7757 
treatMinimalTimeStepScalingFactor()7758   void BehaviourDSLCommon::treatMinimalTimeStepScalingFactor() {
7759     const auto h = ModellingHypothesis::UNDEFINEDHYPOTHESIS;
7760     double r_dt;
7761     this->checkNotEndOfFile("BehaviourDSLCommon::treatMinimalTimeStepScalingFactor", "Cannot read value.");
7762     std::istringstream flux(current->value);
7763     flux >> r_dt;
7764     if ((flux.fail()) || (!flux.eof())) {
7765       this->throwRuntimeError("BehaviourDSLCommon::treatMinimalTimeStepScalingFactor", "Failed to read value.");
7766     }
7767     if (r_dt < 10 * std::numeric_limits<double>::min()) {
7768       this->throwRuntimeError("BehaviourDSLCommon::treatMinimalTimeStepScalingFactor",
7769                               "minimal time step scaling factor either too "
7770                               "low value or negative.");
7771     }
7772     ++(this->current);
7773     this->readSpecifiedToken("BehaviourDSLCommon::treatMinimalTimeStepScalingFactor", ";");
7774     VariableDescription e("real", "minimal_time_step_scaling_factor", 1u, 0u);
7775     e.description = "minimal value for the time step scaling factor";
7776     this->mb.addParameter(h, e, BehaviourData::ALREADYREGISTRED);
7777     this->mb.setParameterDefaultValue(h, "minimal_time_step_scaling_factor", r_dt);
7778     this->mb.setEntryName(h, "minimal_time_step_scaling_factor", "minimal_time_step_scaling_factor");
7779   }  // end of BehaviourDSLCommon::treatMinimalTimeStepScalingFactor
7780 
treatMaximalTimeStepScalingFactor()7781   void BehaviourDSLCommon::treatMaximalTimeStepScalingFactor() {
7782     const auto h = ModellingHypothesis::UNDEFINEDHYPOTHESIS;
7783     double r_dt;
7784     this->checkNotEndOfFile("BehaviourDSLCommon::treatMaximalTimeStepScalingFactor", "Cannot read value.");
7785     std::istringstream flux(current->value);
7786     flux >> r_dt;
7787     if ((flux.fail()) || (!flux.eof())) {
7788       this->throwRuntimeError("BehaviourDSLCommon::treatMaximalTimeStepScalingFactor", "Failed to read value.");
7789     }
7790     if (r_dt < 1) {
7791       this->throwRuntimeError("BehaviourDSLCommon::treatMaximalTimeStepScalingFactor",
7792                               "maximal time step scaling factor value either too "
7793                               "low or negative.");
7794     }
7795     ++(this->current);
7796     this->readSpecifiedToken("BehaviourDSLCommon::treatMaximalTimeStepScalingFactor", ";");
7797     VariableDescription e("real", "maximal_time_step_scaling_factor", 1u, 0u);
7798     e.description = "maximal value for the time step scaling factor";
7799     this->mb.addParameter(h, e, BehaviourData::ALREADYREGISTRED);
7800     this->mb.setParameterDefaultValue(h, "maximal_time_step_scaling_factor", r_dt);
7801     this->mb.setEntryName(h, "maximal_time_step_scaling_factor", "maximal_time_step_scaling_factor");
7802   }  // end of BehaviourDSLCommon::treatMaximalTimeStepScalingFactor
7803 
setMinimalTangentOperator()7804   void BehaviourDSLCommon::setMinimalTangentOperator() {
7805     if (this->mb.getBehaviourType() != BehaviourDescription::STANDARDFINITESTRAINBEHAVIOUR) {
7806       for (const auto& h : this->mb.getDistinctModellingHypotheses()) {
7807         // basic check
7808         if (this->mb.hasAttribute(h, BehaviourData::hasConsistentTangentOperator)) {
7809           if (!this->mb.hasCode(h, BehaviourData::ComputeTangentOperator)) {
7810             this->throwRuntimeError("BehaviourDSLCommon::setMinimalTangentOperator",
7811                                     "behaviour has attribute 'hasConsistentTangentOperator' but "
7812                                     "no associated code");
7813           }
7814         }
7815       }
7816       if (this->mb.getAttribute(BehaviourDescription::requiresStiffnessTensor, false)) {
7817         if (this->mb.getBehaviourType() == BehaviourDescription::STANDARDSTRAINBASEDBEHAVIOUR) {
7818           const auto h = ModellingHypothesis::UNDEFINEDHYPOTHESIS;
7819           // if the user provided a tangent operator, it won't be
7820           // overriden
7821 
7822           CodeBlock tangentOperator;
7823           std::ostringstream code;
7824           code << "if(smt==ELASTIC){\n"
7825                << "this->Dt = this->D;\n"
7826                << "} else {\n"
7827                << "return false;\n"
7828                << "}\n";
7829           tangentOperator.code = code.str();
7830           this->mb.setCode(h, BehaviourData::ComputeTangentOperator, tangentOperator,
7831                            BehaviourData::CREATEBUTDONTREPLACE, BehaviourData::BODY);
7832           this->mb.setAttribute(h, BehaviourData::hasConsistentTangentOperator, true, true);
7833         }
7834       }
7835     }
7836   }  // end of BehaviourDSLCommon::setMinimalTangentOperator
7837 
treatInternalEnergy()7838   void BehaviourDSLCommon::treatInternalEnergy() {
7839     this->readCodeBlock(*this, BehaviourData::ComputeInternalEnergy, &BehaviourDSLCommon::standardModifier, true, true);
7840   }  // end of BehaviourDSLCommon::treatInternalEnergy
7841 
treatDissipatedEnergy()7842   void BehaviourDSLCommon::treatDissipatedEnergy() {
7843     this->readCodeBlock(*this, BehaviourData::ComputeDissipatedEnergy, &BehaviourDSLCommon::standardModifier, true,
7844                         true);
7845   }  // end of BehaviourDSLCommon::treatDissipatedEnergy
7846 
readSlipSystem(BehaviourDSLCommon::CxxTokenizer::const_iterator & p,const BehaviourDSLCommon::CxxTokenizer::const_iterator pe)7847   static BehaviourDescription::SlipSystem readSlipSystem(BehaviourDSLCommon::CxxTokenizer::const_iterator& p,
7848                                                          const BehaviourDSLCommon::CxxTokenizer::const_iterator pe) {
7849     using tfel::utilities::CxxTokenizer;
7850     using tfel::material::SlipSystemsDescription;
7851     auto throw_if = [](const bool c, const std::string& msg) { tfel::raise_if(c, "readSlipSystem: " + msg); };
7852     const auto direction = CxxTokenizer::readList("readSlipSystem", "<", ">", p, pe);
7853     const auto plane = CxxTokenizer::readList("readSlipSystem", "{", "}", p, pe);
7854     throw_if(plane.size() != direction.size(), "plane and direction don't match in size");
7855     throw_if((plane.size() != 3u) && (plane.size() != 4u),
7856              "invalid definition of a plane "
7857              "(must be an array of 3 or 4 integers, read '" +
7858                  std::to_string(plane.size()) + "' values)");
7859     if (plane.size() == 3u) {
7860       SlipSystemsDescription::system3d s3d;
7861       for (tfel::math::tvector<3u, int>::size_type i = 0; i != 3; ++i) {
7862         s3d.plane[i] = std::stoi(plane[i].value);
7863         s3d.burgers[i] = std::stoi(direction[i].value);
7864       }
7865       return {s3d};
7866     }
7867     SlipSystemsDescription::system4d s4d;
7868     for (tfel::math::tvector<4u, int>::size_type i = 0; i != 4; ++i) {
7869       s4d.plane[i] = std::stoi(plane[i].value);
7870       s4d.burgers[i] = std::stoi(direction[i].value);
7871     }
7872     return {s4d};
7873   }
7874 
treatSlipSystem()7875   void BehaviourDSLCommon::treatSlipSystem() {
7876     const auto s = readSlipSystem(this->current, this->tokens.end());
7877     this->mb.setSlipSystems({1u, s});
7878     this->readSpecifiedToken("BehaviourDSLCommon::treatSlipSystem", ";");
7879   }  // end of BehaviourDescription::treatSlipSystem()
7880 
treatSlipSystems()7881   void BehaviourDSLCommon::treatSlipSystems() {
7882     const std::string m = "BehaviourDSLCommon::treatSlipSystems";
7883     std::vector<BehaviourDescription::SlipSystem> ss;
7884     this->readSpecifiedToken(m, "{");
7885     this->checkNotEndOfFile(m, "expected token");
7886     while (this->current->value != "}") {
7887       this->checkNotEndOfFile(m, "expected slip system");
7888       ss.push_back(readSlipSystem(this->current, this->tokens.end()));
7889       this->checkNotEndOfFile(m, "expected ',' or '}'");
7890       if (this->current->value != "}") {
7891         this->readSpecifiedToken(m, ",");
7892         this->checkNotEndOfFile(m, "expected slip system");
7893         if (this->current->value == "}") {
7894           this->throwRuntimeError(m, "unexpected token '}'");
7895         }
7896       }
7897     }
7898     this->readSpecifiedToken(m, "}");
7899     this->readSpecifiedToken(m, ";");
7900     this->mb.setSlipSystems(ss);
7901   }  // end of BehaviourDSLCommon::treatSlipSystems
7902 
treatCrystalStructure()7903   void BehaviourDSLCommon::treatCrystalStructure() {
7904     using tfel::material::CrystalStructure;
7905     this->checkNotEndOfFile("BehaviourDSLCommon::treatCrystalStructure", "expected crystal structure");
7906     if (this->current->value == "Cubic") {
7907       this->mb.setCrystalStructure(CrystalStructure::Cubic);
7908     } else if (this->current->value == "FCC") {
7909       this->mb.setCrystalStructure(CrystalStructure::FCC);
7910     } else if (this->current->value == "BCC") {
7911       this->mb.setCrystalStructure(CrystalStructure::BCC);
7912     } else if (this->current->value == "HCP") {
7913       this->mb.setCrystalStructure(CrystalStructure::HCP);
7914     } else {
7915       this->throwRuntimeError("BehaviourDSLCommon::treatCrystalStructure",
7916                               "unsupported crystal structure "
7917                               "'" +
7918                                   this->current->value + "'");
7919     }
7920     ++(this->current);
7921     this->readSpecifiedToken("BehaviourDSLCommon::treatCrystalStructure", ";");
7922   }  // end of BehaviourDSLCommon::treatCrystalStructure
7923 
treatInteractionMatrix()7924   void BehaviourDSLCommon::treatInteractionMatrix() {
7925     auto throw_if = [this](const bool b, const std::string& m) {
7926       if (b) {
7927         this->throwRuntimeError("BehaviourDSLCommon::treatInteractionMatrix", m);
7928       }
7929     };
7930     throw_if(!this->mb.areSlipSystemsDefined(), "slip systems have not been defined");
7931     const auto& im = this->mb.getInteractionMatrixStructure();
7932     const auto r = im.rank();
7933     const auto mv =
7934         CxxTokenizer::readArray("BehaviourDSLCommon::treatInteractionMatrix", this->current, this->tokens.end());
7935     this->readSpecifiedToken("BehaviourDSLCommon::treatInteractionMatrix", ";");
7936     throw_if(mv.size() != r,
7937              "the number of values does "
7938              "not match the number of independent coefficients "
7939              "in the interaction matrix");
7940     auto imv = std::vector<long double>{};
7941     imv.reserve((mv.size()));
7942     for (const auto& v : mv) {
7943       imv.push_back(tfel::utilities::convert<long double>(v));
7944     }
7945     this->mb.setInteractionMatrix(imv);
7946   }  // end of BehaviourDSLCommon::treatInteractionMatrix
7947 
treatDislocationsMeanFreePathInteractionMatrix()7948   void BehaviourDSLCommon::treatDislocationsMeanFreePathInteractionMatrix() {
7949     auto throw_if = [this](const bool b, const std::string& m) {
7950       if (b) {
7951         this->throwRuntimeError(
7952             "BehaviourDSLCommon::"
7953             "treatDislocationsMeanFreePathInteractionMatrix",
7954             m);
7955       }
7956     };
7957     throw_if(!this->mb.areSlipSystemsDefined(), "slip systems have not been defined");
7958     const auto& im = this->mb.getInteractionMatrixStructure();
7959     const auto r = im.rank();
7960     const auto mv = CxxTokenizer::readArray(
7961         "BehaviourDSLCommon::"
7962         "treatDislocationsMeanFreePathInteractionMatrix",
7963         this->current, this->tokens.end());
7964     this->readSpecifiedToken(
7965         "BehaviourDSLCommon::"
7966         "treatDislocationsMeanFreePathInteractionMatrix",
7967         ";");
7968     throw_if(mv.size() != r,
7969              "the number of values does "
7970              "not match the number of independent coefficients "
7971              "in the interaction matrix");
7972     auto imv = std::vector<long double>{};
7973     imv.reserve((mv.size()));
7974     for (const auto& v : mv) {
7975       imv.push_back(tfel::utilities::convert<long double>(v));
7976     }
7977     this->mb.setDislocationsMeanFreePathInteractionMatrix(imv);
7978   }  // end of BehaviourDSLCommon::treatDislocationsMeanFreePathInteractionMatrix
7979 
7980   void BehaviourDSLCommon::
setComputeFinalThermodynamicForcesFromComputeFinalThermodynamicForcesCandidateIfNecessary()7981       setComputeFinalThermodynamicForcesFromComputeFinalThermodynamicForcesCandidateIfNecessary() {
7982     // first treating specialised mechanical data
7983     for (const auto& h : this->mb.getDistinctModellingHypotheses()) {
7984       if (h != ModellingHypothesis::UNDEFINEDHYPOTHESIS) {
7985         if (!this->mb.hasCode(h, BehaviourData::ComputeFinalThermodynamicForces)) {
7986           if (this->mb.hasCode(h, BehaviourData::ComputeFinalThermodynamicForcesCandidate)) {
7987             this->mb.setCode(h, BehaviourData::ComputeFinalThermodynamicForces,
7988                              this->mb.getCodeBlock(h, BehaviourData::ComputeFinalThermodynamicForcesCandidate),
7989                              BehaviourData::CREATE, BehaviourData::BODY);
7990           }
7991         }
7992       }
7993     }
7994     // now treating the default hypothesis case
7995     if (!this->mb.areAllMechanicalDataSpecialised()) {
7996       const auto h = ModellingHypothesis::UNDEFINEDHYPOTHESIS;
7997       if (!this->mb.hasCode(h, BehaviourData::ComputeFinalThermodynamicForces)) {
7998         if (this->mb.hasCode(h, BehaviourData::ComputeFinalThermodynamicForcesCandidate)) {
7999           this->mb.setCode(h, BehaviourData::ComputeFinalThermodynamicForces,
8000                            this->mb.getCodeBlock(h, BehaviourData::ComputeFinalThermodynamicForcesCandidate),
8001                            BehaviourData::CREATEBUTDONTREPLACE, BehaviourData::BODY);
8002         }
8003       }
8004     }
8005   }  // end of
8006      // BehaviourDSLCommon::setComputeFinalThermodynamicForcesFromComputeFinalThermodynamicForcesCandidateIfNecessary
8007 
getOverridableVariableNameByExternalName(const std::string & en) const8008   std::string BehaviourDSLCommon::getOverridableVariableNameByExternalName(
8009       const std::string& en) const {
8010     constexpr const auto uh = ModellingHypothesis::UNDEFINEDHYPOTHESIS;
8011     const auto& d = this->mb.getBehaviourData(uh);
8012     const auto pp = findByExternalName(d.getParameters(), en);
8013     if (pp != d.getParameters().end()) {
8014       return pp->name;
8015     }
8016     const auto pmp = findByExternalName(d.getMaterialProperties(), en);
8017     if (pmp == d.getMaterialProperties().end()) {
8018       tfel::raise(
8019           "BehaviourDSLCommon::getOverridableVariableNameByExternalName: "
8020           "no overridable variable associated with external name '" +
8021           en + "'");
8022     }
8023     return pmp->name;
8024   }  // end of BehaviourDSLCommon::getOverridableVariableNameByExternalName
8025 
overrideByAParameter(const std::string & n,const double v)8026   void BehaviourDSLCommon::overrideByAParameter(const std::string& n,
8027                                                 const double v) {
8028     this->mb.overrideByAParameter(n, v);
8029   }  // end of BehaviourDSLCommon::overrideByAParameter
8030 
8031   BehaviourDSLCommon::~BehaviourDSLCommon() = default;
8032 
8033 }  // end of namespace mfront
8034