OGS
MFront.cpp
Go to the documentation of this file.
1 
10 #include "MFront.h"
11 
12 #include <MGIS/Behaviour/Integrate.hxx>
13 #include <variant>
14 
15 #include "BaseLib/Error.h"
18 #include "NumLib/Exceptions.h"
19 
20 namespace MPL = MaterialPropertyLib;
21 
22 namespace
23 {
25 constexpr std::ptrdiff_t OGSToMFront(std::ptrdiff_t i)
26 {
27  // MFront: 11 22 33 12 13 23
28  // OGS: 11 22 33 12 23 13
29  if (i < 4)
30  return i;
31  if (i == 4)
32  return 5;
33  return 4;
34 }
36 constexpr std::ptrdiff_t MFrontToOGS(std::ptrdiff_t i)
37 {
38  // MFront: 11 22 33 12 13 23
39  // OGS: 11 22 33 12 23 13
40  return OGSToMFront(i); // Same algorithm: indices 4 and 5 swapped.
41 }
42 
44 template <typename Derived>
45 typename Derived::PlainObject OGSToMFront(Eigen::DenseBase<Derived> const& m)
46 {
47  static_assert(Derived::RowsAtCompileTime != Eigen::Dynamic, "Error");
48  static_assert(Derived::ColsAtCompileTime != Eigen::Dynamic, "Error");
49 
50  typename Derived::PlainObject n;
51 
52  // optimal for row-major storage order
53  for (std::ptrdiff_t r = 0; r < Eigen::DenseBase<Derived>::RowsAtCompileTime;
54  ++r)
55  {
56  auto const R = OGSToMFront(r);
57  for (std::ptrdiff_t c = 0;
58  c < Eigen::DenseBase<Derived>::ColsAtCompileTime;
59  ++c)
60  {
61  auto const C = OGSToMFront(c);
62  n(R, C) = m(r, c);
63  }
64  }
65 
66  return n;
67 }
68 
70 template <typename Derived>
71 typename Derived::PlainObject MFrontToOGS(Eigen::DenseBase<Derived> const& m)
72 {
73  static_assert(Derived::RowsAtCompileTime != Eigen::Dynamic, "Error");
74  static_assert(Derived::ColsAtCompileTime != Eigen::Dynamic, "Error");
75 
76  typename Derived::PlainObject n;
77 
78  // optimal for row-major storage order
79  for (std::ptrdiff_t r = 0; r < Eigen::DenseBase<Derived>::RowsAtCompileTime;
80  ++r)
81  {
82  auto const R = MFrontToOGS(r);
83  for (std::ptrdiff_t c = 0;
84  c < Eigen::DenseBase<Derived>::ColsAtCompileTime;
85  ++c)
86  {
87  auto const C = MFrontToOGS(c);
88  n(R, C) = m(r, c);
89  }
90  }
91 
92  return n;
93 }
94 
95 } // namespace
96 
97 namespace MaterialLib
98 {
99 namespace Solids
100 {
101 namespace MFront
102 {
103 const char* toString(mgis::behaviour::Behaviour::Kinematic kin)
104 {
105  using K = mgis::behaviour::Behaviour::Kinematic;
106  switch (kin)
107  {
108  case K::UNDEFINEDKINEMATIC:
109  return "UNDEFINEDKINEMATIC";
110  case K::SMALLSTRAINKINEMATIC:
111  return "SMALLSTRAINKINEMATIC";
112  case K::COHESIVEZONEKINEMATIC:
113  return "COHESIVEZONEKINEMATIC";
114  case K::FINITESTRAINKINEMATIC_F_CAUCHY:
115  return "FINITESTRAINKINEMATIC_F_CAUCHY";
116  case K::FINITESTRAINKINEMATIC_ETO_PK1:
117  return "FINITESTRAINKINEMATIC_ETO_PK1";
118  }
119 
120  OGS_FATAL("Unknown kinematic {:d}.", kin);
121 }
122 
123 const char* toString(mgis::behaviour::Behaviour::Symmetry sym)
124 {
125  using S = mgis::behaviour::Behaviour::Symmetry;
126  switch (sym)
127  {
128  case S::ISOTROPIC:
129  return "ISOTROPIC";
130  case S::ORTHOTROPIC:
131  return "ORTHOTROPIC";
132  }
133 
134  OGS_FATAL("Unknown symmetry {:d}.", sym);
135 }
136 const char* btypeToString(int btype)
137 {
138  using B = mgis::behaviour::Behaviour;
139  if (btype == B::GENERALBEHAVIOUR)
140  return "GENERALBEHAVIOUR";
141  if (btype == B::STANDARDSTRAINBASEDBEHAVIOUR)
142  return "STANDARDSTRAINBASEDBEHAVIOUR";
143  if (btype == B::STANDARDFINITESTRAINBEHAVIOUR)
144  return "STANDARDFINITESTRAINBEHAVIOUR";
145  if (btype == B::COHESIVEZONEMODEL)
146  return "COHESIVEZONEMODEL";
147 
148  OGS_FATAL("Unknown behaviour type {:d}.", btype);
149 }
150 const char* varTypeToString(int v)
151 {
152  using V = mgis::behaviour::Variable;
153  if (v == V::SCALAR)
154  return "SCALAR";
155  if (v == V::VECTOR)
156  return "VECTOR";
157  if (v == V::STENSOR)
158  return "STENSOR";
159  if (v == V::TENSOR)
160  return "TENSOR";
161 
162  OGS_FATAL("Unknown variable type {:d}.", v);
163 }
164 
165 int getEquivalentPlasticStrainOffset(mgis::behaviour::Behaviour const& b)
166 {
167  return mgis::behaviour::contains(b.isvs, "EquivalentPlasticStrain")
168  ? mgis::behaviour::getVariableOffset(
169  b.isvs, "EquivalentPlasticStrain", b.hypothesis)
170  : -1;
171 }
172 
173 template <int DisplacementDim>
175  mgis::behaviour::Behaviour&& behaviour,
176  std::vector<ParameterLib::Parameter<double> const*>&& material_properties,
177  std::optional<ParameterLib::CoordinateSystem> const&
178  local_coordinate_system)
179  : _behaviour(std::move(behaviour)),
180  equivalent_plastic_strain_offset_(
182  _material_properties(std::move(material_properties)),
183  _local_coordinate_system(
184  local_coordinate_system ? &local_coordinate_system.value() : nullptr)
185 {
186  auto const hypothesis = behaviour.hypothesis;
187 
188  if (_behaviour.gradients.size() != 1)
189  OGS_FATAL(
190  "The behaviour must have exactly a single gradient as input.");
191 
192  if (_behaviour.gradients[0].name != "Strain")
193  OGS_FATAL("The behaviour must be driven by strain.");
194 
195  if (_behaviour.gradients[0].type != mgis::behaviour::Variable::STENSOR)
196  OGS_FATAL("Strain must be a symmetric tensor.");
197 
198  if (mgis::behaviour::getVariableSize(_behaviour.gradients[0], hypothesis) !=
200  OGS_FATAL("Strain must have {:d} components instead of {:d}.",
202  mgis::behaviour::getVariableSize(_behaviour.gradients[0],
203  hypothesis));
204 
205  if (_behaviour.thermodynamic_forces.size() != 1)
206  OGS_FATAL(
207  "The behaviour must compute exactly one thermodynamic force.");
208 
209  if (_behaviour.thermodynamic_forces[0].name != "Stress")
210  OGS_FATAL("The behaviour must compute stress.");
211 
212  if (_behaviour.thermodynamic_forces[0].type !=
213  mgis::behaviour::Variable::STENSOR)
214  OGS_FATAL("Stress must be a symmetric tensor.");
215 
216  if (mgis::behaviour::getVariableSize(_behaviour.thermodynamic_forces[0],
217  hypothesis) !=
219  OGS_FATAL("Stress must have {:d} components instead of {:d}.",
221  mgis::behaviour::getVariableSize(
222  _behaviour.thermodynamic_forces[0], hypothesis));
223 
224  if (!_behaviour.esvs.empty())
225  {
226  if (_behaviour.esvs[0].name != "Temperature")
227  {
228  OGS_FATAL(
229  "Only temperature is supported as external state variable.");
230  }
231 
232  if (mgis::behaviour::getVariableSize(_behaviour.esvs[0], hypothesis) !=
233  1)
234  OGS_FATAL(
235  "Temperature must be a scalar instead of having {:d} "
236  "components.",
237  mgis::behaviour::getVariableSize(
238  _behaviour.thermodynamic_forces[0], hypothesis));
239  }
240 
241  if (_behaviour.mps.size() != _material_properties.size())
242  {
243  ERR("There are {:d} material properties in the loaded behaviour:",
244  _behaviour.mps.size());
245  for (auto const& mp : _behaviour.mps)
246  {
247  ERR("\t{:s}", mp.name);
248  }
249  OGS_FATAL("But the number of passed material properties is {:d}.",
250  _material_properties.size());
251  }
252 }
253 
254 template <int DisplacementDim>
255 std::unique_ptr<typename MechanicsBase<DisplacementDim>::MaterialStateVariables>
257 {
258  return std::make_unique<MaterialStateVariables>(
259  equivalent_plastic_strain_offset_, _behaviour);
260 }
261 
262 template <int DisplacementDim>
263 std::optional<std::tuple<typename MFront<DisplacementDim>::KelvinVector,
264  std::unique_ptr<typename MechanicsBase<
265  DisplacementDim>::MaterialStateVariables>,
268  MPL::VariableArray const& variable_array_prev,
269  MPL::VariableArray const& variable_array,
270  double const t,
272  double const dt,
274  material_state_variables) const
275 {
276  using namespace MathLib::KelvinVector;
277 
278  assert(
279  dynamic_cast<MaterialStateVariables const*>(&material_state_variables));
280  // New state, copy of current one, packed in unique_ptr for return.
281  auto state = std::make_unique<MaterialStateVariables>(
282  static_cast<MaterialStateVariables const&>(material_state_variables));
283  auto& behaviour_data = state->_behaviour_data;
284 
285  // TODO add a test of material behaviour where the value of dt matters.
286  behaviour_data.dt = dt;
287  behaviour_data.rdt = 1.0;
288  behaviour_data.K[0] = 4.0; // if K[0] is greater than 3.5, the consistent
289  // tangent operator must be computed.
290 
291  // evaluate parameters at (t, x)
292  {
293  auto out = behaviour_data.s1.material_properties.begin();
294  for (auto* param : _material_properties)
295  {
296  auto const& vals = (*param)(t, x);
297  out = std::copy(vals.begin(), vals.end(), out);
298  }
299  assert(out == behaviour_data.s1.material_properties.end());
300  }
301 
302  if (!behaviour_data.s0.external_state_variables.empty())
303  {
304  // assuming that there is only temperature
305  if (!std::holds_alternative<double>(
306  variable_array_prev[static_cast<int>(
308  {
309  OGS_FATAL(
310  "MPL::Variable::temperature is not set for variable_array_prev "
311  "before calling MFront::integrateStress.");
312  }
313 
314  behaviour_data.s1.external_state_variables[0] = std::get<double>(
315  variable_array_prev[static_cast<int>(MPL::Variable::temperature)]);
316  }
317 
318  if (!behaviour_data.s1.external_state_variables.empty())
319  {
320  // assuming that there is only temperature
321  if (!std::holds_alternative<double>(
322  variable_array[static_cast<int>(MPL::Variable::temperature)]))
323  {
324  OGS_FATAL(
325  "MPL::Variable::temperature is not set for variable_array "
326  "before calling MFront::integrateStress");
327  }
328 
329  behaviour_data.s1.external_state_variables[0] = std::get<double>(
330  variable_array[static_cast<int>(MPL::Variable::temperature)]);
331  }
332 
333  // rotation tensor
334  auto const Q = [this, &x]() -> KelvinMatrixType<DisplacementDim>
335  {
336  if (!_local_coordinate_system)
337  {
339  }
341  _local_coordinate_system->transformation<DisplacementDim>(x));
342  }();
343 
344  auto const& eps_m_prev = std::get<MPL::SymmetricTensor<DisplacementDim>>(
345  variable_array_prev[static_cast<int>(
346  MPL::Variable::mechanical_strain)]);
347  auto const eps_prev_MFront = OGSToMFront(
348  Q.transpose()
349  .template topLeftCorner<kelvin_vector_dimensions(DisplacementDim),
351  DisplacementDim)>() *
352  eps_m_prev);
353  std::copy_n(eps_prev_MFront.data(), KelvinVector::SizeAtCompileTime,
354  behaviour_data.s0.gradients.data());
355 
356  auto const& eps = std::get<MPL::SymmetricTensor<DisplacementDim>>(
357  variable_array[static_cast<int>(MPL::Variable::mechanical_strain)]);
358  auto const eps_MFront = OGSToMFront(
359  Q.transpose()
360  .template topLeftCorner<kelvin_vector_dimensions(DisplacementDim),
362  DisplacementDim)>() *
363  eps);
364  std::copy_n(eps_MFront.data(), KelvinVector::SizeAtCompileTime,
365  behaviour_data.s1.gradients.data());
366 
367  auto const& sigma_prev = std::get<MPL::SymmetricTensor<DisplacementDim>>(
368  variable_array_prev[static_cast<int>(MPL::Variable::stress)]);
369  auto const sigma_prev_MFront = OGSToMFront(
370  Q.transpose()
371  .template topLeftCorner<kelvin_vector_dimensions(DisplacementDim),
373  DisplacementDim)>() *
374  sigma_prev);
375  std::copy_n(sigma_prev_MFront.data(), KelvinVector::SizeAtCompileTime,
376  behaviour_data.s0.thermodynamic_forces.data());
377  std::copy_n(sigma_prev_MFront.data(), KelvinVector::SizeAtCompileTime,
378  behaviour_data.s1.thermodynamic_forces.data());
379 
380  auto v = mgis::behaviour::make_view(behaviour_data);
381  auto const status = mgis::behaviour::integrate(v, _behaviour);
382  if (status != 1)
383  {
385  "MFront: integration failed with status" + std::to_string(status) +
386  ".");
387  }
388 
389  KelvinVector sigma;
390  std::copy_n(behaviour_data.s1.thermodynamic_forces.data(),
391  KelvinVector::SizeAtCompileTime, sigma.data());
392  sigma =
393  Q.template topLeftCorner<kelvin_vector_dimensions(DisplacementDim),
394  kelvin_vector_dimensions(DisplacementDim)>() *
395  MFrontToOGS(sigma);
396 
397  // TODO row- vs. column-major storage order. This should only matter for
398  // anisotropic materials.
399  if (behaviour_data.K.size() !=
400  KelvinMatrix::RowsAtCompileTime * KelvinMatrix::ColsAtCompileTime)
401  OGS_FATAL("Stiffness matrix has wrong size.");
402 
403  KelvinMatrix C =
404  Q * MFrontToOGS(Eigen::Map<KelvinMatrix>(behaviour_data.K.data())) *
405  Q.transpose()
406  .template topLeftCorner<kelvin_vector_dimensions(DisplacementDim),
408  DisplacementDim)>();
409 
410  return std::make_optional(
411  std::make_tuple<typename MFront<DisplacementDim>::KelvinVector,
412  std::unique_ptr<typename MechanicsBase<
413  DisplacementDim>::MaterialStateVariables>,
415  std::move(sigma), std::move(state), std::move(C)));
416 }
417 
418 template <int DisplacementDim>
419 std::vector<typename MechanicsBase<DisplacementDim>::InternalVariable>
421 {
422  std::vector<typename MechanicsBase<DisplacementDim>::InternalVariable>
423  internal_variables;
424 
425  for (auto const& iv : _behaviour.isvs)
426  {
427  auto const name = iv.name;
428  auto const offset = mgis::behaviour::getVariableOffset(
429  _behaviour.isvs, name, _behaviour.hypothesis);
430  auto const size =
431  mgis::behaviour::getVariableSize(iv, _behaviour.hypothesis);
432 
433  // TODO (naumov): For orthotropic materials the internal variables
434  // should be rotated to the global coordinate system before output.
435  // MFront stores the variables in local coordinate system.
436  // The `size` variable could be used to find out the type of variable.
438  name, static_cast<int>(size),
439  [offset, size](
440  typename MechanicsBase<
441  DisplacementDim>::MaterialStateVariables const& state,
442  std::vector<double>& cache) -> std::vector<double> const&
443  {
444  assert(dynamic_cast<MaterialStateVariables const*>(&state) !=
445  nullptr);
446  auto const& internal_state_variables =
447  static_cast<MaterialStateVariables const&>(state)
448  ._behaviour_data.s1.internal_state_variables;
449 
450  cache.resize(size);
451  std::copy_n(internal_state_variables.data() + offset,
452  size,
453  begin(cache));
454  return cache;
455  },
456  [offset, size](
459  {
460  assert(dynamic_cast<MaterialStateVariables const*>(&state) !=
461  nullptr);
462  auto& internal_state_variables =
463  static_cast<MaterialStateVariables&>(state)
464  ._behaviour_data.s1.internal_state_variables;
465 
466  return {internal_state_variables.data() + offset, size};
467  }};
468  internal_variables.push_back(new_variable);
469  }
470 
471  return internal_variables;
472 }
473 
474 template <int DisplacementDim>
476  double const /*t*/,
477  ParameterLib::SpatialPosition const& /*x*/,
478  KelvinMatrix const* const C) const
479 {
480  if (C == nullptr)
481  {
482  OGS_FATAL(
483  "MFront::getBulkModulus() requires the tangent stiffness C input "
484  "argument to be valid.");
485  }
486  auto const& identity2 = MathLib::KelvinVector::Invariants<
488  DisplacementDim)>::identity2;
489  return 1. / 9. * identity2.transpose() * *C * identity2;
490 }
491 
492 template <int DisplacementDim>
494  double const /*t*/,
495  ParameterLib::SpatialPosition const& /*x*/,
496  double const /*dt*/,
497  KelvinVector const& /*eps*/,
498  KelvinVector const& /*sigma*/,
500  /*material_state_variables*/) const
501 {
502  // TODO implement
503  return std::numeric_limits<double>::quiet_NaN();
504 }
505 
506 template <int DisplacementDim>
507 double MFront<
508  DisplacementDim>::MaterialStateVariables::getEquivalentPlasticStrain() const
509 {
510  if (equivalent_plastic_strain_offset_ >= 0)
511  {
512  return _behaviour_data.s1
513  .internal_state_variables[static_cast<mgis::size_type>(
514  equivalent_plastic_strain_offset_)];
515  }
516 
517  return 0.0;
518 }
519 
520 template class MFront<2>;
521 template class MFront<3>;
522 
523 } // namespace MFront
524 } // namespace Solids
525 } // namespace MaterialLib
#define OGS_FATAL(...)
Definition: Error.h:26
void ERR(char const *fmt, Args const &... args)
Definition: Logging.h:42
mgis::behaviour::Behaviour _behaviour
Definition: MFront.h:114
std::vector< ParameterLib::Parameter< double > const * > _material_properties
Definition: MFront.h:116
MathLib::KelvinVector::KelvinVectorType< DisplacementDim > KelvinVector
Definition: MFront.h:70
MathLib::KelvinVector::KelvinMatrixType< DisplacementDim > KelvinMatrix
Definition: MFront.h:72
bool contains(Container const &container, typename Container::value_type const &element)
Definition: Algorithm.h:256
const char * btypeToString(int btype)
Converts MGIS behaviour type to a string representation.
Definition: MFront.cpp:136
const char * toString(mgis::behaviour::Behaviour::Kinematic kin)
Converts MGIS kinematic to a string representation.
Definition: MFront.cpp:103
const char * varTypeToString(int v)
Converts MGIS variable type to a string representation.
Definition: MFront.cpp:150
int getEquivalentPlasticStrainOffset(mgis::behaviour::Behaviour const &b)
Definition: MFront.cpp:165
std::array< VariableType, static_cast< int >(Variable::number_of_variables)> VariableArray
Definition: VariableType.h:108
constexpr int kelvin_vector_dimensions(int const displacement_dim)
Kelvin vector dimensions for given displacement dimension.
Definition: KelvinVector.h:23
Eigen::Matrix< double, kelvin_vector_dimensions(DisplacementDim), kelvin_vector_dimensions(DisplacementDim), Eigen::RowMajor > KelvinMatrixType
Definition: KelvinVector.h:56
KelvinMatrixType< DisplacementDim > fourthOrderRotationMatrix(Eigen::Matrix< double, DisplacementDim, DisplacementDim, Eigen::ColMajor, DisplacementDim, DisplacementDim > const &transformation)
void copy(PETScVector const &x, PETScVector &y)
Definition: LinAlg.cpp:37
static const double r
Derived::PlainObject OGSToMFront(Eigen::DenseBase< Derived > const &m)
Converts between OGSes and MFront's Kelvin vectors and matrices.
Definition: MFront.cpp:45
Derived::PlainObject MFrontToOGS(Eigen::DenseBase< Derived > const &m)
Converts between OGSes and MFront's Kelvin vectors and matrices.
Definition: MFront.cpp:71
Helper type for providing access to internal variables.
Definition: MechanicsBase.h:97
MathLib::KelvinVector::KelvinVectorType< DisplacementDim > KelvinVector
Definition: MechanicsBase.h:75
MathLib::KelvinVector::KelvinMatrixType< DisplacementDim > KelvinMatrix
Definition: MechanicsBase.h:77