OGS
CreateMFrontGeneric.cpp
Go to the documentation of this file.
1// SPDX-FileCopyrightText: Copyright (c) OpenGeoSys Community (opengeosys.org)
2// SPDX-License-Identifier: BSD-3-Clause
3
4#ifndef _WIN32
5#include <dlfcn.h>
6#endif
7
8#include "BaseLib/FileTools.h"
10#include "ParameterLib/Utils.h"
11
12namespace
13{
14const char* btypeToString(int btype)
15{
16 using B = mgis::behaviour::Behaviour;
17 if (btype == B::GENERALBEHAVIOUR)
18 {
19 return "GENERALBEHAVIOUR";
20 }
21 if (btype == B::STANDARDSTRAINBASEDBEHAVIOUR)
22 {
23 return "STANDARDSTRAINBASEDBEHAVIOUR";
24 }
25 if (btype == B::STANDARDFINITESTRAINBEHAVIOUR)
26 {
27 return "STANDARDFINITESTRAINBEHAVIOUR";
28 }
29 if (btype == B::COHESIVEZONEMODEL)
30 {
31 return "COHESIVEZONEMODEL";
32 }
33
34 OGS_FATAL("Unknown behaviour type {}.", btype);
35}
36
37const char* toString(mgis::behaviour::Behaviour::Kinematic kin)
38{
39 using K = mgis::behaviour::Behaviour::Kinematic;
40 switch (kin)
41 {
42 case K::UNDEFINEDKINEMATIC:
43 return "UNDEFINEDKINEMATIC";
44 case K::SMALLSTRAINKINEMATIC:
45 return "SMALLSTRAINKINEMATIC";
46 case K::COHESIVEZONEKINEMATIC:
47 return "COHESIVEZONEKINEMATIC";
48 case K::FINITESTRAINKINEMATIC_F_CAUCHY:
49 return "FINITESTRAINKINEMATIC_F_CAUCHY";
50 case K::FINITESTRAINKINEMATIC_ETO_PK1:
51 return "FINITESTRAINKINEMATIC_ETO_PK1";
52 }
53
54 OGS_FATAL("Unknown kinematic {}.", BaseLib::to_underlying(kin));
55}
56
57const char* toString(mgis::behaviour::Behaviour::Symmetry sym)
58{
59 using S = mgis::behaviour::Behaviour::Symmetry;
60 switch (sym)
61 {
62 case S::ISOTROPIC:
63 return "ISOTROPIC";
64 case S::ORTHOTROPIC:
65 return "ORTHOTROPIC";
66 }
67
68 OGS_FATAL("Unknown symmetry {}.", BaseLib::to_underlying(sym));
69}
70
72void varInfo(std::string const& msg,
73 std::vector<mgis::behaviour::Variable> const& vars,
74 mgis::behaviour::Hypothesis hypothesis)
75{
76 INFO("#{:s}: {:d} (array size {:d}).",
77 msg,
78 vars.size(),
79 mgis::behaviour::getArraySize(vars, hypothesis));
80 for (auto const& var : vars)
81 {
82 INFO(" --> type `{:s}' with name `{:s}', size {:d}, offset {:d}.",
84 var.name,
85 mgis::behaviour::getVariableSize(var, hypothesis),
86 mgis::behaviour::getVariableOffset(vars, var.name, hypothesis));
87 }
88}
89
91void varInfo(std::string const& msg, std::vector<std::string> const& parameters)
92{
93 INFO("#{:s}: {:d}.", msg, parameters.size());
94 for (auto const& parameter : parameters)
95 {
96 INFO(" --> with name `{:s}'.", parameter);
97 }
98}
99
100std::vector<ParameterLib::Parameter<double> const*> readMaterialProperties(
101 mgis::behaviour::Behaviour const& behaviour,
102 mgis::behaviour::Hypothesis const& hypothesis,
103 std::vector<std::unique_ptr<ParameterLib::ParameterBase>> const& parameters,
104 BaseLib::ConfigTree const& config)
105{
106 if (behaviour.mps.empty())
107 {
108 return {};
109 }
110
111 std::map<std::string, std::string> map_name_to_param;
112
113 // gather material properties from the prj file
115 auto const mps_config = config.getConfigSubtree("material_properties");
116 for (
117 auto const& mp_config :
119 mps_config.getConfigParameterList("material_property"))
120 {
122 auto name = mp_config.getConfigAttribute<std::string>("name");
123 auto param_name =
125 mp_config.getConfigAttribute<std::string>("parameter");
126
127 map_name_to_param.emplace(std::move(name), std::move(param_name));
128 }
129
130 std::vector<ParameterLib::Parameter<double> const*> material_properties;
131 for (auto const& mp : behaviour.mps)
132 {
133 auto const it = map_name_to_param.find(mp.name);
134 if (it == map_name_to_param.end())
135 OGS_FATAL(
136 "Material Property `{:s}' has not been configured in the "
137 "project file.",
138 mp.name);
139
140 auto const& param_name = it->second;
141 auto const num_comp = mgis::behaviour::getVariableSize(mp, hypothesis);
142 auto const* param = &ParameterLib::findParameter<double>(
143 param_name, parameters, num_comp);
144
145 INFO("Using OGS parameter `{:s}' for material property `{:s}'.",
146 param_name, mp.name);
147
148 using V = mgis::behaviour::Variable;
149 if (mp.type == V::STENSOR || mp.type == V::TENSOR)
150 {
151 WARN(
152 "Material property `{:s}' is a tensorial quantity. You, "
153 "the "
154 "user, have to make sure that the component order of "
155 "parameter `{:s}' matches the one required by MFront!",
156 mp.name, param_name);
157 }
158
159 material_properties.push_back(param);
160 map_name_to_param.erase(it);
161 }
162
163 if (!map_name_to_param.empty())
164 {
165 ERR("Some material parameters that were configured are not used by "
166 "the material model.");
167 ERR("These parameters are:");
168
169 for (auto const& e : map_name_to_param)
170 {
171 ERR(" name: `{:s}', parameter: `{:s}'.", e.first, e.second);
172 }
173
174 OGS_FATAL(
175 "Configuration errors occurred. Please fix the project file.");
176 }
177
178 return material_properties;
179}
180
181// Very similar to above readMaterialProperties but does not generalize because
182// of config specific strings for ogs_file_param and return type.
183std::map<std::string, ParameterLib::Parameter<double> const*>
185 mgis::behaviour::Behaviour const& behaviour,
186 mgis::behaviour::Hypothesis const& hypothesis,
187 std::vector<std::unique_ptr<ParameterLib::ParameterBase>> const& parameters,
188 BaseLib::ConfigTree const& config)
189{
190 if (behaviour.isvs.empty())
191 {
192 return {};
193 }
194
195 // gather state variables from the prj file
196 auto const initial_values_config =
198 config.getConfigSubtreeOptional("initial_values");
199 if (!initial_values_config)
200 {
201 return {};
202 }
203
204 std::map<std::string, std::string> map_name_to_param;
205 for (
206 auto const c :
208 initial_values_config->getConfigParameterList("state_variable"))
209 {
211 auto name = c.getConfigAttribute<std::string>("name");
213 auto param_name = c.getConfigAttribute<std::string>("parameter");
214
215 map_name_to_param.emplace(std::move(name), std::move(param_name));
216 }
217
218 std::map<std::string, ParameterLib::Parameter<double> const*>
219 state_variables_initial_properties;
220 for (auto const& isv : behaviour.isvs)
221 {
222 auto const it = map_name_to_param.find(isv.name);
223
224 // Not all internal state variables might need initialization and are
225 // skipped.
226 if (it == map_name_to_param.end())
227 {
228 continue;
229 }
230
231 auto const& param_name = it->second;
232 auto const num_comp = mgis::behaviour::getVariableSize(isv, hypothesis);
233 auto const* param = &ParameterLib::findParameter<double>(
234 param_name, parameters, num_comp);
235
236 INFO(
237 "Using OGS parameter `{:s}' for initial value of internal "
238 "state variable `{:s}'.",
239 param_name, isv.name);
240
241 using V = mgis::behaviour::Variable;
242 if (isv.type == V::STENSOR || isv.type == V::TENSOR)
243 {
244 WARN(
245 "State variable `{:s}' is a tensorial quantity. You, the user, "
246 "have to make sure that the component order of parameter "
247 "`{:s}' matches the one required by MFront!",
248 isv.name, param_name);
249 }
250
251 state_variables_initial_properties[isv.name] = param;
252 map_name_to_param.erase(it);
253 }
254
255 if (!map_name_to_param.empty())
256 {
257 ERR("Some state variables initial value parameters that were "
258 "configured are not used by the material model.");
259 ERR("These parameters are:");
260
261 for (auto const& e : map_name_to_param)
262 {
263 ERR(" name: `{:s}', parameter: `{:s}'.", e.first, e.second);
264 }
265
266 OGS_FATAL(
267 "Configuration errors occurred. Please fix the project file.");
268 }
269
270 return state_variables_initial_properties;
271}
272
273mgis::behaviour::Behaviour loadBehaviour(
274 std::string const& lib_path, std::string behaviour_name,
275 mgis::behaviour::Hypothesis const hypothesis)
276{
277 // Fix for https://gitlab.opengeosys.org/ogs/ogs/-/issues/3073
278 // Pre-load dependencies of mfront lib
279#ifndef _WIN32
280 dlopen("libTFELNUMODIS.so", RTLD_NOW);
281 dlopen("libTFELUtilities.so", RTLD_NOW);
282 dlopen("libTFELException.so", RTLD_NOW);
283#endif
284
285 std::optional<std::runtime_error> small_strain_load_error;
286
287 // Try small strains first.
288 try
289 {
290 return mgis::behaviour::load(lib_path, behaviour_name, hypothesis);
291 }
292 catch (std::runtime_error const& e)
293 {
294 // Didn't work, store the exception and try finite strain.
295 small_strain_load_error = e;
296 }
297
298 try
299 {
300 auto o = mgis::behaviour::FiniteStrainBehaviourOptions{};
301 o.stress_measure = mgis::behaviour::FiniteStrainBehaviourOptions::PK2;
302 o.tangent_operator =
303 mgis::behaviour::FiniteStrainBehaviourOptions::DS_DEGL;
304
305 return mgis::behaviour::load(o, lib_path, behaviour_name, hypothesis);
306 }
307 catch (std::runtime_error const& e)
308 {
309 if (small_strain_load_error)
310 {
311 OGS_FATAL(
312 "Could not load the {} from {} neither for small strains "
313 "(error {}) nor for finite strains (error {}).",
314 behaviour_name, lib_path, small_strain_load_error->what(),
315 e.what());
316 }
317 }
318
319 OGS_FATAL("Could not load the {} from {}.", behaviour_name, lib_path);
320}
321} // namespace
322
324{
325
327 int const displacement_dim,
328 std::vector<std::unique_ptr<ParameterLib::ParameterBase>> const& parameters,
329 BaseLib::ConfigTree const& config)
330{
331 INFO("### MFRONT ########################################################");
332
334 config.checkConfigParameter("type", "MFront");
335
337 auto const library = config.getConfigSubtreeOptional("library");
338
339 bool const library_path_is_relative_to_prj_file =
340 library /* If no library tag is specified in the prj file, the lib
341 shipped with OGS is used, whose path is not relative to the
342 project file. */
343 &&
345 library->getConfigAttribute("path_is_relative_to_prj_file", true);
346
347 std::string const library_name =
348 library ? library->getValue<std::string>() : "libOgsMFrontBehaviour";
349
350 auto const lib_path =
351 library_path_is_relative_to_prj_file
352 ? BaseLib::joinPaths(config.projectDirectory(), library_name)
353 : library_name;
354
355 mgis::behaviour::Hypothesis hypothesis;
356 if (displacement_dim == 2)
357 {
358 // TODO support the axial symmetry modelling hypothesis.
359 WARN(
360 "The model is defined in 2D. On the material level currently a "
361 "plane strain setting is used. In particular it is not checked if "
362 "axial symmetry or plane stress are assumed. Special material "
363 "behaviour for these settings is currently not supported.");
364 hypothesis = mgis::behaviour::Hypothesis::PLANESTRAIN;
365 }
366 else if (displacement_dim == 3)
367 {
368 hypothesis = mgis::behaviour::Hypothesis::TRIDIMENSIONAL;
369 }
370 else
371 {
372 OGS_FATAL("Displacement dim {} is not supported.", displacement_dim);
373 }
374
375 auto behaviour = loadBehaviour(
376 lib_path,
378 config.getConfigParameter<std::string>("behaviour"),
379 hypothesis);
380
381 INFO("Behaviour: `{:s}'.", behaviour.behaviour);
382 INFO("Hypothesis: `{:s}'.", mgis::behaviour::toString(hypothesis));
383 INFO("Source: `{:s}'.", behaviour.source);
384 INFO("TFEL version: `{:s}'.", behaviour.tfel_version);
385 INFO("Behaviour type: `{:s}'.", btypeToString(behaviour.btype));
386 INFO("Kinematic: `{:s}'.", toString(behaviour.kinematic));
387 INFO("Symmetry: `{:s}'.", toString(behaviour.symmetry));
388
389 varInfo("Mat. props.", behaviour.mps, hypothesis);
390 varInfo("Gradients", behaviour.gradients, hypothesis);
391 varInfo("Thdyn. forces", behaviour.thermodynamic_forces, hypothesis);
392 varInfo("Int. StVars.", behaviour.isvs, hypothesis);
393 varInfo("Ext. StVars.", behaviour.esvs, hypothesis);
394
395 // TODO read parameters from prj file, not yet (2018-11-05) supported by
396 // MGIS library.
397 varInfo("Real-valued parameters", behaviour.params);
398 varInfo("Integer parameters", behaviour.iparams);
399 varInfo("Unsigned parameters", behaviour.usparams);
400
401 INFO("#Tangent operator blocks: {}.", behaviour.to_blocks.size());
402 for (auto const& [var1, var2] : behaviour.to_blocks)
403 {
404 INFO(" --> ({}, {}).", var1.name, var2.name);
405 }
406
407 std::vector<ParameterLib::Parameter<double> const*> material_properties =
408 readMaterialProperties(behaviour, hypothesis, parameters, config);
409
410 std::map<std::string, ParameterLib::Parameter<double> const*>
411 state_variables_initial_properties =
412 readStateVariablesInitialValueProperties(behaviour, hypothesis,
413 parameters, config);
414
415 INFO("### MFRONT END ####################################################");
416
417 return {std::move(behaviour), std::move(material_properties),
418 std::move(state_variables_initial_properties)};
419}
420
421} // namespace MaterialLib::Solids::MFront
#define OGS_FATAL(...)
Definition Error.h:19
void INFO(fmt::format_string< Args... > fmt, Args &&... args)
Definition Logging.h:28
void ERR(fmt::format_string< Args... > fmt, Args &&... args)
Definition Logging.h:40
void WARN(fmt::format_string< Args... > fmt, Args &&... args)
Definition Logging.h:34
std::optional< ConfigTree > getConfigSubtreeOptional(std::string const &root) const
std::filesystem::path projectDirectory() const
T getConfigParameter(std::string const &param) const
ConfigTree getConfigSubtree(std::string const &root) const
void checkConfigParameter(std::string const &param, std::string_view const value) const
constexpr auto to_underlying(E e) noexcept
Converts an enumeration to its underlying type.
Definition cpp23.h:22
std::string joinPaths(std::string const &pathA, std::string const &pathB)
MFrontConfig createMFrontConfig(int const displacement_dim, std::vector< std::unique_ptr< ParameterLib::ParameterBase > > const &parameters, BaseLib::ConfigTree const &config)
const char * varTypeToString(int v)
OGS_NO_DANGLING Parameter< ParameterDataType > & findParameter(std::string const &parameter_name, std::vector< std::unique_ptr< ParameterBase > > const &parameters, int const num_components, MeshLib::Mesh const *const mesh=nullptr)
std::vector< ParameterLib::Parameter< double > const * > readMaterialProperties(mgis::behaviour::Behaviour const &behaviour, mgis::behaviour::Hypothesis const &hypothesis, std::vector< std::unique_ptr< ParameterLib::ParameterBase > > const &parameters, BaseLib::ConfigTree const &config)
void varInfo(std::string const &msg, std::vector< mgis::behaviour::Variable > const &vars, mgis::behaviour::Hypothesis hypothesis)
Prints info about MFront variables.
const char * toString(mgis::behaviour::Behaviour::Kinematic kin)
std::map< std::string, ParameterLib::Parameter< double > const * > readStateVariablesInitialValueProperties(mgis::behaviour::Behaviour const &behaviour, mgis::behaviour::Hypothesis const &hypothesis, std::vector< std::unique_ptr< ParameterLib::ParameterBase > > const &parameters, BaseLib::ConfigTree const &config)
mgis::behaviour::Behaviour loadBehaviour(std::string const &lib_path, std::string behaviour_name, mgis::behaviour::Hypothesis const hypothesis)