1 /*!
2  * \file   mtest/src/SchemeBase.cxx
3  * \brief
4  * \author Thomas Helfer
5  * \date   02 oct. 2015
6  * \copyright Copyright (C) 2006-2018 CEA/DEN, EDF R&D. All rights
7  * reserved.
8  * This project is publicly released under either the GNU GPL Licence
9  * or the CECILL-A licence. A copy of thoses licences are delivered
10  * with the sources of TFEL. CEA or EDF may also distribute this
11  * project under specific licensing conditions.
12  */
13 
14 #include <sstream>
15 #include <algorithm>
16 
17 #include "TFEL/Raise.hxx"
18 #include "MFront/MFrontLogStream.hxx"
19 #include "MTest/AccelerationAlgorithmFactory.hxx"
20 #include "MTest/CastemAccelerationAlgorithm.hxx"
21 #include "MTest/Evolution.hxx"
22 #include "MTest/SchemeBase.hxx"
23 
24 namespace mtest {
25 
SchemeBase()26   SchemeBase::SchemeBase() : evm(new EvolutionManager()) {
27     // declare time variable
28     this->declareVariable("t", true);
29   }  // end of SchemeBase::SchemeBase
30 
addEvolution(const std::string & n,const EvolutionPtr p,const bool b1,const bool b2)31   void SchemeBase::addEvolution(const std::string& n,
32                                 const EvolutionPtr p,
33                                 const bool b1,
34                                 const bool b2) {
35     if (b1) {
36       this->declareVariable(n, b1);
37     } else {
38       tfel::raise_if(std::find(this->vnames.begin(), this->vnames.end(), n) ==
39                          this->vnames.end(),
40                      "SchemeBase::addEvolution: "
41                      "variable '" +
42                          n + "' is not defined");
43     }
44     if (b2) {
45       tfel::raise_if(this->evm->find(n) != this->evm->end(),
46                      "SchemeBase::addEvolution: "
47                      "evolution '" +
48                          n + "' already defined");
49     }
50     (*(this->evm))[n] = p;
51   } // end of SchemeBase::addEvolution
52 
setEvolutionValue(const std::string & n,const real t,const real v)53   void SchemeBase::setEvolutionValue(const std::string& n,
54                                      const real t,
55                                      const real v) {
56     const auto pev = this->evm->find(n);
57     tfel::raise_if(
58         pev == this->evm->end(),
59         "SchemeBase::setEvolutionValue : no evolution '" + n + "' declared");
60     pev->second->setValue(t, v);
61   }  // end of SchemeBase::setEvolutionValue
62 
getEvolutions() const63   const EvolutionManager& SchemeBase::getEvolutions() const {
64     return *(this->evm);
65   }  // end of SchemeBase::getEvolutions() const
66 
setTimes(const std::vector<real> & t)67   void SchemeBase::setTimes(const std::vector<real>& t) {
68     tfel::raise_if(!this->times.empty(),
69                    "SchemeBase::setTimes: "
70                    "times already defined");
71     this->times = t;
72   }  // end of SchemeBase::setTimes
73 
setMaximumNumberOfIterations(const unsigned int i)74   void SchemeBase::setMaximumNumberOfIterations(const unsigned int i) {
75     tfel::raise_if(this->options.iterMax != -1,
76                    "SchemeBase::setMaximumNumberOfIterations: "
77                    "the maximum number of iterations "
78                    "has already been declared");
79     tfel::raise_if(i == 0,
80                    "SchemeBase::setMaximumNumberOfIterations: "
81                    "invalid number of iterations");
82     this->options.iterMax = static_cast<int>(i);
83   }
84 
setMaximumNumberOfSubSteps(const unsigned int i)85   void SchemeBase::setMaximumNumberOfSubSteps(const unsigned int i) {
86     tfel::raise_if(this->options.mSubSteps != -1,
87                    "SchemeBase::setMaximumNumberOfSubSteps: "
88                    "the maximum number of sub steps "
89                    "has already been declared");
90     tfel::raise_if(i == 0,
91                    "SchemeBase::setMaximumNumberOfSubSteps: "
92                    "invalid number of sub steps");
93     this->options.mSubSteps = static_cast<int>(i);
94   }
95 
setOutputFrequency(const OutputFrequency o)96   void SchemeBase::setOutputFrequency(const OutputFrequency o) {
97     this->output_frequency = o;
98   }
99 
setDynamicTimeStepScaling(const bool b)100   void SchemeBase::setDynamicTimeStepScaling(const bool b) {
101     this->options.dynamic_time_step_scaling = b;
102   }
103 
setMaximalTimeStep(const real v)104   void SchemeBase::setMaximalTimeStep(const real v) {
105     TFEL_CONSTEXPR const auto emin = 100 * std::numeric_limits<real>::min();
106     TFEL_CONSTEXPR const auto eps = 100 * std::numeric_limits<real>::epsilon();
107     tfel::raise_if(this->options.maximal_time_step > 0,
108                    "SchemeBase::setMaximalTimeStep: "
109                    "the maximal time step "
110                    "has already been declared");
111     if (this->options.minimal_time_step > 0) {
112       tfel::raise_if(v <= this->options.minimal_time_step,
113                      "SchemeBase::setMaximalTimeStep: "
114                      "the specified maximal time step "
115                      "is lower than the minimal time step");
116       tfel::raise_if((std::abs(v - this->options.minimal_time_step) < emin) ||
117                          (std::abs(v - this->options.minimal_time_step) < eps),
118                      "SchemeBase::setMaximalTimeStep: "
119                      "the minimal and the maximal time step are too close");
120     }
121     tfel::raise_if(v <= emin,
122                    "SchemeBase::setMaximalTimeStep: "
123                    "the maximal time step is either negative or too small");
124     this->options.maximal_time_step = v;
125   }
126 
setMinimalTimeStep(const real v)127   void SchemeBase::setMinimalTimeStep(const real v) {
128     TFEL_CONSTEXPR const auto emin = 100 * std::numeric_limits<real>::min();
129     TFEL_CONSTEXPR const auto eps = 100 * std::numeric_limits<real>::epsilon();
130     tfel::raise_if(this->options.minimal_time_step > 0,
131                    "SchemeBase::setMinimalTimeStep: "
132                    "the minimal time step "
133                    "has already been declared");
134     if (this->options.maximal_time_step > 0) {
135       tfel::raise_if(v >= this->options.maximal_time_step,
136                      "SchemeBase::setMinimalTimeStep: "
137                      "the specified minimal time step "
138                      "is greater than the maximal time step");
139       const auto d = std::abs(this->options.maximal_time_step - v);
140       tfel::raise_if((d < emin) || (d < eps * this->options.maximal_time_step),
141                      "SchemeBase::setMinimalTimeStep: "
142                      "the maximal and the minimal time step are too close");
143     }
144     tfel::raise_if(v <= emin,
145                    "SchemeBase::setMinimalTimeStep: "
146                    "the specified minimal time step is "
147                    "either negative or too small");
148     this->options.minimal_time_step = v;
149   }
150 
setMinimalTimeStepScalingFactor(const real v)151   void SchemeBase::setMinimalTimeStepScalingFactor(const real v) {
152     tfel::raise_if(this->options.minimal_time_step_scaling_factor > 0,
153                    "SchemeBase::setMinimalTimeStepScalingFactor: "
154                    "the minimal time step scaling factor "
155                    "has already been declared");
156     tfel::raise_if(v >= 1,
157                    "SchemeBase::setMinimalTimeStepScalingFactor: "
158                    "the minimal time step scaling factor "
159                    "is greater than one ");
160     tfel::raise_if(v <= 100 * std::numeric_limits<real>::epsilon(),
161                    "SchemeBase::setMinimalTimeStepScalingFactor: "
162                    "the minimal time step scaling is either "
163                    "negative or too small");
164     this->options.minimal_time_step_scaling_factor = v;
165   }
166 
setMaximalTimeStepScalingFactor(const real v)167   void SchemeBase::setMaximalTimeStepScalingFactor(const real v) {
168     tfel::raise_if(this->options.maximal_time_step_scaling_factor > 0,
169                    "SchemeBase::setMaximalTimeStepScalingFactor: "
170                    "the maximal time step scaling factor "
171                    "has already been declared");
172     tfel::raise_if(v < 1,
173                    "SchemeBase::setMaximalTimeStepScalingFactor: "
174                    "the maximal time step scaling factor "
175                    "is lower than one ");
176     this->options.maximal_time_step_scaling_factor = v;
177   }
178 
setDescription(const std::string & d)179   void SchemeBase::setDescription(const std::string& d) {
180     tfel::raise_if(!this->description.empty(),
181                    "SchemeBase::setDescription: "
182                    "description already set.");
183     this->description = d;
184   }  // end of SchemeBase::setDescription
185 
setAuthor(const std::string & a)186   void SchemeBase::setAuthor(const std::string& a) {
187     tfel::raise_if(!this->author.empty(),
188                    "SchemeBase::setAuthor: "
189                    "author already set.");
190     this->author = a;
191   }  // end of SchemeBase::setAuthor
192 
setDate(const std::string & d)193   void SchemeBase::setDate(const std::string& d) {
194     tfel::raise_if(!this->date.empty(),
195                    "SchemeBase::setDate: "
196                    "date already set.");
197     this->date = d;
198   }  // end of SchemeBase::setDate
199 
setModellingHypothesis(const std::string & h)200   void SchemeBase::setModellingHypothesis(const std::string& h) {
201     tfel::raise_if(this->hypothesis != ModellingHypothesis::UNDEFINEDHYPOTHESIS,
202                    "SchemeBase::setModellingHypothesis: "
203                    "the modelling hypothesis is already defined");
204     this->hypothesis = ModellingHypothesis::fromString(h);
205   }  // end of SchemeBase::setModellingHypothesis
206 
207   tfel::material::ModellingHypothesis::Hypothesis
getModellingHypothesis() const208   SchemeBase::getModellingHypothesis() const {
209     tfel::raise_if(this->hypothesis == ModellingHypothesis::UNDEFINEDHYPOTHESIS,
210                    "SchemeBase::getModellingHypothesis: "
211                    "the modelling hypothesis is not defined");
212     return this->hypothesis;
213   }
214 
getDimension() const215   unsigned short SchemeBase::getDimension() const {
216     tfel::raise_if(this->hypothesis == ModellingHypothesis::UNDEFINEDHYPOTHESIS,
217                    "SchemeBase::getDimension: "
218                    "the modelling hypothesis is "
219                    "not defined");
220     return tfel::material::getSpaceDimension(this->hypothesis);
221   }
222 
setAccelerationAlgorithm(const std::string & a)223   void SchemeBase::setAccelerationAlgorithm(const std::string& a) {
224     tfel::raise_if(this->options.aa != nullptr,
225                    "SchemeBase::setAccelerationAlgorithm: "
226                    "acceleration algorithm already set");
227     auto& f = AccelerationAlgorithmFactory::getAccelerationAlgorithmFactory();
228     this->options.aa = f.getAlgorithm(a);
229   }
230 
setAccelerationAlgorithmParameter(const std::string & p,const std::string & v)231   void SchemeBase::setAccelerationAlgorithmParameter(const std::string& p,
232                                                      const std::string& v) {
233     tfel::raise_if(this->options.aa == nullptr,
234                    "SchemeBase::setAccelerationAlgorithmParameter: "
235                    "no acceleration algorithm set");
236     this->options.aa->setParameter(p, v);
237   }
238 
setPredictionPolicy(const PredictionPolicy p)239   void SchemeBase::setPredictionPolicy(const PredictionPolicy p) {
240     tfel::raise_if(
241         this->options.ppolicy != PredictionPolicy::UNSPECIFIEDPREDICTIONPOLICY,
242         "SchemeBase::setPredictionPolicy: "
243         "prediction policy already declared");
244     this->options.ppolicy = p;
245   }  // end of SchemeBase::setPredictionPolicy
246 
setStiffnessMatrixType(const StiffnessMatrixType k)247   void SchemeBase::setStiffnessMatrixType(const StiffnessMatrixType k) {
248     tfel::raise_if(this->options.ktype !=
249                        StiffnessMatrixType::UNSPECIFIEDSTIFFNESSMATRIXTYPE,
250                    "SchemeBase::setStiffnessMatrixType: "
251                    "stiffness matrix type already specificed");
252     this->options.ktype = k;
253   }
254 
setUseCastemAccelerationAlgorithm(const bool ucaa)255   void SchemeBase::setUseCastemAccelerationAlgorithm(const bool ucaa) {
256     if (ucaa) {
257       tfel::raise_if(this->options.aa != nullptr,
258                      "SchemeBase::setUseCastemAccelerationAlgorithm: "
259                      "an algorithm was already set");
260       this->options.aa = std::shared_ptr<AccelerationAlgorithm>(
261           new CastemAccelerationAlgorithm);
262     }
263     this->options.useCastemAcceleration = ucaa;
264   }
265 
setCastemAccelerationTrigger(const int i)266   void SchemeBase::setCastemAccelerationTrigger(const int i) {
267     tfel::raise_if(!this->options.useCastemAcceleration,
268                    "SchemeBase::setCastemAccelerationTrigger: "
269                    "the castem acceleration algorithm has "
270                    "not been set using the "
271                    "@UseCast3mAccelerationAlgorithm keyword. "
272                    "If the Cast3M acceleration algorithm "
273                    "was specified using the "
274                    "@AccelerationAlgorithm keyword, please "
275                    "use the @AccelerationAlgorithmParameter "
276                    "keyword to specify the acceleration trigger.");
277     tfel::raise_if(this->options.aa == nullptr,
278                    "SchemeBase::setCastemAccelerationTrigger: "
279                    "internal error");
280     std::ostringstream nb;
281     nb << i;
282     this->options.aa->setParameter("AccelerationTrigger", nb.str());
283   }
284 
setCastemAccelerationPeriod(const int p)285   void SchemeBase::setCastemAccelerationPeriod(const int p) {
286     tfel::raise_if(!this->options.useCastemAcceleration,
287                    "SchemeBase::setCastemAccelerationPeriod: "
288                    "the castem acceleration algorithm has not "
289                    "been set using the "
290                    "@UseCast3mAccelerationAlgorithm keyword. "
291                    "If the Cast3M acceleration algorithm was "
292                    "specified using the @AccelerationAlgorithm "
293                    "keyword, please use the "
294                    "@AccelerationAlgorithmParameter keyword to "
295                    "specify the acceleration period.");
296     tfel::raise_if(this->options.aa == nullptr,
297                    "SchemeBase::setCastemAccelerationPeriod: "
298                    "internal error");
299     std::ostringstream nb;
300     nb << p;
301     this->options.aa->setParameter("AccelerationPeriod", nb.str());
302   }
303 
setStiffnessUpdatingPolicy(const StiffnessUpdatingPolicy p)304   void SchemeBase::setStiffnessUpdatingPolicy(const StiffnessUpdatingPolicy p) {
305     tfel::raise_if(
306         this->options.ks !=
307             StiffnessUpdatingPolicy::UNSPECIFIEDSTIFFNESSUPDATINGPOLICY,
308         "SchemeBase::setStiffnessUpdatePolicy: "
309         "stiffness matrix type already specificed");
310     this->options.ks = p;
311   }  // end of SchemeBase::setStiffnessUpdatingPolicy
312 
resetOutputFile()313   void SchemeBase::resetOutputFile() {
314     // output file
315     if (!this->output.empty()) {
316       this->out.close();
317       this->out.open(this->output.c_str());
318       tfel::raise_if(!this->out,
319                      "SchemeBase::resetOutputFile: "
320                      "can't open file '" +
321                          this->output + "'");
322       this->out.exceptions(std::ofstream::failbit | std::ofstream::badbit);
323       if (this->oprec != -1) {
324         this->out.precision(static_cast<std::streamsize>(this->oprec));
325       }
326     }
327     // residual file
328     if (!this->residualFileName.empty()) {
329       this->residual.close();
330       this->residual.open(this->residualFileName.c_str());
331       tfel::raise_if(!this->residual,
332                      "SchemeBase::resetOutputFile: "
333                      "unable to open file '" +
334                          this->residualFileName + "'");
335       this->residual.exceptions(std::ofstream::failbit | std::ofstream::badbit);
336       if (this->rprec != -1) {
337         this->residual.precision(static_cast<std::streamsize>(this->rprec));
338       } else {
339         if (this->oprec != -1) {
340           this->residual.precision(static_cast<std::streamsize>(this->oprec));
341         }
342       }
343     }
344   }  // end of resetOutputFile
345 
completeInitialisation()346   void SchemeBase::completeInitialisation() {
347     tfel::raise_if(this->initialisationFinished,
348                    "SchemeBase::completeInitialisation : "
349                    "object already initialised");
350     // initialisation is complete
351     this->initialisationFinished = true;
352     try {
353       if (this->hypothesis == ModellingHypothesis::UNDEFINEDHYPOTHESIS) {
354         this->setDefaultModellingHypothesis();
355       }
356       // numerical parameters
357       if (this->options.mSubSteps == -1) {
358         this->options.mSubSteps = 10;
359       }
360       if (this->options.iterMax == -1) {
361         this->options.iterMax = 100;
362       }
363       if (this->options.aa != nullptr) {
364         this->options.aa->initialize(this->getNumberOfUnknowns());
365       }
366       // prediction policy
367       if (this->options.ppolicy ==
368           PredictionPolicy::UNSPECIFIEDPREDICTIONPOLICY) {
369         this->options.ppolicy = PredictionPolicy::NOPREDICTION;
370       }
371       // stiffness matrix type
372       if (this->options.ktype ==
373           StiffnessMatrixType::UNSPECIFIEDSTIFFNESSMATRIXTYPE) {
374         this->options.ktype = this->getDefaultStiffnessMatrixType();
375       }
376       // options selected
377       if (mfront::getVerboseMode() >= mfront::VERBOSE_LEVEL1) {
378         auto& log = mfront::getLogStream();
379         if (this->options.aa != nullptr) {
380           log << "** " << this->options.aa->getName()
381               << " acceleration algorithm selected\n";
382         }
383         if (this->options.ppolicy == PredictionPolicy::LINEARPREDICTION) {
384           log << "** using linear prediction\n";
385         } else if (this->options.ppolicy ==
386                    PredictionPolicy::ELASTICPREDICTION) {
387           log << "** prediction using elastic stiffness\n";
388         } else if (this->options.ppolicy ==
389                    PredictionPolicy::ELASTICPREDICTIONFROMMATERIALPROPERTIES) {
390           log << "** prediction using elastic stiffness computed from material "
391                  "properties\n";
392         } else if (this->options.ppolicy ==
393                    PredictionPolicy::TANGENTOPERATORPREDICTION) {
394           log << "** prediction using tangent operator\n";
395         } else {
396           tfel::raise_if(
397               this->options.ppolicy != PredictionPolicy::NOPREDICTION,
398               "MTest::completeInitialisation : "
399               "internal error, unsupported "
400               "prediction policy");
401           log << "** no prediction\n";
402         }
403       }
404       this->resetOutputFile();
405     } catch (...) {
406       this->initialisationFinished = false;
407       throw;
408     }
409   }  // end of SchemeBase::completeInitialisation
410 
declareVariable(const std::string & v,const bool check)411   void SchemeBase::declareVariable(const std::string& v, const bool check) {
412     if (std::find(this->vnames.begin(), this->vnames.end(), v) !=
413         this->vnames.end()) {
414       tfel::raise_if(check,
415                      "SchemeBase::declareVariable: "
416                      "variable '" +
417                          v + "' already declared");
418     } else {
419       this->vnames.push_back(v);
420     }
421   }
422 
declareVariables(const std::vector<std::string> & v,const bool check)423   void SchemeBase::declareVariables(const std::vector<std::string>& v,
424                                     const bool check) {
425     for (const auto& n : v) {
426       this->declareVariable(n, check);
427     }
428   }
429 
setOutputFileName(const std::string & o)430   void SchemeBase::setOutputFileName(const std::string& o) {
431     tfel::raise_if(!this->output.empty(),
432                    "SchemeBase::setOutputFileName: "
433                    "output file name already defined");
434     this->output = o;
435   }
436 
isOutputFileNameDefined() const437   bool SchemeBase::isOutputFileNameDefined() const {
438     return !this->output.empty();
439   }
440 
setOutputFilePrecision(const unsigned int p)441   void SchemeBase::setOutputFilePrecision(const unsigned int p) {
442     tfel::raise_if(this->oprec != -1,
443                    "SchemeBase::setOutputFileName: "
444                    "output file precision already defined");
445     this->oprec = static_cast<int>(p);
446   }
447 
setResidualFileName(const std::string & o)448   void SchemeBase::setResidualFileName(const std::string& o) {
449     tfel::raise_if(!this->residualFileName.empty(),
450                    "SchemeBase::setResidualFileName : "
451                    "residual file name already defined");
452     this->residualFileName = o;
453   }
454 
isResidualFileNameDefined() const455   bool SchemeBase::isResidualFileNameDefined() const {
456     return !this->residualFileName.empty();
457   }
458 
setResidualFilePrecision(const unsigned int p)459   void SchemeBase::setResidualFilePrecision(const unsigned int p) {
460     tfel::raise_if(this->rprec != -1,
461                    "SchemeBase::setResidualFileName: "
462                    "residual file precision already defined");
463     this->rprec = static_cast<int>(p);
464   }
465 
setXMLOutputFileName(const std::string & o)466   void SchemeBase::setXMLOutputFileName(const std::string& o) {
467     tfel::raise_if(!this->xmlFileName.empty(),
468                    "SchemeBase::setXMLOutputFileName : "
469                    "XMLOutput file name already defined");
470     this->xmlFileName = o;
471   }
472 
isXMLOutputFileNameDefined() const473   bool SchemeBase::isXMLOutputFileNameDefined() const {
474     return !this->xmlFileName.empty();
475   }
476 
getXMLOutputFileName() const477   std::string SchemeBase::getXMLOutputFileName() const {
478     tfel::raise_if(this->xmlFileName.empty(),
479                    "SchemeBase::getXMLOutputFileName : "
480                    "XML output file name not defined");
481     return this->xmlFileName;
482   }
483 
484   SchemeBase::~SchemeBase() = default;
485 
486 }  // end of namespace mtest
487