1 /*!
2  * \file   mfront/src/BehaviourData.cxx
3  *
4  * \brief
5  * \author Thomas Helfer
6  * \date   18 Jan 2007
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 <sstream>
16 #include <iterator>
17 #include <algorithm>
18 #include <stdexcept>
19 
20 #include "TFEL/Raise.hxx"
21 #include "TFEL/Glossary/Glossary.hxx"
22 #include "TFEL/Glossary/GlossaryEntry.hxx"
23 #include "TFEL/Utilities/CxxTokenizer.hxx"
24 #include "MFront/MFrontUtilities.hxx"
25 #include "MFront/DSLUtilities.hxx"
26 #include "MFront/PerformanceProfiling.hxx"
27 #include "MFront/ModelDescription.hxx"
28 #include "MFront/BehaviourData.hxx"
29 #include "MFront/MFrontLogStream.hxx"
30 
31 namespace mfront {
32 
33   const char* const BehaviourData::FlowRule = "FlowRule";
34   const char* const BehaviourData::BeforeInitializeLocalVariables =
35       "BeforeInitializeLocalVariables";
36   const char* const BehaviourData::InitializeLocalVariables =
37       "InitializeLocalVariables";
38   const char* const BehaviourData::AfterInitializeLocalVariables =
39       "AfterInitializeLocalVariables";
40   const char* const BehaviourData::ComputePredictor = "ComputePredictor";
41   const char* const BehaviourData::ComputeStressFreeExpansion =
42       "ComputeStressFreeExpansion";
43   const char* const BehaviourData::ComputeThermodynamicForces =
44       "ComputeThermodynamicForces";
45   const char* const BehaviourData::ComputeFinalThermodynamicForces =
46       "ComputeFinalThermodynamicForces";
47   const char* const BehaviourData::ComputeFinalThermodynamicForcesCandidate =
48       "ComputeFinalThermodynamicForcesCandidate";
49   const char* const BehaviourData::ComputeInternalEnergy =
50       "ComputeInternalEnergy";
51   const char* const BehaviourData::ComputeDissipatedEnergy =
52       "ComputeDissipatedEnergy";
53   const char* const BehaviourData::APrioriTimeStepScalingFactor =
54       "APrioriTimeStepScalingFactor";
55   const char* const BehaviourData::Integrator = "Integrator";
56   const char* const BehaviourData::APosterioriTimeStepScalingFactor =
57       "APosterioriTimeStepScalingFactor";
58   const char* const BehaviourData::ComputeDerivative = "ComputeDerivative";
59   const char* const BehaviourData::UpdateAuxiliaryStateVariables =
60       "UpdateAuxiliaryStateVariables";
61   const char* const BehaviourData::ComputePredictionOperator =
62       "ComputePredictionOperator";
63   const char* const BehaviourData::ComputeTangentOperator =
64       "ComputeTangentOperator";
65   const char* const BehaviourData::InitializeJacobian = "InitializeJacobian";
66   const char* const BehaviourData::InitializeJacobianInvert =
67       "InitializeJacobianInvert";
68   const char* const BehaviourData::AdditionalConvergenceChecks =
69       "AdditionalConvergenceChecks";
70 
71   const char* const BehaviourData::profiling = "profiling";
72   const char* const BehaviourData::hasAPrioriTimeStepScalingFactor =
73       "hasAPrioriTimeStepScalingFactor";
74   const char* const BehaviourData::hasAPosterioriTimeStepScalingFactor =
75       "hasAPosterioriTimeStepScalingFactor";
76   const char* const BehaviourData::hasConsistentTangentOperator =
77       "hasConsistentTangentOperator";
78   const char* const BehaviourData::isConsistentTangentOperatorSymmetric =
79       "isConsistentTangentOperatorSymmetric";
80   const char* const BehaviourData::hasPredictionOperator =
81       "hasPredictionOperator";
82   const char* const BehaviourData::compareToNumericalJacobian =
83       "compareToNumericalJacobian";
84   const char* const BehaviourData::numericallyComputedJacobianBlocks =
85       "numericallyComputedJacobianBlocks";
86   const char* const BehaviourData::allowsNewUserDefinedVariables =
87       "allowsNewUserDefinedVariables";
88   const char* const BehaviourData::algorithm = "algorithm";
89   const char* const BehaviourData::numberOfEvaluations = "numberOfEvaluations";
90 
91   /*!
92    * check if the given name has already been used as value in the
93    * glossary map or in the entry map
94    * \param[in] gm : glossray names
95    * \param[in] em : entry names
96    * \param[in] n  : glossary name
97    */
BehaviourDataCheckIfNameIsAnEntryNameOrAGlossaryName(const std::map<std::string,std::string> & gm,const std::map<std::string,std::string> & em,const std::string & n)98   static void BehaviourDataCheckIfNameIsAnEntryNameOrAGlossaryName(
99       const std::map<std::string, std::string>& gm,
100       const std::map<std::string, std::string>& em,
101       const std::string& n) {
102     auto check = [&n](const std::map<std::string, std::string>& m,
103                       const char* const t) {
104       for (const auto& v : m) {
105         tfel::raise_if(v.second == n,
106                        "BehaviourDataCheckIfNameIsAnEntryNameOrAGlossaryName: "
107                        "name '" +
108                            n + "' is already used as a " + std::string(t));
109       }
110     };
111     check(gm, "glossary name");
112     check(em, "entry name");
113   }  // end of BehaviourDataCheckIfNameIsAnEntryNameOrAGlossaryName
114 
115   /*!
116    * \brief associate a glossary name or an entry name to a variable
117    * \param[in] m  : map to be updated
118    * \param[in] gn : glossary names
119    * \param[in] en : entry names
120    * \param[in] vn  : variable name
121    * \param[in] n  : variable name
122    * \param[in] g  : glossray name or entry name
123    */
BehaviourDataAddToGlossaryOrEntryNames(std::map<std::string,std::string> & m,const std::map<std::string,std::string> & gn,const std::map<std::string,std::string> & en,const std::set<std::string> & vn,const std::string & n,const std::string & g)124   static void BehaviourDataAddToGlossaryOrEntryNames(
125       std::map<std::string, std::string>& m,
126       const std::map<std::string, std::string>& gn,
127       const std::map<std::string, std::string>& en,
128       const std::set<std::string>& vn,
129       const std::string& n,
130       const std::string& g) {
131     auto throw_if = [](const bool c, const std::string& msg) {
132       tfel::raise_if(c, "BehaviourDataAddToGlossaryOrEntryNames: " + msg);
133     };
134     BehaviourDataCheckIfNameIsAnEntryNameOrAGlossaryName(gn, en, g);
135     throw_if(en.find(n) != en.end(),
136              "an entry name has already been specified for "
137              "variable '" +
138                  n + "'");
139     throw_if(gn.find(n) != gn.end(),
140              "a glossary name has already been specified for "
141              "variable '" +
142                  n + "'");
143     if (n != g) {
144       throw_if(vn.find(g) != vn.end(), "a member with the '" + g +
145                                            "' name has already "
146                                            "been declared");
147     }
148     throw_if(!m.insert({n, g}).second, "glossary name for variable '" + n +
149                                            "' "
150                                            "already specified");
151   }
152 
throwUndefinedAttribute(const std::string & n)153   void BehaviourData::throwUndefinedAttribute(const std::string& n) {
154     tfel::raise(
155         "BehaviourData::getAttribute: "
156         "no attribute named '" +
157         n + "'");
158   }  // end of BehaviourData::throwUndefinedAttribute
159 
160   BehaviourData::CodeBlocksAggregator::CodeBlocksAggregator() = default;
161 
isMutable() const162   bool BehaviourData::CodeBlocksAggregator::isMutable() const {
163     return this->is_mutable;
164   }  // end of BehaviourData::CodeBlocksAggregator::isMutable
165 
update()166   void BehaviourData::CodeBlocksAggregator::update() {
167     // updating code
168     this->cblock.code = cblock_begin;
169     if (!this->cblock_body.empty()) {
170       if (!this->cblock.code.empty()) {
171         if (*(this->cblock.code.rbegin()) != '\n') {
172           this->cblock.code.push_back('\n');
173         }
174       }
175     }
176     this->cblock.code += cblock_body;
177     if (!this->cblock_end.empty()) {
178       if (!this->cblock.code.empty()) {
179         if (*(this->cblock.code.rbegin()) != '\n') {
180           this->cblock.code.push_back('\n');
181         }
182       }
183     }
184     this->cblock.code += cblock_end;
185     // updating description
186     this->cblock.description = cdoc_begin;
187     if (!this->cdoc_body.empty()) {
188       if (!this->cblock.description.empty()) {
189         if (*(this->cblock.description.rbegin()) != '\n') {
190           this->cblock.description.push_back('\n');
191         }
192       }
193     }
194     this->cblock.description += cdoc_body;
195     if (!this->cdoc_end.empty()) {
196       if (!this->cblock.description.empty()) {
197         if (*(this->cblock.description.rbegin()) != '\n') {
198           this->cblock.description.push_back('\n');
199         }
200       }
201     }
202     this->cblock.description += cdoc_end;
203   }  // end of BehaviourData::update
204 
set(const CodeBlock & c,const Position p,const bool b)205   void BehaviourData::CodeBlocksAggregator::set(const CodeBlock& c,
206                                                 const Position p,
207                                                 const bool b) {
208     auto raise = [](const std::string& m) {
209       tfel::raise("BehaviourData::CodeBlocksAggregator::set: " + m);
210     };
211     this->check();
212     this->cblock.staticMembers.insert(c.staticMembers.begin(),
213                                       c.staticMembers.end());
214     this->cblock.members.insert(c.members.begin(), c.members.end());
215     for (const auto& a : c.attributes) {
216       if (this->cblock.attributes.count(a.first) != 0) {
217         auto& ca = this->cblock.attributes[a.first];
218         if (ca.is<bool>()) {
219           if (!a.second.is<bool>()) {
220             raise("unmatched type for attribute '" + a.first + "'");
221           }
222           if (a.second.get<bool>() != ca.get<bool>()) {
223             raise("unmatched value for attribute '" + a.first + "'");
224           }
225         } else if (ca.is<std::string>()) {
226           if (!a.second.is<std::string>()) {
227             raise("unmatched type for attribute '" + a.first + "'");
228           }
229           if (a.second.get<std::string>() != ca.get<std::string>()) {
230             raise("unmatched value for attribute '" + a.first + "'");
231           }
232         } else if (ca.is<std::vector<VariableDescription>>()) {
233           if (!a.second.is<std::vector<VariableDescription>>()) {
234             raise("unmatched type for attribute '" + a.first + "'");
235           }
236           auto& cv = ca.get<std::vector<VariableDescription>>();
237           for (const auto& v :
238                a.second.get<std::vector<VariableDescription>>()) {
239             const auto pv = std::find_if(cv.cbegin(), cv.cend(),
240                                          [&v](const VariableDescription& v2) {
241                                            return v.name == v2.name;
242                                          });
243             if (pv == cv.cend()) {
244               cv.push_back(v);
245             }
246           }
247         } else {
248           raise("unsupported attribute type (internal error)");
249         }
250       } else {
251         this->cblock.attributes.insert(a);
252       }
253     }
254     switch (p) {
255       case AT_BEGINNING:
256         if (!this->cblock_begin.empty()) {
257           this->cblock_begin += '\n';
258         }
259         this->cblock_begin += c.code;
260         if (!c.description.empty()) {
261           if (!this->cdoc_begin.empty()) {
262             this->cdoc_begin += '\n';
263           }
264           this->cdoc_begin += c.description;
265         }
266         break;
267       case BODY:
268         if (!this->cblock_body.empty()) {
269           this->cblock_body += '\n';
270         }
271         this->cblock_body += c.code;
272         if (!c.description.empty()) {
273           if (!this->cdoc_body.empty()) {
274             this->cdoc_body += '\n';
275           }
276           this->cdoc_body += c.description;
277         }
278         break;
279       case AT_END:
280         if (!this->cblock_end.empty()) {
281           this->cblock_end += '\n';
282         }
283         this->cblock_end += c.code;
284         if (!c.description.empty()) {
285           if (!this->cdoc_end.empty()) {
286             this->cdoc_end += '\n';
287           }
288           this->cdoc_end += c.description;
289         }
290         break;
291     }
292     this->update();
293     this->is_mutable = b;
294   }  // end of BehaviourData::CodeBlocksAggregator::set
295 
replace(const CodeBlock & c,const Position p,const bool b)296   void BehaviourData::CodeBlocksAggregator::replace(const CodeBlock& c,
297                                                     const Position p,
298                                                     const bool b) {
299     this->check();
300     this->cblock_begin.clear();
301     this->cblock_body.clear();
302     this->cblock_end.clear();
303     this->cblock.code.clear();
304     this->cblock.members.clear();
305     this->cblock.staticMembers.clear();
306     this->set(c, p, b);
307   }  // end of BehaviourData::CodeBlocksAggregator::set
308 
check() const309   void BehaviourData::CodeBlocksAggregator::check() const {
310     tfel::raise_if(!this->is_mutable,
311                    "BehaviourData::CodeBlocksAggregator::set: "
312                    "can't modifiy a code block");
313   }  // end of BehaviourData::CodeBlocksAggregator::check
314 
get() const315   const CodeBlock& BehaviourData::CodeBlocksAggregator::get() const {
316     this->is_mutable = false;
317     return this->cblock;
318   }  // end of BehaviourData::CodeBlocksAggregator::get
319 
320   BehaviourData::CodeBlocksAggregator::~CodeBlocksAggregator() = default;
321 
BehaviourData()322   BehaviourData::BehaviourData() {
323     this->registerMemberName("dt");
324     this->reserveName("\u0394t");  // symbolic value
325     // treating the temperature
326     auto T = VariableDescription{"temperature", "T", 1u, 0u};
327     T.setGlossaryName("Temperature");
328     this->addExternalStateVariable(T, UNREGISTRED);
329   }  // end of BehaviourData::BehaviourData()
330 
331   BehaviourData::BehaviourData(const BehaviourData&) = default;
332 
checkAlreadyRegistred(const std::set<std::string> & r,const std::string & n)333   static void checkAlreadyRegistred(const std::set<std::string>& r,
334                                     const std::string& n) {
335     if (r.find(n) == r.end()) {
336       tfel::raise(
337           "checkAlreadyRegistred: "
338           "variable '" +
339           n + "' was not registred");
340     }
341   }
342 
addStaticVariable(const StaticVariableDescription & v,const RegistrationStatus s)343   void BehaviourData::addStaticVariable(const StaticVariableDescription& v,
344                                         const RegistrationStatus s) {
345     if ((this->hasAttribute(BehaviourData::allowsNewUserDefinedVariables)) &&
346         (!this->getAttribute<bool>(
347             BehaviourData::allowsNewUserDefinedVariables))) {
348       const auto cbn = this->getCodeBlockNames();
349       tfel::raise_if(cbn.empty(),
350                      "BehaviourData::addStaticVariable: "
351                      "no more variable can be defined. This may mean that "
352                      "the parser does not expect you to add variables");
353       auto cbs = std::string{};
354       for (const auto& n : cbn) {
355         cbs += "\n- " + n;
356       }
357       tfel::raise(
358           "BehaviourData::addStaticVariable: "
359           "no more variable can be defined. This may mean that "
360           "you already declared a block of code (or that the dsl "
361           "does not expect you to add variables for whatever reason). "
362           "This is the list of "
363           "code blocks defined :" +
364           cbs);
365     }
366     if (s == UNREGISTRED) {
367       this->registerStaticMemberName(v.name);
368     } else {
369       checkAlreadyRegistred(this->reservedNames, v.name);
370     }
371     this->staticVariables.push_back(v);
372   }  // end of BehaviourData::addStaticVariable
373 
getIntegerConstant(const std::string & n) const374   int BehaviourData::getIntegerConstant(const std::string& n) const {
375     for (const auto& v : this->staticVariables) {
376       if (v.name == n) {
377         tfel::raise_if(v.type != "int",
378                        "MaterialPropertyDSL::getIntegerConstant: "
379                        "invalid type for variable '" +
380                            n + "'");
381         return v.value;
382       }
383     }
384     tfel::raise(
385         "MaterialPropertyDSL::getIntegerConstant: "
386         "unknown variable '" +
387         n + "'");
388   }  // end of BehaviourData::getIntegerConstant
389 
getStaticVariables() const390   const StaticVariableDescriptionContainer& BehaviourData::getStaticVariables()
391       const {
392     return this->staticVariables;
393   }  // end of BehaviourData::getStaticVariables
394 
getPersistentVariableDescription(const std::string & v) const395   const VariableDescription& BehaviourData::getPersistentVariableDescription(
396       const std::string& v) const {
397     return this->getPersistentVariables().getVariable(v);
398   }  // end of BehaviourData::getPersistentVariableDescription
399 
400   const VariableDescription&
getPersistentVariableDescriptionByExternalName(const std::string & v) const401   BehaviourData::getPersistentVariableDescriptionByExternalName(
402       const std::string& v) const {
403     return this->getPersistentVariables().getVariableByExternalName(v);
404   }  // end of BehaviourData::getPersistentVariableDescriptionByExternalName
405 
getIntegrationVariableDescription(const std::string & v) const406   const VariableDescription& BehaviourData::getIntegrationVariableDescription(
407       const std::string& v) const {
408     return this->getIntegrationVariables().getVariable(v);
409   }  // end of BehaviourData::getIntegrationVariableDescription
410 
411   const VariableDescription&
getIntegrationVariableDescriptionByExternalName(const std::string & v) const412   BehaviourData::getIntegrationVariableDescriptionByExternalName(
413       const std::string& v) const {
414     return this->getIntegrationVariables().getVariableByExternalName(v);
415   }  // end of BehaviourData::getIntegrationVariableDescriptionByExternalName
416 
getStateVariableDescription(const std::string & v) const417   const VariableDescription& BehaviourData::getStateVariableDescription(
418       const std::string& v) const {
419     return this->getStateVariables().getVariable(v);
420   }  // end of BehaviourData::getStateVariableDescription
421 
422   const VariableDescription&
getStateVariableDescriptionByExternalName(const std::string & v) const423   BehaviourData::getStateVariableDescriptionByExternalName(
424       const std::string& v) const {
425     return this->getStateVariables().getVariableByExternalName(v);
426   }  // end of BehaviourData::getStateVariableDescriptionByExternalName
427 
getExternalStateVariableDescription(const std::string & v) const428   const VariableDescription& BehaviourData::getExternalStateVariableDescription(
429       const std::string& v) const {
430     return this->getExternalStateVariables().getVariable(v);
431   }  // end of BehaviourData::getExternalStateVariableDescription
432 
433   const VariableDescription&
getExternalStateVariableDescriptionByExternalName(const std::string & v) const434   BehaviourData::getExternalStateVariableDescriptionByExternalName(
435       const std::string& v) const {
436     return this->getExternalStateVariables().getVariableByExternalName(v);
437   }  // end of BehaviourData::getExternalStateVariableDescriptionByExternalName
438 
439   const VariableDescription&
getAuxiliaryStateVariableDescription(const std::string & v) const440   BehaviourData::getAuxiliaryStateVariableDescription(
441       const std::string& v) const {
442     return this->getAuxiliaryStateVariables().getVariable(v);
443   }  // end of BehaviourData::getAuxiliaryStateVariableDescription
444 
445   const VariableDescription&
getAuxiliaryStateVariableDescriptionByExternalName(const std::string & v) const446   BehaviourData::getAuxiliaryStateVariableDescriptionByExternalName(
447       const std::string& v) const {
448     return this->getAuxiliaryStateVariables().getVariableByExternalName(v);
449   }  // end of BehaviourData::getAuxiliaryStateVariableDescriptionByExternalName
450 
getParameterDescription(const std::string & v) const451   const VariableDescription& BehaviourData::getParameterDescription(
452       const std::string& v) const {
453     return this->getParameters().getVariable(v);
454   }  // end of BehaviourData::getParameterDescription
455 
456   const VariableDescription&
getParameterDescriptionByExternalName(const std::string & v) const457   BehaviourData::getParameterDescriptionByExternalName(
458       const std::string& v) const {
459     return this->getParameters().getVariableByExternalName(v);
460   }  // end of BehaviourData::getParameterDescriptionByExternalName
461 
addMaterialProperty(const VariableDescription & v,const RegistrationStatus s)462   void BehaviourData::addMaterialProperty(const VariableDescription& v,
463                                           const RegistrationStatus s) {
464     const auto op = this->overriding_parameters.find(v.name);
465     if (op != this->overriding_parameters.end()) {
466       if (v.arraySize != 1u) {
467         tfel::raise(
468             "BehaviourData::addMaterialProperty: "
469             "overriding arrays of material properties is not supported yet");
470       }
471       this->addParameter(v, s);
472       this->setParameterDefaultValue(v.name, op->second);
473     } else {
474       this->addVariable(this->materialProperties, v, s, false);
475     }
476   }  // end of BehaviourData::addMaterialProperty
477 
addIntegrationVariable(const VariableDescription & v,const RegistrationStatus s)478   void BehaviourData::addIntegrationVariable(const VariableDescription& v,
479                                              const RegistrationStatus s) {
480     this->addVariable(this->integrationVariables, v, s, true);
481   }  // end of BehaviourData::addIntegrationVariable
482 
addStateVariable(const VariableDescription & v,const RegistrationStatus s)483   void BehaviourData::addStateVariable(const VariableDescription& v,
484                                        const RegistrationStatus s) {
485     this->addVariable(this->stateVariables, v, s, true);
486     if (s == FORCEREGISTRATION) {
487       this->addVariable(this->integrationVariables, v, ALREADYREGISTRED, true,
488                         true);
489     } else {
490       this->addVariable(this->integrationVariables, v, ALREADYREGISTRED, true);
491     }
492     /*!
493      * for compatibility reasons with previous mfront versions
494      * (<2.0), auxiliary state variables shall be put after
495      * state variables.
496      */
497     bool found = false;
498     auto p = this->persistentVariables.begin();
499     while (p != this->persistentVariables.end()) {
500       if (this->isAuxiliaryStateVariableName(p->name)) {
501         this->persistentVariables.insert(p, v);
502         found = true;
503         break;
504       } else {
505         ++p;
506       }
507     }
508     if (!found) {
509       this->persistentVariables.push_back(v);
510     }
511   }  // end of BehaviourData::addStateVariable
512 
addAuxiliaryStateVariable(const VariableDescription & v,const RegistrationStatus s)513   void BehaviourData::addAuxiliaryStateVariable(const VariableDescription& v,
514                                                 const RegistrationStatus s) {
515     this->addVariable(this->auxiliaryStateVariables, v, s, false);
516     if (s == FORCEREGISTRATION) {
517       this->addVariable(this->persistentVariables, v, ALREADYREGISTRED, true,
518                         true);
519     } else {
520       this->addVariable(this->persistentVariables, v, ALREADYREGISTRED, true);
521     }
522   }  // end of BehaviourData::addAuxiliaryStateVariable
523 
addExternalStateVariable(const VariableDescription & v,const RegistrationStatus s)524   void BehaviourData::addExternalStateVariable(const VariableDescription& v,
525                                                const RegistrationStatus s) {
526     this->addVariable(this->externalStateVariables, v, s, true);
527   }  // end of BehaviourData::addExternalStateVariable
528 
addLocalVariable(const VariableDescription & v,const RegistrationStatus s)529   void BehaviourData::addLocalVariable(const VariableDescription& v,
530                                        const RegistrationStatus s) {
531     this->addVariable(this->localVariables, v, s, false, true);
532   }  // end of BehaviourData::addLocalVariable
533 
addParameter(const VariableDescription & v,const RegistrationStatus s)534   void BehaviourData::addParameter(const VariableDescription& v,
535                                    const RegistrationStatus s) {
536     const auto op = this->overriding_parameters.find(v.name);
537     if (op != this->overriding_parameters.end()) {
538       if (v.arraySize != 1u) {
539         tfel::raise(
540             "BehaviourData::addParameter: "
541             "overriding array of parameters is not supported yet");
542       }
543     }
544     this->addVariable(this->parameters, v, s, false);
545   }  // end of BehaviourData::addParameter
546 
hasParameter(const std::string & n) const547   bool BehaviourData::hasParameter(const std::string& n) const {
548     return this->parameters.contains(n);
549   }
550 
hasParameters() const551   bool BehaviourData::hasParameters() const {
552     return !this->parameters.empty();
553   }
554 
isMemberUsedInCodeBlocks(const std::string & v) const555   bool BehaviourData::isMemberUsedInCodeBlocks(const std::string& v) const {
556     for (const auto& c : this->cblocks) {
557       const auto& m = c.second.get().members;
558       if (m.find(v) != m.end()) {
559         return true;
560       }
561     }
562     return false;
563   }  // end of BehaviourData::isMemberUsedInCodeBlocks
564 
isMaterialPropertyName(const std::string & n) const565   bool BehaviourData::isMaterialPropertyName(const std::string& n) const {
566     return this->getMaterialProperties().contains(n);
567   }  // end of BehaviourData::isMaterialPropertyName
568 
isStaticVariableName(const std::string & n) const569   bool BehaviourData::isStaticVariableName(const std::string& n) const {
570     return this->getStaticVariables().contains(n);
571   }  // end of BehaviourData::isStaticVariableName
572 
isLocalVariableName(const std::string & n) const573   bool BehaviourData::isLocalVariableName(const std::string& n) const {
574     return this->getLocalVariables().contains(n);
575   }  // end of BehaviourData::isLocalVariableName
576 
isPersistentVariableName(const std::string & n) const577   bool BehaviourData::isPersistentVariableName(const std::string& n) const {
578     return this->getPersistentVariables().contains(n);
579   }  // end of BehaviourData::isPersistentVariableName
580 
isIntegrationVariableName(const std::string & n) const581   bool BehaviourData::isIntegrationVariableName(const std::string& n) const {
582     return this->getIntegrationVariables().contains(n);
583   }  // end of BehaviourData::isIntegrationVariableName
584 
isIntegrationVariableIncrementName(const std::string & n) const585   bool BehaviourData::isIntegrationVariableIncrementName(
586       const std::string& n) const {
587     if (n.size() < 2) {
588       return false;
589     }
590     if (n[0] != 'd') {
591       return false;
592     }
593     return this->getIntegrationVariables().contains(n.substr(1));
594   }  // end of BehaviourData::isIntegrationVariableName
595 
isStateVariableName(const std::string & n) const596   bool BehaviourData::isStateVariableName(const std::string& n) const {
597     return this->getStateVariables().contains(n);
598   }  // end of BehaviourData::isStateVariableName
599 
isStateVariableIncrementName(const std::string & n) const600   bool BehaviourData::isStateVariableIncrementName(const std::string& n) const {
601     if (n.size() < 2) {
602       return false;
603     }
604     if (n[0] != 'd') {
605       return false;
606     }
607     return this->getStateVariables().contains(n.substr(1));
608   }  // end of BehaviourData::isStateVariableName
609 
isAuxiliaryStateVariableName(const std::string & n) const610   bool BehaviourData::isAuxiliaryStateVariableName(const std::string& n) const {
611     return this->getAuxiliaryStateVariables().contains(n);
612   }  // end of BehaviourData::isStateVariableName
613 
isExternalStateVariableName(const std::string & n) const614   bool BehaviourData::isExternalStateVariableName(const std::string& n) const {
615     return this->getExternalStateVariables().contains(n);
616   }  // end of BehaviourData::isExternalStateVariableName
617 
isExternalStateVariableIncrementName(const std::string & n) const618   bool BehaviourData::isExternalStateVariableIncrementName(
619       const std::string& n) const {
620     if (n.size() < 2) {
621       return false;
622     }
623     if (n[0] != 'd') {
624       return false;
625     }
626     return this->getExternalStateVariables().contains(n.substr(1));
627   }  // end of BehaviourData::isExternalStateVariableName
628 
isParameterName(const std::string & n) const629   bool BehaviourData::isParameterName(const std::string& n) const {
630     return this->getParameters().contains(n);
631   }  // end of BehaviourData::isParameterName
632 
getMaterialProperties() const633   const VariableDescriptionContainer& BehaviourData::getMaterialProperties()
634       const {
635     return this->materialProperties;
636   }  // end of BehaviourData::getMaterialProperties
637 
getPersistentVariables() const638   const VariableDescriptionContainer& BehaviourData::getPersistentVariables()
639       const {
640     return this->persistentVariables;
641   }  // end of BehaviourData::getPersistentVariables
642 
getVariablesNames() const643   std::set<std::string> BehaviourData::getVariablesNames() const {
644     auto getNames = [](std::set<std::string>& r,
645                        const VariableDescriptionContainer& c) {
646       for (const auto& v : c) {
647         tfel::raise_if(!r.insert(v.name).second,
648                        "BehaviourData::getVariablesNames: "
649                        "internal error, variable name "
650                        "'" +
651                            v.name + "' multiply defined");
652       }
653     };
654     auto n = std::set<std::string>{};
655     getNames(n, this->getMaterialProperties());
656     getNames(n, this->getStateVariables());
657     getNames(n, this->getAuxiliaryStateVariables());
658     getNames(n, this->getExternalStateVariables());
659     getNames(n, this->getParameters());
660     return n;
661   }  // end of BehaviourData::getVariablesNames
662 
getVariables(const std::string & t) const663   const VariableDescriptionContainer& BehaviourData::getVariables(
664       const std::string& t) const {
665     const VariableDescriptionContainer& (BehaviourData::*m)() const;
666     if (t == "MaterialProperty") {
667       m = &BehaviourData::getMaterialProperties;
668     } else if (t == "PersistentVariable") {
669       m = &BehaviourData::getPersistentVariables;
670     } else if (t == "IntegrationVariable") {
671       m = &BehaviourData::getIntegrationVariables;
672     } else if (t == "StateVariable") {
673       m = &BehaviourData::getStateVariables;
674     } else if (t == "AuxiliaryStateVariable") {
675       m = &BehaviourData::getAuxiliaryStateVariables;
676     } else if (t == "ExternalStateVariable") {
677       m = &BehaviourData::getExternalStateVariables;
678     } else if (t == "Parameter") {
679       m = &BehaviourData::getParameters;
680     } else {
681       tfel::raise(
682           "BehaviourData::getVariables: "
683           "invalid variables type '" +
684           t + "'");
685     }
686     return (this->*m)();
687   }  // end of BehaviourData::getIntegrationVariables
688 
getIntegrationVariables() const689   const VariableDescriptionContainer& BehaviourData::getIntegrationVariables()
690       const {
691     return this->integrationVariables;
692   }  // end of BehaviourData::getIntegrationVariables
693 
getStateVariables() const694   const VariableDescriptionContainer& BehaviourData::getStateVariables() const {
695     return this->stateVariables;
696   }  // end of BehaviourData::getStateVariables
697 
698   const VariableDescriptionContainer&
getAuxiliaryStateVariables() const699   BehaviourData::getAuxiliaryStateVariables() const {
700     return this->auxiliaryStateVariables;
701   }  // end of BehaviourData::getAuxiliaryStateVariables
702 
getExternalStateVariables() const703   const VariableDescriptionContainer& BehaviourData::getExternalStateVariables()
704       const {
705     return this->externalStateVariables;
706   }  // end of BehaviourData::getExternalStateVariables
707 
getLocalVariables() const708   const VariableDescriptionContainer& BehaviourData::getLocalVariables() const {
709     return this->localVariables;
710   }  // end of BehaviourData::getLocalVariables
711 
isUsableInPurelyImplicitResolution() const712   bool BehaviourData::isUsableInPurelyImplicitResolution() const {
713     return this->usableInPurelyImplicitResolution;
714   }  // end of BehaviourData::isUsableInPurelyImplicitResolution
715 
setBounds(const std::string & n,const VariableBoundsDescription & b)716   void BehaviourData::setBounds(const std::string& n,
717                                 const VariableBoundsDescription& b) {
718     bool treated = false;
719     auto set_bounds = [&n, &b, &treated](VariableDescriptionContainer& c) {
720       if (c.contains(n)) {
721         c.getVariable(n).setBounds(b);
722         treated = true;
723       }
724     };
725     set_bounds(this->materialProperties);
726     set_bounds(this->localVariables);
727     set_bounds(this->stateVariables);
728     set_bounds(this->auxiliaryStateVariables);
729     set_bounds(this->integrationVariables);
730     set_bounds(this->persistentVariables);
731     set_bounds(this->externalStateVariables);
732     set_bounds(this->parameters);
733     tfel::raise_if(!treated,
734                    "BehaviourData::setBounds: "
735                    "no variable named '" +
736                        n + "'");
737   }  // end of BehaviourData::getBounds
738 
setBounds(const std::string & n,const unsigned short i,const VariableBoundsDescription & b)739   void BehaviourData::setBounds(const std::string& n,
740                                 const unsigned short i,
741                                 const VariableBoundsDescription& b) {
742     bool treated = false;
743     auto set_bounds = [&n, i, &b, &treated](VariableDescriptionContainer& c) {
744       if (c.contains(n)) {
745         c.getVariable(n).setBounds(b, i);
746         treated = true;
747       }
748     };
749     set_bounds(this->materialProperties);
750     set_bounds(this->localVariables);
751     set_bounds(this->stateVariables);
752     set_bounds(this->auxiliaryStateVariables);
753     set_bounds(this->integrationVariables);
754     set_bounds(this->persistentVariables);
755     set_bounds(this->externalStateVariables);
756     set_bounds(this->parameters);
757     tfel::raise_if(!treated,
758                    "BehaviourData::setBounds: "
759                    "no variable named '" +
760                        n + "'");
761   }
762 
763   const VariableDescription&
getVariableDescriptionByExternalName(const std::string & n) const764   BehaviourData::getVariableDescriptionByExternalName(
765       const std::string& n) const {
766     auto contains = [&n](const VariableDescriptionContainer& vc) {
767       for (const auto& v : vc) {
768         if (v.getExternalName() == n) {
769           return true;
770         }
771       }
772       return false;
773     };
774     if (contains(this->materialProperties)) {
775       return this->materialProperties.getVariableByExternalName(n);
776     }
777     if (contains(this->localVariables)) {
778       return this->localVariables.getVariableByExternalName(n);
779     }
780     if (contains(this->stateVariables)) {
781       return this->stateVariables.getVariableByExternalName(n);
782     }
783     if (contains(this->auxiliaryStateVariables)) {
784       return this->auxiliaryStateVariables.getVariableByExternalName(n);
785     }
786     if (contains(this->integrationVariables)) {
787       return this->integrationVariables.getVariableByExternalName(n);
788     }
789     if (contains(this->externalStateVariables)) {
790       return this->externalStateVariables.getVariableByExternalName(n);
791     }
792     if (contains(this->parameters)) {
793       return this->parameters.getVariableByExternalName(n);
794     }
795     tfel::raise(
796         "BehaviourData::getVariableDescriptionByExternalName: "
797         "no variable with external name '" +
798         n +
799         "' found. "
800         "Such variable is *not*:\n"
801         "- a material property\n"
802         "- a local variable\n"
803         "- a state variable\n"
804         "- an auxiliary state variable\n"
805         "- an integration variable\n"
806         "- an external state variable\n"
807         "- a parameter");
808   }  // end of BehaviourData::getVariableDescriptionByExternalName
809 
getVariableDescription(const std::string & n) const810   const VariableDescription& BehaviourData::getVariableDescription(
811       const std::string& n) const {
812     if (this->materialProperties.contains(n)) {
813       return this->materialProperties.getVariable(n);
814     }
815     if (this->localVariables.contains(n)) {
816       return this->localVariables.getVariable(n);
817     }
818     if (this->stateVariables.contains(n)) {
819       return this->stateVariables.getVariable(n);
820     }
821     if (this->auxiliaryStateVariables.contains(n)) {
822       return this->auxiliaryStateVariables.getVariable(n);
823     }
824     if (this->integrationVariables.contains(n)) {
825       return this->integrationVariables.getVariable(n);
826     }
827     if (this->externalStateVariables.contains(n)) {
828       return this->externalStateVariables.getVariable(n);
829     }
830     if (this->parameters.contains(n)) {
831       return this->parameters.getVariable(n);
832     }
833     tfel::raise(
834         "BehaviourData::getVariableDescription: "
835         "no variable named '" +
836         n +
837         "' found. "
838         "This variable is *not*:\n"
839         "- a material property\n"
840         "- a local variable\n"
841         "- a state variable\n"
842         "- an auxiliary state variable\n"
843         "- an integration variable\n"
844         "- an external state variable\n"
845         "- a parameter");
846   }  // end of BehaviourData::getVariableDescription
847 
setVariableAttribute(const std::string & v,const std::string & n,const VariableAttribute & a,const bool b)848   void BehaviourData::setVariableAttribute(const std::string& v,
849                                            const std::string& n,
850                                            const VariableAttribute& a,
851                                            const bool b) {
852     bool treated = false;
853     auto set_if = [&v, &n, &a, b, &treated](VariableDescriptionContainer& vc) {
854       if (vc.contains(v)) {
855         vc.getVariable(v).setAttribute(n, a, b);
856         treated = true;
857       }
858     };
859     set_if(this->materialProperties);
860     set_if(this->localVariables);
861     set_if(this->integrationVariables);
862     set_if(this->stateVariables);
863     set_if(this->auxiliaryStateVariables);
864     set_if(this->persistentVariables);
865     set_if(this->externalStateVariables);
866     set_if(this->parameters);
867     tfel::raise_if(!treated,
868                    "BehaviourData::setVariableAttribute: "
869                    "no variable named '" +
870                        n +
871                        "' found."
872                        "This variable is *not*:\n"
873                        "- a material property\n"
874                        "- a local variable\n"
875                        "- a state variable\n"
876                        "- an auxiliary state variable\n"
877                        "- an integration variable\n"
878                        "- a  persistent variable\n"
879                        "- an external state variable\n"
880                        "- a parameter");
881   }  // end of BehaviourData::setVariableAttribute
882 
getVariableDescription(const std::string & n)883   VariableDescription& BehaviourData::getVariableDescription(
884       const std::string& n) {
885     if (this->materialProperties.contains(n)) {
886       return this->materialProperties.getVariable(n);
887     }
888     if (this->localVariables.contains(n)) {
889       return this->localVariables.getVariable(n);
890     }
891     if (this->stateVariables.contains(n)) {
892       return this->stateVariables.getVariable(n);
893     }
894     if (this->auxiliaryStateVariables.contains(n)) {
895       return this->auxiliaryStateVariables.getVariable(n);
896     }
897     if (this->integrationVariables.contains(n)) {
898       return this->integrationVariables.getVariable(n);
899     }
900     if (this->externalStateVariables.contains(n)) {
901       return this->externalStateVariables.getVariable(n);
902     }
903     if (this->parameters.contains(n)) {
904       return this->parameters.getVariable(n);
905     }
906     tfel::raise(
907         "BehaviourData::getVariableDescription: "
908         "no variable named '" +
909         n +
910         "' found."
911         "This variable is *not*:\n"
912         "- a material property\n"
913         "- a local variable\n"
914         "- a state variable\n"
915         "- an auxiliary state variable\n"
916         "- an integration variable\n"
917         "- an external state variable\n"
918         "- a parameter");
919   }  // end of BehaviourData::getVariableDescription
920 
setPhysicalBounds(const std::string & n,const VariableBoundsDescription & b)921   void BehaviourData::setPhysicalBounds(const std::string& n,
922                                         const VariableBoundsDescription& b) {
923     bool treated = false;
924     auto set_bounds = [&n, &b, &treated](VariableDescriptionContainer& c) {
925       if (c.contains(n)) {
926         c.getVariable(n).setPhysicalBounds(b);
927         treated = true;
928       }
929     };
930     set_bounds(this->materialProperties);
931     set_bounds(this->localVariables);
932     set_bounds(this->stateVariables);
933     set_bounds(this->auxiliaryStateVariables);
934     set_bounds(this->integrationVariables);
935     set_bounds(this->persistentVariables);
936     set_bounds(this->externalStateVariables);
937     set_bounds(this->parameters);
938     tfel::raise_if(!treated,
939                    "BehaviourData::setPhysicalBounds: "
940                    "no variable named '" +
941                        n + "'");
942   }  // end of BehaviourData::setPhysicalBounds
943 
setPhysicalBounds(const std::string & n,const unsigned short i,const VariableBoundsDescription & b)944   void BehaviourData::setPhysicalBounds(const std::string& n,
945                                         const unsigned short i,
946                                         const VariableBoundsDescription& b) {
947     bool treated = false;
948     auto set_bounds = [&n, &i, &b, &treated](VariableDescriptionContainer& c) {
949       if (c.contains(n)) {
950         c.getVariable(n).setPhysicalBounds(b, i);
951         treated = true;
952       }
953     };
954     set_bounds(this->materialProperties);
955     set_bounds(this->localVariables);
956     set_bounds(this->stateVariables);
957     set_bounds(this->auxiliaryStateVariables);
958     set_bounds(this->integrationVariables);
959     set_bounds(this->persistentVariables);
960     set_bounds(this->externalStateVariables);
961     set_bounds(this->parameters);
962     tfel::raise_if(!treated,
963                    "BehaviourData::setPhysicalBounds: "
964                    "no variable named '" +
965                        n + "'");
966   }  // end of BehaviourData::setPhysicalBounds
967 
setUsableInPurelyImplicitResolution(const bool b)968   void BehaviourData::setUsableInPurelyImplicitResolution(const bool b) {
969     this->usableInPurelyImplicitResolution = b;
970   }  // end of BehaviourData::setUsableInPurelyImplicitResolution
971 
972   void BehaviourData::
declareExternalStateVariableProbablyUnusableInPurelyImplicitResolution(const std::string & n)973       declareExternalStateVariableProbablyUnusableInPurelyImplicitResolution(
974           const std::string& n) {
975     this->pupirv.insert(n);
976   }  // end of
977      // BehaviourData::declareExternalStateVariableProbablyUnusableInPurelyImplicitResolution
978 
979   const std::set<std::string>& BehaviourData::
getExternalStateVariablesDeclaredProbablyUnusableInPurelyImplicitResolution() const980       getExternalStateVariablesDeclaredProbablyUnusableInPurelyImplicitResolution()
981           const {
982     return this->pupirv;
983   }  // end of
984      // BehaviourData::getExternalStateVariablesDeclaredProbablyUnusableInPurelyImplicitResolution
985 
addVariable(VariableDescriptionContainer & c,const VariableDescription & v,const RegistrationStatus s,const bool bi,const bool b)986   void BehaviourData::addVariable(VariableDescriptionContainer& c,
987                                   const VariableDescription& v,
988                                   const RegistrationStatus s,
989                                   const bool bi,
990                                   const bool b) {
991     if ((!b) && (s != FORCEREGISTRATION)) {
992       if ((this->hasAttribute(BehaviourData::allowsNewUserDefinedVariables)) &&
993           (!this->getAttribute<bool>(
994               BehaviourData::allowsNewUserDefinedVariables))) {
995         const auto cbn = this->getCodeBlockNames();
996         tfel::raise_if(
997             cbn.empty(),
998             "BehaviourData::addVariable: can't add variable '" + v.name +
999                 "', "
1000                 "no more variable can be defined. This may mean that "
1001                 "the parser does not expect you to add variables");
1002         auto cbs = std::string{};
1003         for (const auto& n : cbn) {
1004           cbs += "\n- " + n;
1005         }
1006         tfel::raise(
1007             "BehaviourData::addVariable: can't add variable '" + v.name +
1008             "', "
1009             "no more variable can be defined. This may mean that "
1010             "you already declared a block of code (or that the dsl "
1011             "does not expect you to add variables for whatever reason). "
1012             "This is the list of "
1013             "code blocks defined :" +
1014             cbs);
1015       }
1016     }
1017     if (s == ALREADYREGISTRED) {
1018       checkAlreadyRegistred(this->reservedNames, v.name);
1019       if (!v.symbolic_form.empty()) {
1020         checkAlreadyRegistred(this->reservedNames, v.symbolic_form);
1021       }
1022     } else {
1023       this->registerMemberName(v.name);
1024       if (!v.symbolic_form.empty()) {
1025         this->reserveName(v.symbolic_form);
1026       }
1027       if (bi) {
1028         this->registerMemberName("d" + v.name);
1029         if (!v.symbolic_form.empty()) {
1030           this->reserveName("\u0394" + v.symbolic_form);
1031         } else {
1032           this->reserveName("\u0394" + v.name);
1033         }
1034       }
1035     }
1036     if (v.hasGlossaryName()) {
1037       this->glossaryNames.insert({v.name, v.getExternalName()});
1038     }
1039     if (v.hasEntryName()) {
1040       this->entryNames.insert({v.name, v.getExternalName()});
1041     }
1042     c.push_back(v);
1043   }  // end of BehaviourData::addVariable
1044 
reserveName(const std::string & n)1045   void BehaviourData::reserveName(const std::string& n) {
1046     tfel::raise_if(!this->reservedNames.insert(n).second,
1047                    "BehaviourData::reserveName: "
1048                    "name '" +
1049                        n + "' already registred");
1050   }  // end of BehaviourData::reserveName
1051 
isNameReserved(const std::string & n) const1052   bool BehaviourData::isNameReserved(const std::string& n) const {
1053     return this->reservedNames.count(n) != 0;
1054   }
1055 
registerGlossaryName(const std::string & n,const std::string & g)1056   void BehaviourData::registerGlossaryName(const std::string& n,
1057                                            const std::string& g) {
1058     using namespace tfel::glossary;
1059     const auto& glossary = Glossary::getGlossary();
1060     if (glossary.contains(n)) {
1061       std::ostringstream msg;
1062       msg << "BehaviourData::registerEntryName: "
1063           << "the name '" << n << "' is a registred as a glossary name.\n";
1064       displayGlossaryEntryCompleteDescription(msg,
1065                                               glossary.getGlossaryEntry(n));
1066       tfel::raise(msg.str());
1067     }
1068     if (!glossary.contains(g)) {
1069       tfel::raise(
1070           "BehaviourData::registerGlossaryName: "
1071           "the name '" +
1072           g + "' is a not known as a glossary name");
1073     }
1074     if (!this->isNameReserved(n)) {
1075       tfel::raise(
1076           "BehaviourData::registerGlossaryName: "
1077           "the variable name '" +
1078           n + "' not is registred");
1079     }
1080     /*
1081      * Special exceptions for glossary name which are also supported type name:
1082      * those names are already registred and no clash ispossible.
1083      */
1084     const auto& flags = SupportedTypes::getTypeFlags();
1085     if (flags.find(g) == flags.end()) {
1086       this->reserveName(g);
1087     }
1088     tfel::raise_if(!this->glossaryNames.insert({n, g}).second,
1089                    "BehaviourData::registerGlossaryName: "
1090                    "a variable named '" +
1091                        n + "' has already been registred");
1092   }  // end of BehaviourData::registerGlossaryName
1093 
registerEntryName(const std::string & n,const std::string & e)1094   void BehaviourData::registerEntryName(const std::string& n,
1095                                         const std::string& e) {
1096     using namespace tfel::glossary;
1097     const auto& glossary = Glossary::getGlossary();
1098     if (glossary.contains(e)) {
1099       std::ostringstream msg;
1100       msg << "BehaviourData::registerEntryName: "
1101           << "the name '" << e << "' is a registred as a glossary name.\n";
1102       displayGlossaryEntryCompleteDescription(msg,
1103                                               glossary.getGlossaryEntry(e));
1104       tfel::raise(msg.str());
1105     }
1106     if (!this->isNameReserved(n)) {
1107       tfel::raise(
1108           "BehaviourData::registerGlossaryName: "
1109           "the variable name '" +
1110           n + "' is registred");
1111     }
1112     /*
1113      * Special exceptions for glossary name which are also supported type name:
1114      * those names are already registred and no clash ispossible.
1115      */
1116     const auto& flags = SupportedTypes::getTypeFlags();
1117     if (flags.find(e) == flags.end()) {
1118       this->reserveName(e);
1119     }
1120     tfel::raise_if(!this->entryNames.insert({n, e}).second,
1121                    "BehaviourData::registerEntryName: "
1122                    "a variable named '" +
1123                        n + "' has already been registred");
1124   }  // end of BehaviourData::registerEntryName
1125 
registerMemberName(const std::string & n)1126   void BehaviourData::registerMemberName(const std::string& n) {
1127     using namespace tfel::glossary;
1128     const auto& glossary = Glossary::getGlossary();
1129     for (auto& e : this->entryNames) {
1130       tfel::raise_if(e.second == n,
1131                      "BehaviourData::registerMemberName: "
1132                      "the name '" +
1133                          n +
1134                          "' is already been used "
1135                          "for an entry name");
1136     }
1137     if (glossary.contains(n)) {
1138       std::ostringstream msg;
1139       msg << "BehaviourData::registerMemberName: "
1140           << "the name '" << n << "' is a registred as a glossary name.\n";
1141       displayGlossaryEntryCompleteDescription(msg,
1142                                               glossary.getGlossaryEntry(n));
1143       tfel::raise(msg.str());
1144     }
1145     this->reserveName(n);
1146     tfel::raise_if(!this->membersNames.insert(n).second,
1147                    "BehaviourData::registerMemberName: "
1148                    "a variable named '" +
1149                        n + "' has already been registred");
1150   }  // end of BehaviourData::registerMemberName
1151 
registerStaticMemberName(const std::string & n)1152   void BehaviourData::registerStaticMemberName(const std::string& n) {
1153     const auto& g = tfel::glossary::Glossary::getGlossary();
1154     for (auto& e : this->entryNames) {
1155       tfel::raise_if(e.second == n,
1156                      "BehaviourData::registerStaticMemberName: "
1157                      "the name '" +
1158                          n +
1159                          "' is already been used "
1160                          "for an entry name");
1161     }
1162     if (g.contains(n)) {
1163       std::ostringstream msg;
1164       msg << "BehaviourData::registerStaticMemberName: "
1165           << "the name '" << n << "' is a registred as a glossary name.\n";
1166       displayGlossaryEntryCompleteDescription(msg, g.getGlossaryEntry(n));
1167       tfel::raise(msg.str());
1168     }
1169     this->reserveName(n);
1170     tfel::raise_if(!this->staticMembersNames.insert(n).second,
1171                    "BehaviourData::registerStaticMemberName: "
1172                    "a variable named '" +
1173                        n + "' has already been registred");
1174   }  // end of BehaviourData::registerStaticMemberName
1175 
getRegistredMembersNames() const1176   const std::set<std::string>& BehaviourData::getRegistredMembersNames() const {
1177     return this->membersNames;
1178   }  // end of BehaviourData::getRegistredMemberNames
1179 
getRegistredStaticMembersNames() const1180   const std::set<std::string>& BehaviourData::getRegistredStaticMembersNames()
1181       const {
1182     return this->staticMembersNames;
1183   }  // end of BehaviourData::getRegistredStaticMemberNames
1184 
checkVariableName(const std::string & n) const1185   void BehaviourData::checkVariableName(const std::string& n) const {
1186     if ((this->materialProperties.contains(n)) ||
1187         (this->persistentVariables.contains(n)) ||
1188         (this->integrationVariables.contains(n)) ||
1189         (this->stateVariables.contains(n)) ||
1190         (this->auxiliaryStateVariables.contains(n)) ||
1191         (this->externalStateVariables.contains(n)) ||
1192         (this->localVariables.contains(n)) || (this->parameters.contains(n)) ||
1193         (this->staticVariables.contains(n))) {
1194       return;
1195     }
1196     tfel::raise(
1197         "BehaviourData::checkVariableName: "
1198         "no variable named '" +
1199         n + "'");
1200   }  // end of BehaviourData::checkVariableName
1201 
setCode(const std::string & n,const CodeBlock & c,const Mode m,const Position p,const bool b)1202   void BehaviourData::setCode(const std::string& n,
1203                               const CodeBlock& c,
1204                               const Mode m,
1205                               const Position p,
1206                               const bool b) {
1207     auto pc = this->cblocks.find(n);
1208     if (pc == this->cblocks.end()) {
1209       pc = this->cblocks.insert({n, CodeBlocksAggregator{}}).first;
1210     } else {
1211       if (m == CREATE) {
1212         tfel::raise(
1213             "BehaviourData::setCode: "
1214             "a code block named '" +
1215             n +
1216             "' already exists.\n"
1217             "If you wanted to append this new code to the "
1218             "existing one, you shall use the 'Append' option.\n"
1219             "You can also replace it with 'Replace' option "
1220             "(assuming you know what you are doing).\n");
1221       } else if (m == CREATEORREPLACE) {
1222         tfel::raise_if(!pc->second.isMutable(),
1223                        "BehaviourData::setCode: "
1224                        "the code block named '" +
1225                            n +
1226                            "' "
1227                            "is not modifiable");
1228         this->cblocks.erase(pc);
1229         pc = this->cblocks.insert({n, CodeBlocksAggregator{}}).first;
1230       } else if (m == CREATEBUTDONTREPLACE) {
1231         return;
1232       }
1233     }
1234     pc->second.set(c, p, b);
1235   }  // end of BehaviourData::setCode
1236 
getCodeBlock(const std::string & n) const1237   const CodeBlock& BehaviourData::getCodeBlock(const std::string& n) const {
1238     auto p = this->cblocks.find(n);
1239     tfel::raise_if(p == this->cblocks.end(),
1240                    "BehaviourData::getCode: "
1241                    "no code block associated with '" +
1242                        n + "'");
1243     return p->second.get();
1244   }  // end of BehaviourData::getCodeBlock
1245 
getCode(const std::string & n,const std::string & cn,const bool b) const1246   std::string BehaviourData::getCode(const std::string& n,
1247                                      const std::string& cn,
1248                                      const bool b) const {
1249     if (!b) {
1250       return this->getCodeBlock(n).code;
1251     }
1252     std::ostringstream out;
1253     writeStandardPerformanceProfilingBegin(out, cn, n);
1254     out << this->getCodeBlock(n).code;
1255     writeStandardPerformanceProfilingEnd(out);
1256     return out.str();
1257   }  // end of BehaviourData::getCode
1258 
hasCode(const std::string & n) const1259   bool BehaviourData::hasCode(const std::string& n) const {
1260     return this->cblocks.find(n) != this->cblocks.end();
1261   }
1262 
setParameterDefaultValue(const std::string & n,const double v)1263   void BehaviourData::setParameterDefaultValue(const std::string& n,
1264                                                const double v) {
1265     auto throw_if = [](const bool b, const std::string& m) {
1266       tfel::raise_if(b, "BehaviourData::setParameterDefaultValue: " + m);
1267     };
1268     throw_if(!this->parameters.contains(n), "no parameter '" + n + "' defined");
1269     const auto& p = this->parameters.getVariable(n);
1270     const auto f = SupportedTypes::getTypeFlag(p.type);
1271     throw_if(f != SupportedTypes::SCALAR,
1272              "parameter '" + n + "' is not a scalar");
1273     const auto op = this->overriding_parameters.find(n);
1274     if (op == this->overriding_parameters.end()) {
1275       throw_if(!this->parametersDefaultValues.insert({n, v}).second,
1276                "default value for parameter '" + n + "' already defined");
1277     } else {
1278       throw_if(!this->parametersDefaultValues.insert({n, op->second}).second,
1279                "default value for parameter '" + n + "' already defined");
1280     }
1281   }  // end of BehaviourData::setParameterDefaultValue
1282 
setParameterDefaultValue(const std::string & n,const unsigned short i,const double v)1283   void BehaviourData::setParameterDefaultValue(const std::string& n,
1284                                                const unsigned short i,
1285                                                const double v) {
1286     auto throw_if = [](const bool b, const std::string& m) {
1287       tfel::raise_if(b, "BehaviourData::setParameterDefaultValue: " + m);
1288     };
1289     throw_if(!this->parameters.contains(n), "no parameter '" + n + "' defined");
1290     const auto& p = this->parameters.getVariable(n);
1291     const auto f = SupportedTypes::getTypeFlag(p.type);
1292     throw_if(f != SupportedTypes::SCALAR,
1293              "parameter '" + n + "' is not a floatting point");
1294     throw_if(p.arraySize == 1,
1295              "parameter '" + n + "' has not been declared as an array");
1296     const auto idx = std::to_string(i);
1297     throw_if(i >= p.arraySize, "index " + idx + " is greater than parameter '" +
1298                                    n + "' array size");
1299     const auto n2 = n + '[' + idx + ']';
1300     //     const auto op = this->overriding_parameters.find(n2);
1301     //     if (op != this->overriding_parameters.end()) {
1302     //     }
1303     throw_if(!this->parametersDefaultValues.insert({n2, v}).second,
1304              "default value for parameter '" + n2 + "' already defined");
1305   }
1306 
setParameterDefaultValue(const std::string & n,const int v)1307   void BehaviourData::setParameterDefaultValue(const std::string& n,
1308                                                const int v) {
1309     auto throw_if = [](const bool b, const std::string& m) {
1310       tfel::raise_if(b, "BehaviourData::setParameterDefaultValue: " + m);
1311     };
1312     throw_if(!this->parameters.contains(n), "no parameter '" + n + "' defined");
1313     const auto& p = this->parameters.getVariable(n);
1314     throw_if(p.type != "int", "parameter '" + n + "' is not a floatting point");
1315     throw_if(!this->iParametersDefaultValues.insert({n, v}).second,
1316              "default value for parameter '" + n + "' already defined");
1317   }
1318 
setParameterDefaultValue(const std::string & n,const unsigned short v)1319   void BehaviourData::setParameterDefaultValue(const std::string& n,
1320                                                const unsigned short v) {
1321     auto throw_if = [](const bool b, const std::string& m) {
1322       tfel::raise_if(b, "BehaviourData::setParameterDefaultValue: " + m);
1323     };
1324     throw_if(!this->parameters.contains(n), "no parameter '" + n + "' defined");
1325     const auto& p = this->parameters.getVariable(n);
1326     throw_if(p.type != "ushort",
1327              "parameter '" + n + "' is not a floatting point");
1328     throw_if(!this->uParametersDefaultValues.insert({n, v}).second,
1329              "default value for parameter '" + n + "' already defined");
1330   }
1331 
getFloattingPointParameterDefaultValue(const std::string & n) const1332   double BehaviourData::getFloattingPointParameterDefaultValue(
1333       const std::string& n) const {
1334     auto throw_if = [](const bool b, const std::string& m) {
1335       tfel::raise_if(
1336           b, "BehaviourData::getFloattingPointParameterDefaultValue: " + m);
1337     };
1338     throw_if(!this->parameters.contains(n), "no parameter '" + n + "' defined");
1339     const auto p = this->parametersDefaultValues.find(n);
1340     throw_if(p == this->parametersDefaultValues.end(),
1341              "no default value defined for parameter '" + n + "'");
1342     return p->second;
1343   }  // end of BehaviourData::getFloattingPointParameterDefaultValue
1344 
getFloattingPointParameterDefaultValue(const std::string & n,const unsigned short i) const1345   double BehaviourData::getFloattingPointParameterDefaultValue(
1346       const std::string& n, const unsigned short i) const {
1347     auto throw_if = [](const bool b, const std::string& m) {
1348       tfel::raise_if(
1349           b, "BehaviourData::getFloattingPointParameterDefaultValue: " + m);
1350     };
1351     throw_if(!this->parameters.contains(n), "no parameter '" + n + "' defined");
1352     const auto& v = this->parameters.getVariable(n);
1353     throw_if(v.arraySize == 1u, "parameter '" + n + "' is not an array");
1354     throw_if(i >= v.arraySize, "invalid index for parameter '" + n + "'");
1355     const auto n2 = n + '[' + std::to_string(i) + ']';
1356     const auto p = this->parametersDefaultValues.find(n2);
1357     throw_if(p == this->parametersDefaultValues.end(),
1358              "no default value defined for parameter '" + n2 + "'");
1359     return p->second;
1360   }  // end of BehaviourData::getFloattingPointParameterDefaultValue
1361 
getIntegerParameterDefaultValue(const std::string & n) const1362   int BehaviourData::getIntegerParameterDefaultValue(
1363       const std::string& n) const {
1364     tfel::raise_if(!this->parameters.contains(n),
1365                    "BehaviourData::getIntegerParameterDefaultValue: "
1366                    "no parameter '" +
1367                        n + "' defined");
1368     auto p = this->iParametersDefaultValues.find(n);
1369     tfel::raise_if(p == this->iParametersDefaultValues.end(),
1370                    "BehaviourData::getIntegerParameterDefaultValue: "
1371                    "no default value defined for parameter '" +
1372                        n + "'");
1373     return p->second;
1374   }  // end of BehaviourData::getIntegerParameterDefaultValue
1375 
getUnsignedShortParameterDefaultValue(const std::string & n) const1376   unsigned short BehaviourData::getUnsignedShortParameterDefaultValue(
1377       const std::string& n) const {
1378     tfel::raise_if(!this->parameters.contains(n),
1379                    "BehaviourData::getUnsignedShortParameterDefaultValue: "
1380                    "no parameter '" +
1381                        n + "' defined");
1382     auto p = this->uParametersDefaultValues.find(n);
1383     tfel::raise_if(p == this->uParametersDefaultValues.end(),
1384                    "BehaviourData::getUnsignedShortParameterDefaultValue: "
1385                    "no default value defined for parameter '" +
1386                        n + "'");
1387     return p->second;
1388   }  // end of BehaviourData::getUnsignedShortParameterDefaultValue
1389 
setAttribute(const std::string & n,const BehaviourAttribute & a,const bool b)1390   void BehaviourData::setAttribute(const std::string& n,
1391                                    const BehaviourAttribute& a,
1392                                    const bool b) {
1393     auto throw_if = [](const bool c, const std::string& m) {
1394       tfel::raise_if(c, "BehaviourData::setAttribute: " + m);
1395     };
1396     auto p = this->attributes.find(n);
1397     if (p != this->attributes.end()) {
1398       throw_if(a.getTypeIndex() != p->second.getTypeIndex(),
1399                "attribute already exists with a different type");
1400     }
1401     if (!this->attributes.insert({n, a}).second) {
1402       throw_if(!b, "attribute '" + n + "' already declared");
1403     }
1404   }  // end of BehaviourData::setAttribute
1405 
updateAttribute(const std::string & n,const BehaviourAttribute & a)1406   void BehaviourData::updateAttribute(const std::string& n,
1407                                       const BehaviourAttribute& a) {
1408     auto throw_if = [](const bool c, const std::string& m) {
1409       tfel::raise_if(c, "BehaviourData::updateAttribute: " + m);
1410     };
1411     auto p = this->attributes.find(n);
1412     throw_if(p == this->attributes.end(), "unknown attribute '" + n + "'");
1413     throw_if(a.getTypeIndex() != p->second.getTypeIndex(),
1414              "attribute already exists with a different type");
1415     p->second = a;
1416   }  // end of BehaviourData::setAttribute
1417 
hasAttribute(const std::string & n) const1418   bool BehaviourData::hasAttribute(const std::string& n) const {
1419     return this->attributes.count(n) != 0u;
1420   }  // end of BehaviourData::hasAttribute
1421 
1422   const std::map<std::string, BehaviourAttribute>&
getAttributes() const1423   BehaviourData::getAttributes() const {
1424     return this->attributes;
1425   }  // end of BehaviourData::getAttributes
1426 
getCodeBlockNames() const1427   std::vector<std::string> BehaviourData::getCodeBlockNames() const {
1428     auto names = std::vector<std::string>{};
1429     for (const auto& c : this->cblocks) {
1430       names.push_back(c.first);
1431     }
1432     return names;
1433   }  // end of BehaviourData::getCodeBlockNames
1434 
hasGlossaryName(const std::string & n) const1435   bool BehaviourData::hasGlossaryName(const std::string& n) const {
1436     this->checkVariableName(n);
1437     return this->glossaryNames.find(n) != this->glossaryNames.end();
1438   }  // end of BehaviourData::hasGlossaryName
1439 
hasEntryName(const std::string & n) const1440   bool BehaviourData::hasEntryName(const std::string& n) const {
1441     this->checkVariableName(n);
1442     return this->entryNames.find(n) != this->entryNames.end();
1443   }  // end of BehaviourData::hasEntryName
1444 
getExternalName(const std::string & n) const1445   std::string BehaviourData::getExternalName(const std::string& n) const {
1446     this->checkVariableName(n);
1447     auto p = this->glossaryNames.find(n);
1448     if (p != this->glossaryNames.end()) {
1449       return p->second;
1450     }
1451     p = this->entryNames.find(n);
1452     if (p != this->entryNames.end()) {
1453       return p->second;
1454     }
1455     return n;
1456   }  // end of BehaviourData::getExternalName
1457 
getExternalNames(const VarContainer & v) const1458   std::vector<std::string> BehaviourData::getExternalNames(
1459       const VarContainer& v) const {
1460     return v.getExternalNames();
1461   }  // end of BehaviourData::getExternalNames
1462 
getExternalNames(std::vector<std::string> & names,const VarContainer & v) const1463   void BehaviourData::getExternalNames(std::vector<std::string>& names,
1464                                        const VarContainer& v) const {
1465     v.getExternalNames(names);
1466   }  // end of BehaviourData::getExternalNames
1467 
appendExternalNames(std::vector<std::string> & names,const VarContainer & v) const1468   void BehaviourData::appendExternalNames(std::vector<std::string>& names,
1469                                           const VarContainer& v) const {
1470     v.appendExternalNames(names);
1471   }  // end of BehaviourData::appendExternalNames
1472 
setGlossaryName(const std::string & n,const std::string & g)1473   void BehaviourData::setGlossaryName(const std::string& n,
1474                                       const std::string& g) {
1475     using tfel::glossary::Glossary;
1476     const auto& glossary = Glossary::getGlossary();
1477     tfel::raise_if(!glossary.contains(g),
1478                    "BehaviourData::setGlossaryName: "
1479                    "'" +
1480                        g + "' is not a glossary name");
1481     bool treated = false;
1482     auto set_glossary_name = [&n, &g,
1483                               &treated](VariableDescriptionContainer& c) {
1484       if (c.contains(n)) {
1485         c.getVariable(n).setGlossaryName(g);
1486         treated = true;
1487       }
1488     };
1489     this->checkVariableName(n);
1490     BehaviourDataAddToGlossaryOrEntryNames(
1491         this->glossaryNames, this->glossaryNames, this->entryNames,
1492         this->reservedNames, n, glossary.getGlossaryEntry(g).getKey());
1493     set_glossary_name(this->materialProperties);
1494     set_glossary_name(this->localVariables);
1495     set_glossary_name(this->stateVariables);
1496     set_glossary_name(this->auxiliaryStateVariables);
1497     set_glossary_name(this->integrationVariables);
1498     set_glossary_name(this->persistentVariables);
1499     set_glossary_name(this->externalStateVariables);
1500     set_glossary_name(this->parameters);
1501     tfel::raise_if(!treated,
1502                    "BehaviourData::setGlossaryName: "
1503                    "no variable named '" +
1504                        n + "'");
1505   }  // end of BehaviourData::addGlossaryName
1506 
isGlossaryNameUsed(const std::string & n) const1507   bool BehaviourData::isGlossaryNameUsed(const std::string& n) const {
1508     using namespace tfel::glossary;
1509     const auto& g = Glossary::getGlossary();
1510     tfel::raise_if(!g.contains(n),
1511                    "BehaviourData::isGlossaryNameUsed: "
1512                    "'" +
1513                        n + "' is not a glossary name");
1514     for (const auto& gn : this->glossaryNames) {
1515       if (gn.second == n) {
1516         return true;
1517       }
1518     }
1519     return false;
1520   }  // end of BehaviourData::isGlossaryName
1521 
setEntryName(const std::string & n,const std::string & e)1522   void BehaviourData::setEntryName(const std::string& n, const std::string& e) {
1523     using namespace tfel::glossary;
1524     const auto& glossary = Glossary::getGlossary();
1525     bool treated = false;
1526     auto set_entry_name = [&n, &e, &treated](VariableDescriptionContainer& c) {
1527       if (c.contains(n)) {
1528         c.getVariable(n).setEntryName(e);
1529         treated = true;
1530       }
1531     };
1532     if (glossary.contains(e)) {
1533       std::ostringstream msg;
1534       msg << "BehaviourData::setEntryName: "
1535           << "'" << e << "' is a glossary name. " << std::endl
1536           << "Please use 'setGlossaryName' method instead or choose another "
1537              "entry name.";
1538       displayGlossaryEntryCompleteDescription(msg,
1539                                               glossary.getGlossaryEntry(e));
1540       tfel::raise(msg.str());
1541     }
1542     tfel::raise_if(!tfel::utilities::CxxTokenizer::isValidIdentifier(e, false),
1543                    "BehaviourData::setEntryName: "
1544                    "'" +
1545                        e + "' is a not a valid entry name");
1546     this->checkVariableName(n);
1547     BehaviourDataAddToGlossaryOrEntryNames(
1548         this->entryNames, this->glossaryNames, this->entryNames,
1549         this->reservedNames, n, e);
1550     set_entry_name(this->materialProperties);
1551     set_entry_name(this->localVariables);
1552     set_entry_name(this->stateVariables);
1553     set_entry_name(this->auxiliaryStateVariables);
1554     set_entry_name(this->integrationVariables);
1555     set_entry_name(this->persistentVariables);
1556     set_entry_name(this->externalStateVariables);
1557     set_entry_name(this->parameters);
1558     tfel::raise_if(!treated,
1559                    "BehaviourData::setEntryName: "
1560                    "no variable named '" +
1561                        n + "'");
1562   }  // end of BehaviourData::addEntryName
1563 
isUsedAsEntryName(const std::string & n) const1564   bool BehaviourData::isUsedAsEntryName(const std::string& n) const {
1565     for (const auto& en : this->entryNames) {
1566       if (en.second == n) {
1567         return true;
1568       }
1569     }
1570     return false;
1571   }  // end of BehaviourData::isEntryName
1572 
getVariableNameFromGlossaryNameOrEntryName(const std::string & n) const1573   std::string BehaviourData::getVariableNameFromGlossaryNameOrEntryName(
1574       const std::string& n) const {
1575     for (const auto& e : this->glossaryNames) {
1576       if (e.second == n) {
1577         return e.first;
1578       }
1579     }
1580     for (const auto& e : this->entryNames) {
1581       if (e.second == n) {
1582         return e.first;
1583       }
1584     }
1585     tfel::raise(
1586         "BehaviourData::getVariableNameFromGlossaryNameOrEntryName: "
1587         "no variable with glossary or entry name '" +
1588         n + "'");
1589   }  // end of BehaviourData::getVariableNameFromGlossaryNameOrEntryName
1590 
getParameters() const1591   const VariableDescriptionContainer& BehaviourData::getParameters() const {
1592     return this->parameters;
1593   }  // end of BehaviourData::getParameters
1594 
appendToMembers(const std::string & c)1595   void BehaviourData::appendToMembers(const std::string& c) {
1596     this->members += c;
1597     if (!this->members.empty()) {
1598       if (*(this->members.rbegin()) != '\n') {
1599         this->members += '\n';
1600       }
1601     }
1602   }  // end of BehaviourData::appendToMembers
1603 
getMembers() const1604   std::string BehaviourData::getMembers() const {
1605     return this->members;
1606   }  // end of BehaviourData::getMembers
1607 
appendToPrivateCode(const std::string & c)1608   void BehaviourData::appendToPrivateCode(const std::string& c) {
1609     this->privateCode += c;
1610     if (!this->privateCode.empty()) {
1611       if (*(this->privateCode.rbegin()) != '\n') {
1612         this->privateCode += '\n';
1613       }
1614     }
1615   }  // end of BehaviourData::appendToPrivateCode
1616 
getPrivateCode() const1617   std::string BehaviourData::getPrivateCode() const {
1618     return this->privateCode;
1619   }  // end of BehaviourData::getPrivateCode
1620 
addStressFreeExpansion(const StressFreeExpansionDescription & sfed)1621   void BehaviourData::addStressFreeExpansion(
1622       const StressFreeExpansionDescription& sfed) {
1623     auto throw_if = [](const bool c, const std::string& m) {
1624       tfel::raise_if(c, "BehaviourData::addStressFreeExpansion: " + m);
1625     };
1626     auto check_esv = [this, &throw_if](const SFED_ESV& h) {
1627       throw_if(!this->isExternalStateVariableName(h.vname),
1628                "'" + h.vname + "' is not an external state variable name");
1629       const auto& ev = this->getExternalStateVariables().getVariable(h.vname);
1630       throw_if(ev.arraySize != 1u,
1631                "invalid arrary size of variable '" + h.vname + "'");
1632     };
1633     auto check_esv2 = [this, &throw_if](const SFED_ESV& h) {
1634       throw_if(!this->isExternalStateVariableName(h.vname),
1635                "'" + h.vname + "' is not an external state variable name");
1636       const auto& ev = this->getExternalStateVariables().getVariable(h.vname);
1637       throw_if(ev.arraySize != 3u,
1638                "invalid arrary size of variable '" + h.vname + "'");
1639     };
1640     auto treat = [&check_esv, &throw_if,
1641                   this](const StressFreeExpansionHandler& h) {
1642       if (h.is<SFED_ESV>()) {
1643         check_esv(h.get<SFED_ESV>());
1644       } else if (h.is<std::shared_ptr<ModelDescription>>()) {
1645         const auto& md = *(h.get<std::shared_ptr<ModelDescription>>());
1646         throw_if(!md.constantMaterialProperties.empty(),
1647                  "constant material properties are not supported yet");
1648         throw_if(md.functions.size() != 1u,
1649                  "invalid number of functions in model '" + md.className + "'");
1650         throw_if(md.functions[0].name.empty(), "invalid function name");
1651         throw_if(md.functions[0].modifiedVariables.size() != 1u,
1652                  "invalid number of modified variables in function '" +
1653                      md.functions[0].name + "' in model '" + md.className +
1654                      "'");
1655         // checking output
1656         throw_if(md.outputs.size() != 1u,
1657                  "external model must have one and only output");
1658         // checking inputs
1659         for (const auto& i : md.inputs) {
1660           throw_if(i.arraySize != 1u,
1661                    "invalid array size for model variable '" + i.name + "'");
1662           // external name
1663           const auto& n = i.getExternalName();
1664           // check that an external state variable with the same
1665           // external state variable exists
1666           const auto& evnames =
1667               this->getExternalNames(this->getExternalStateVariables());
1668           if (n == tfel::glossary::Glossary::Temperature) {
1669             continue;
1670           }
1671           if ((std::find(std::begin(evnames), std::end(evnames), n) ==
1672                std::end(evnames))) {
1673             // adding a new state variable with given external name
1674             auto v = i;
1675             v.name = md.className + "_" + v.name;
1676             this->addExternalStateVariable(v, UNREGISTRED);
1677           }
1678         }
1679         // declaring the output has an auxiliary state variable
1680         auto o = md.outputs[0];
1681         o.name = md.className + "_" + o.name;
1682         this->addAuxiliaryStateVariable(o, UNREGISTRED);
1683       } else if (h.is<NullExpansion>()) {
1684         // do nothing
1685       } else {
1686         throw_if(true, "unsupported stress free expansion handler");
1687       }
1688     };
1689     if (sfed.is<VolumeSwellingStressFreeExpansion>()) {
1690       const auto& s = sfed.get<VolumeSwellingStressFreeExpansion>();
1691       throw_if(s.sfe.is<NullExpansion>(), "null swelling is not allowed");
1692       treat(s.sfe);
1693     } else if (sfed.is<IsotropicStressFreeExpansion>()) {
1694       const auto& s = sfed.get<IsotropicStressFreeExpansion>();
1695       throw_if(s.sfe.is<NullExpansion>(), "null swelling is not allowed");
1696       treat(s.sfe);
1697     } else if (sfed.is<AxialGrowth>()) {
1698       const auto& s = sfed.get<AxialGrowth>();
1699       throw_if(s.sfe.is<NullExpansion>(), "null swelling is not allowed");
1700       treat(s.sfe);
1701     } else if (sfed.is<Relocation>()) {
1702       const auto& s = sfed.get<Relocation>();
1703       throw_if(s.sfe.is<NullExpansion>(), "null swelling is not allowed");
1704       treat(s.sfe);
1705     } else if (sfed.is<OrthotropicStressFreeExpansion>()) {
1706       const auto& s = sfed.get<OrthotropicStressFreeExpansion>();
1707       throw_if(s.sfe0.is<NullExpansion>() && s.sfe1.is<NullExpansion>() &&
1708                    s.sfe2.is<NullExpansion>(),
1709                "null swelling is not allowed");
1710       treat(s.sfe0);
1711       treat(s.sfe1);
1712       treat(s.sfe2);
1713     } else if (sfed.is<OrthotropicStressFreeExpansionII>()) {
1714       const auto& s = sfed.get<OrthotropicStressFreeExpansionII>();
1715       check_esv2(s.esv);
1716     } else {
1717       throw_if(true, "internal error, unsupported stress free expansion type");
1718     }
1719     this->sfeds.push_back(sfed);
1720   }  // end of BehaviourData::addStressFreeExpansion
1721 
1722   const std::vector<BehaviourData::StressFreeExpansionDescription>&
getStressFreeExpansionDescriptions() const1723   BehaviourData::getStressFreeExpansionDescriptions() const {
1724     return this->sfeds;
1725   }  // end of BehaviourData::getStressFreeExpansionDescriptions
1726 
isStressFreeExansionAnisotropic() const1727   bool BehaviourData::isStressFreeExansionAnisotropic() const {
1728     for (const auto& sfed : this->sfeds) {
1729       if ((sfed.is<BehaviourData::AxialGrowth>()) ||
1730           (sfed.is<BehaviourData::Relocation>()) ||
1731           (sfed.is<BehaviourData::OrthotropicStressFreeExpansion>()) ||
1732           (sfed.is<BehaviourData::OrthotropicStressFreeExpansionII>())) {
1733         return true;
1734       } else {
1735         tfel::raise_if(
1736             (!sfed.is<BehaviourData::IsotropicStressFreeExpansion>()) &&
1737                 (!sfed.is<BehaviourData::VolumeSwellingStressFreeExpansion>()),
1738             "BehaviourData::isStressFreeExansionAnisotropic: "
1739             "internal error, unsupported stress "
1740             "free expansion type");
1741       }
1742     }
1743     return false;
1744   }  // end of BehaviourData::isStressFreeExansionAnisotropic
1745 
getSymbols(std::map<std::string,std::string> & symbols) const1746   void BehaviourData::getSymbols(
1747       std::map<std::string, std::string>& symbols) const {
1748     mfront::getSymbols(symbols, this->materialProperties);
1749     mfront::getSymbols(symbols, this->persistentVariables);
1750     mfront::getSymbols(symbols, this->integrationVariables);
1751     mfront::getSymbols(symbols, this->stateVariables);
1752     mfront::getSymbols(symbols, this->auxiliaryStateVariables);
1753     mfront::getSymbols(symbols, this->externalStateVariables);
1754     mfront::getSymbols(symbols, this->localVariables);
1755     mfront::getSymbols(symbols, this->parameters);
1756   }  // end of BehaviourData::getSymbols
1757 
overrideByAParameter(const std::string & n,const double v)1758   void BehaviourData::overrideByAParameter(const std::string& n,
1759                                            const double v) {
1760     if (this->overriding_parameters.count(n) != 0) {
1761       tfel::raise(
1762           "BehaviourData::overrideByAParameter: "
1763           "an override for variable '" +
1764           n + "' has already been specified");
1765     }
1766     this->overriding_parameters[n] = v;
1767   }  // end of BehaviourData::overrideByAParameter
1768 
1769   BehaviourData::~BehaviourData() = default;
1770 
1771 }  // end of namespace mfront
1772