1 /*!
2  * \file   StandardElastoViscoPlasticityBrick.cxx
3  * \brief
4  * \author Thomas Helfer
5  * \date   17/03/2018
6  */
7 
8 #include "TFEL/Raise.hxx"
9 #include "TFEL/Utilities/Data.hxx"
10 #include "MFront/ImplicitDSLBase.hxx"
11 #include "MFront/NonLinearSystemSolver.hxx"
12 #include "MFront/BehaviourBrick/StressPotential.hxx"
13 #include "MFront/BehaviourBrick/StressPotentialFactory.hxx"
14 #include "MFront/BehaviourBrick/InelasticFlow.hxx"
15 #include "MFront/BehaviourBrick/InelasticFlowFactory.hxx"
16 #include "MFront/AbstractBehaviourDSL.hxx"
17 #include "MFront/StandardElastoViscoPlasticityBrick.hxx"
18 
19 namespace mfront {
20 
21   static std::string getId(const size_t i, const size_t m) {
22     if (m == 1) {
getReservedNames() const23       return "";
24     }
25     return std::to_string(i);
26   }  // end of getId
27 
28   StandardElastoViscoPlasticityBrick::StandardElastoViscoPlasticityBrick(
29       AbstractBehaviourDSL& dsl_,
30       BehaviourDescription& mb_,
31       const Parameters&,
usesJacobian() const32       const DataMap& d)
33       : BehaviourBrickBase(dsl_, mb_) {
34     auto raise = [](const std::string& m) {
35       tfel::raise(
36           "StandardElastoViscoPlasticityBrick::"
37           "StandardElastoViscoPlasticityBrick: " +
38           m);
39     };  // end of raise
40     auto& iff = bbrick::InelasticFlowFactory::getFactory();
41     auto getDataStructure = [&raise](const std::string& n, const Data& ds) {
42       if (ds.is<std::string>()) {
43         tfel::utilities::DataStructure nds;
44         nds.name = ds.get<std::string>();
45         return nds;
46       }
47       if (!ds.is<tfel::utilities::DataStructure>()) {
48         raise("invalid data type for entry '" + n + "'");
49       }
50       return ds.get<tfel::utilities::DataStructure>();
51     };  // end of getDataStructure
52     auto getStressPotential = [&d,&getDataStructure,&raise, this](const char* const n) {
53       if (d.count(n) != 0) {
54         const auto ds = getDataStructure(n, d.at(n));
55         if (this->stress_potential != nullptr) {
56           raise("the stress potential has already been defined");
57         }
58         auto& spf = bbrick::StressPotentialFactory::getFactory();
59         this->stress_potential = spf.generate(ds.name);
60         this->stress_potential->initialize(this->bd, this->dsl, ds.data);
61       }
62     };
63     getStressPotential("elastic_potential");
64     getStressPotential("stress_potential");
65     if (this->stress_potential == nullptr) {
66       raise("no stress potential defined");
67     }
68     for (const auto& e : d) {
69       if ((e.first == "elastic_potential") || (e.first == "stress_potential")) {
70         // already treated
71       } else if (e.first == "inelastic_flow") {
72         auto append_flow = [this, &iff, getDataStructure](const Data& ifd,
73                                                           const size_t msize) {
74           const auto ds = getDataStructure("inelatic_flow", ifd);
75           auto iflow = iff.generate(ds.name);
76           iflow->initialize(this->bd, this->dsl,
77                             getId(this->flows.size(), msize), ds.data);
78           this->flows.push_back(iflow);
79         };
80         if (e.second.is<std::vector<Data>>()) {
81           // multiple inelastic flows are defined
82           const auto& ifs = e.second.get<std::vector<Data>>();
83           for (const auto& iflow : ifs) {
84             append_flow(iflow, ifs.size());
85           }
86         } else {
87           append_flow(e.second, 1u);
88         }
89       } else {
90         raise("unsupported entry '" + e.first + "'");
91       }
92     }
93   }  // end of StandardElastoViscoPlasticityBrick
94 
95   std::string StandardElastoViscoPlasticityBrick::getName() const {
96     return "ElastoViscoPlasticity";
97   }
98 
99   std::vector<StandardElastoViscoPlasticityBrick::Hypothesis>
100   StandardElastoViscoPlasticityBrick::getSupportedModellingHypotheses() const {
writeResolutionAlgorithm(std::ostream & out,const BehaviourDescription & mb,const Hypothesis h) const101     return this->stress_potential->getSupportedModellingHypotheses(this->bd,
102                                                                    this->dsl);
103   }
104 
105   void StandardElastoViscoPlasticityBrick::completeVariableDeclaration() const {
106     this->stress_potential->completeVariableDeclaration(this->bd, this->dsl);
107     auto i = size_t{};
108     for (const auto& f : this->flows) {
109       f->completeVariableDeclaration(this->bd, this->dsl,
110                                      getId(i, this->flows.size()));
111       ++i;
112     }
113   }  // end of StandardElastoViscoPlasticityBrick::completeVariableDeclaration
114 
115   void StandardElastoViscoPlasticityBrick::endTreatment() const {
116     const auto& idsl = dynamic_cast<const ImplicitDSLBase&>(this->dsl);
117     this->stress_potential->endTreatment(this->bd, this->dsl);
118     const bool requiresAnalyticalJacobian =
119         ((idsl.getSolver().usesJacobian()) &&
120          (!idsl.getSolver().requiresNumericalJacobian()));
121     if (requiresAnalyticalJacobian) {
122       this->stress_potential->writeStressDerivatives(this->bd);
123     }
124     auto i = size_t{};
125     for (const auto& f : this->flows) {
126       f->endTreatment(this->bd, this->dsl, *(this->stress_potential),
127                       getId(i, this->flows.size()));
128       ++i;
129     }
130     // at this stage, one assumes that the various components of the inelastic
131     // flow (stress_potential, isotropic hardening rule) have added the
132     // initialization of their material properties the
133     // `BeforeInitializeLocalVariables`. We then ask the inelastic flows if
134     // they
135     // require an  activation state (in practice, it mean that an isotropic
136     // hardening rule has been defined). If so, the initialization of the
137     // activation states requires the the computation of an elastic prediction
138     // of the stress. The brik asks the stress potential to compute it in a
139     // variable called sigel and the inelastic flows shall use it to compute
140     // their initial state. All thoses steps must be added to the
141     // `BeforeInitializeLocalVariables` code block.
142     const bool bep = [this] {
143       for (const auto& pf : this->flows) {
144         if (pf->requiresActivationState()) {
145           return true;
146         }
147       }
148       return false;
149     }();
150     if (bep) {
151       // compute the elastic prediction
152       this->stress_potential->computeElasticPrediction(bd);
153       i = size_t{};
154       for (const auto& pf : this->flows) {
155         if (pf->requiresActivationState()) {
156           pf->computeInitialActivationState(bd, *(this->stress_potential),
157                                             getId(i, this->flows.size()));
158         }
159         ++i;
160       }
161     }
162   }  // end of StandardElastoViscoPlasticityBrick::endTreatment
163 
164   StandardElastoViscoPlasticityBrick::~StandardElastoViscoPlasticityBrick() =
165       default;
166 
167 }  // end of namespace mfront
168