OGS
Function.cpp
Go to the documentation of this file.
1
11
12#include <exprtk.hpp>
13#include <numeric>
14#include <range/v3/range/conversion.hpp>
15#include <range/v3/view/transform.hpp>
16#include <ranges>
17#include <typeinfo>
18#include <unordered_set>
19
20#include "BaseLib/Algorithm.h"
23
24namespace MaterialPropertyLib
25{
26// Passing symbol table by reference as required by register_symbol_table()
27// call.
28template <typename T>
29static std::vector<exprtk::expression<T>> compileExpressions(
30 exprtk::symbol_table<T>& symbol_table,
31 std::vector<std::string> const& string_expressions)
32{
33 exprtk::parser<T> parser;
34
35 std::vector<exprtk::expression<T>> expressions(string_expressions.size());
36 for (unsigned i = 0; i < string_expressions.size(); ++i)
37 {
38 expressions[i].register_symbol_table(symbol_table);
39 if (!parser.compile(string_expressions[i], expressions[i]))
40 {
41 OGS_FATAL("Error: {:s}\tExpression: {:s}\n",
42 parser.error(),
43 string_expressions[i]);
44 }
45 }
46 return expressions;
47}
48
49template <int D>
50class Function::Implementation
51{
52public:
53 using Expression = exprtk::expression<double>;
54
55public:
57 std::vector<std::string> const& variables,
58 std::vector<std::string> const& value_string_expressions,
59 std::vector<std::pair<std::string, std::vector<std::string>>> const&
60 dvalue_string_expressions);
61
62private:
65 exprtk::symbol_table<double> createSymbolTable(
66 std::vector<std::string> const& variables);
67
68public:
71 std::vector<Expression> value_expressions;
72
75 std::vector<std::pair<Variable, std::vector<Expression>>>
77
81
83};
84
85template <int D>
87 std::vector<std::string> const& variables)
88{
89 exprtk::symbol_table<double> symbol_table;
90 symbol_table.add_constants();
91
92 symbol_table.create_variable("t");
93
94 for (auto const& v : variables)
95 {
96 if (v == "t")
97 {
98 symbol_table.create_variable("t");
99 }
100 else if (v == "x")
101 {
102 symbol_table.create_variable("x");
103 spatial_position_is_required = true;
104 }
105 else if (v == "y")
106 {
107 symbol_table.create_variable("y");
108 spatial_position_is_required = true;
109 }
110 else if (v == "z")
111 {
112 symbol_table.create_variable("z");
113 spatial_position_is_required = true;
114 }
115 else
116 {
117 auto add_scalar = [&v, &symbol_table](double& value)
118 { symbol_table.add_variable(v, value); };
119
120 auto add_vector =
121 [&v, &symbol_table](double* ptr, std::size_t const size)
122 { symbol_table.add_vector(v, ptr, size); };
123
124 auto add_any_variable = BaseLib::Overloaded{
125 [&add_scalar](VariableArray::Scalar* address)
126 { add_scalar(*address); },
127 [&add_vector](VariableArray::KelvinVector* address)
128 {
129 auto constexpr size =
131 auto& result = address->template emplace<
132 Eigen::Matrix<double, size, 1>>();
133 add_vector(result.data(), size);
134 },
135 [&add_vector](VariableArray::DeformationGradient* address)
136 {
137 auto constexpr size = MathLib::VectorizedTensor::size(D);
138 auto& result = address->template emplace<
139 Eigen::Matrix<double, size, 1>>();
140 add_vector(result.data(), size);
141 }};
142
143 Variable const variable = convertStringToVariable(v);
144 variable_array.visitVariable(add_any_variable, variable);
145 }
146 }
147 return symbol_table;
148}
149
150template <int D>
152 std::vector<std::string> const& variables,
153 std::vector<std::string> const& value_string_expressions,
154 std::vector<std::pair<std::string, std::vector<std::string>>> const&
155 dvalue_string_expressions)
156{
157 auto symbol_table = createSymbolTable(variables);
158
159 // value expressions.
160 value_expressions =
161 compileExpressions(symbol_table, value_string_expressions);
162
163 // dValue expressions.
164 for (auto const& [variable_name, string_expressions] :
165 dvalue_string_expressions)
166 {
167 dvalue_expressions.emplace_back(
168 convertStringToVariable(variable_name),
169 compileExpressions(symbol_table, string_expressions));
170 }
171}
172
173static void updateVariableArrayValues(std::vector<Variable> const& variables,
174 VariableArray const& new_variable_array,
175 VariableArray& variable_array)
176{
177 for (auto const& variable : variables)
178 {
179 auto assign_scalar =
180 [&variable, &new_variable_array](VariableArray::Scalar* address)
181 {
182 double const value = *std::get<VariableArray::Scalar const*>(
183 new_variable_array.address_of(variable));
184
185 if (std::isnan(value))
186 {
187 OGS_FATAL(
188 "Function property: Scalar variable '{:s}' is not "
189 "initialized.",
190 variable_enum_to_string[static_cast<int>(variable)]);
191 }
192
193 *address = value;
194 };
195 auto assign_kelvin_vector = [&variable, &new_variable_array](
197 {
198 auto assign_value = [&destination = *address,
199 &variable]<typename S>(S const& source)
200 {
201 if constexpr (std::is_same_v<S, std::monostate>)
202 {
203 OGS_FATAL(
204 "Function property: Kelvin vector variable '{:s}' is "
205 "not initialized.",
206 variable_enum_to_string[static_cast<int>(variable)]);
207 }
208 else
209 {
210 if (std::holds_alternative<S>(destination))
211 {
212 std::get<S>(destination) = MathLib::KelvinVector::
214 }
215 else
216 {
217 OGS_FATAL(
218 "Function property: Mismatch of Kelvin vector "
219 "sizes for variable {:s}.",
220 variable_enum_to_string[static_cast<int>(
221 variable)]);
222 }
223 }
224 };
225 std::visit(assign_value,
226 *std::get<VariableArray::KelvinVector const*>(
227 new_variable_array.address_of(variable)));
228 };
229 auto assign_deformation_gradient =
230 [&variable,
231 &new_variable_array](VariableArray::DeformationGradient* address)
232 {
233 auto assign_value = [&destination = *address,
234 &variable]<typename S>(S const& source)
235 {
236 if constexpr (std::is_same_v<S, std::monostate>)
237 {
238 OGS_FATAL(
239 "Function property: Vectorized tensor variable '{:s}' "
240 "is not initialized.",
241 variable_enum_to_string[static_cast<int>(variable)]);
242 }
243 else
244 {
245 if (std::holds_alternative<S>(destination))
246 {
247 std::get<S>(destination) = source;
248 }
249 else
250 {
251 OGS_FATAL(
252 "Function property: Mismatch of vectorized tensor "
253 "sizes for variable {:s}.",
254 variable_enum_to_string[static_cast<int>(
255 variable)]);
256 }
257 }
258 };
259 std::visit(assign_value,
260 *std::get<VariableArray::DeformationGradient const*>(
261 new_variable_array.address_of(variable)));
262 };
263
264 variable_array.visitVariable(
265 BaseLib::Overloaded{assign_scalar, assign_kelvin_vector,
266 assign_deformation_gradient},
267 variable);
268 }
269}
270
272 std::vector<Variable> const& variables,
273 VariableArray const& new_variable_array,
274 ParameterLib::SpatialPosition const& pos, double const t,
275 std::vector<exprtk::expression<double>> const& expressions,
276 VariableArray& variable_array, std::mutex& mutex,
277 bool const spatial_position_is_required)
278{
279 std::vector<double> result(expressions.size());
280
281 {
282 std::lock_guard lock_guard(mutex);
283 updateVariableArrayValues(variables, new_variable_array,
284 variable_array);
285
286 std::transform(
287 begin(expressions), end(expressions), begin(result),
288 [t, &pos, spatial_position_is_required](auto const& e)
289 {
290 auto& symbol_table = e.get_symbol_table();
291 symbol_table.get_variable("t")->ref() = t;
292
293 if (spatial_position_is_required)
294 {
295 if (!pos.getCoordinates())
296 {
297 OGS_FATAL(
298 "FunctionParameter: The spatial position "
299 "has to be set by "
300 "coordinates.");
301 }
302 auto const coords = pos.getCoordinates().value();
303 symbol_table.get_variable("x")->ref() = coords[0];
304 symbol_table.get_variable("y")->ref() = coords[1];
305 symbol_table.get_variable("z")->ref() = coords[2];
306 }
307
308 return e.value();
309 });
310 }
311
312 switch (result.size())
313 {
314 case 1:
315 {
316 return result[0];
317 }
318 case 2:
319 {
320 return Eigen::Vector2d{result[0], result[1]};
321 }
322 case 3:
323 {
324 return Eigen::Vector3d{result[0], result[1], result[2]};
325 }
326 case 4:
327 {
328 Eigen::Matrix<double, 2, 2> m;
329 m = Eigen::Map<Eigen::Matrix<double, 2, 2> const>(result.data(), 2,
330 2);
331 return m;
332 }
333 case 9:
334 {
335 Eigen::Matrix<double, 3, 3> m;
336 m = Eigen::Map<Eigen::Matrix<double, 3, 3> const>(result.data(), 3,
337 3);
338 return m;
339 }
340 }
341 OGS_FATAL("Cannot convert a vector of size {} to a PropertyDataType",
342 result.size());
343}
344
345static std::vector<std::string> collectVariables(
346 std::vector<std::string> const& value_string_expressions,
347 std::vector<std::pair<std::string, std::vector<std::string>>> const&
348 dvalue_string_expressions)
349{
350 std::vector<std::string> variables;
351
352 auto collect_variables = [&](auto string_expressions)
353 {
354 for (auto const& string_expression : string_expressions)
355 {
356 if (!exprtk::collect_variables(string_expression, variables))
357 {
358 OGS_FATAL(
359 "Collecting variables from expression '{}' didn't work.",
360 string_expression);
361 }
362 }
363 };
364
365 collect_variables(value_string_expressions);
366 for (auto const& var_name_string_expression : dvalue_string_expressions)
367 {
368 collect_variables(var_name_string_expression.second);
369 }
370
371 BaseLib::makeVectorUnique(variables);
372 return variables;
373}
374
376 std::string name,
377 std::vector<std::string> const& value_string_expressions,
378 std::vector<std::pair<std::string, std::vector<std::string>>> const&
379 dvalue_string_expressions)
380{
381 name_ = std::move(name);
382
383 auto const variables =
384 collectVariables(value_string_expressions, dvalue_string_expressions);
385
386 // filter the strings unrelated to time or spatial position
387 static const std::unordered_set<std::string> filter_not_variables = {
388 "t", "x", "y", "z"};
389 variables_ =
390 variables |
391 std::views::filter([](const std::string& s)
392 { return !filter_not_variables.contains(s); }) |
393 std::views::transform([](std::string const& s)
394 { return convertStringToVariable(s); }) |
395 ranges::to<std::vector>;
396
397 impl2_ = std::make_unique<Implementation<2>>(
398 variables, value_string_expressions, dvalue_string_expressions);
399 impl3_ = std::make_unique<Implementation<3>>(
400 variables, value_string_expressions, dvalue_string_expressions);
401}
402
403std::variant<Function::Implementation<2>*, Function::Implementation<3>*>
405 VariableArray const& variable_array) const
406{
407 if (variable_array.is2D())
408 {
409 return impl2_.get();
410 }
411 if (variable_array.is3D())
412 {
413 return impl3_.get();
414 }
415
416 OGS_FATAL(
417 "Variable array has vectors for 2 and 3 dimensions simultaneously. "
418 "Mixed dimensions cannot be dealt within Function evaluation.");
419}
420
423 double const t, double const /*dt*/) const
424{
425 return std::visit(
426 [&](auto&& impl_ptr)
427 {
428 return evaluateExpressions(variables_, variable_array, pos, t,
429 impl_ptr->value_expressions,
430 impl_ptr->variable_array, mutex_,
431 impl_ptr->spatial_position_is_required);
432 },
434}
435
437 Variable const variable,
439 double const t, double const /*dt*/) const
440{
441 return std::visit(
442 [&](auto&& impl_ptr)
443 {
444 auto const it = std::find_if(begin(impl_ptr->dvalue_expressions),
445 end(impl_ptr->dvalue_expressions),
446 [&variable](auto const& v)
447 { return v.first == variable; });
448
449 if (it == end(impl_ptr->dvalue_expressions))
450 {
451 OGS_FATAL(
452 "Requested derivative with respect to the variable {:s} "
453 "not "
454 "provided for Function-type property {:s}.",
455 variable_enum_to_string[static_cast<int>(variable)], name_);
456 }
457
458 return evaluateExpressions(variables_, variable_array, pos, t,
459 it->second, impl_ptr->variable_array,
460 mutex_,
461 impl_ptr->spatial_position_is_required);
462 },
464}
465
466Function::~Function() = default;
467
468} // namespace MaterialPropertyLib
#define OGS_FATAL(...)
Definition Error.h:26
std::vector< Expression > value_expressions
Definition Function.cpp:71
Implementation(std::vector< std::string > const &variables, std::vector< std::string > const &value_string_expressions, std::vector< std::pair< std::string, std::vector< std::string > > > const &dvalue_string_expressions)
Definition Function.cpp:151
exprtk::symbol_table< double > createSymbolTable(std::vector< std::string > const &variables)
Definition Function.cpp:86
std::vector< std::pair< Variable, std::vector< Expression > > > dvalue_expressions
Definition Function.cpp:76
exprtk::expression< double > Expression
Definition Function.cpp:53
std::unique_ptr< Implementation< 3 > > impl3_
Definition Function.h:53
std::vector< Variable > variables_
Variables used in the exprtk expressions.
Definition Function.h:60
std::variant< Function::Implementation< 2 > *, Function::Implementation< 3 > * > getImplementationForDimensionOfVariableArray(VariableArray const &variable_array) const
Definition Function.cpp:404
Function(std::string name, std::vector< std::string > const &value_string_expressions, std::vector< std::pair< std::string, std::vector< std::string > > > const &dvalue_string_expressions)
Definition Function.cpp:375
PropertyDataType dValue(VariableArray const &variable_array, Variable const variable, ParameterLib::SpatialPosition const &pos, double const t, double const dt) const override
Definition Function.cpp:436
std::unique_ptr< Implementation< 2 > > impl2_
Definition Function.h:52
virtual PropertyDataType value() const
Definition Property.cpp:76
std::variant< std::monostate, Eigen::Vector< double, 5 >, Eigen::Vector< double, 9 > > DeformationGradient
std::variant< std::monostate, Eigen::Vector< double, 4 >, Eigen::Vector< double, 6 > > KelvinVector
VariablePointerConst address_of(Variable const v) const
auto visitVariable(Visitor &&visitor, Variable const variable)
std::optional< MathLib::Point3d > const getCoordinates() const
void makeVectorUnique(std::vector< T > &v)
Definition Algorithm.h:180
static std::vector< exprtk::expression< T > > compileExpressions(exprtk::symbol_table< T > &symbol_table, std::vector< std::string > const &string_expressions)
Definition Function.cpp:29
static std::vector< std::string > collectVariables(std::vector< std::string > const &value_string_expressions, std::vector< std::pair< std::string, std::vector< std::string > > > const &dvalue_string_expressions)
Definition Function.cpp:345
static void updateVariableArrayValues(std::vector< Variable > const &variables, VariableArray const &new_variable_array, VariableArray &variable_array)
Definition Function.cpp:173
static PropertyDataType evaluateExpressions(std::vector< Variable > const &variables, VariableArray const &new_variable_array, ParameterLib::SpatialPosition const &pos, double const t, std::vector< exprtk::expression< double > > const &expressions, VariableArray &variable_array, std::mutex &mutex, bool const spatial_position_is_required)
Definition Function.cpp:271
static const std::array< std::string, static_cast< int >(Variable::number_of_variables)> variable_enum_to_string
Variable convertStringToVariable(std::string const &string)
std::variant< double, Eigen::Matrix< double, 2, 1 >, Eigen::Matrix< double, 3, 1 >, Eigen::Matrix< double, 2, 2 >, Eigen::Matrix< double, 3, 3 >, Eigen::Matrix< double, 4, 1 >, Eigen::Matrix< double, 6, 1 >, Eigen::MatrixXd > PropertyDataType
Definition Property.h:31
Eigen::Matrix< double, 4, 1 > kelvinVectorToSymmetricTensor(Eigen::Matrix< double, 4, 1, Eigen::ColMajor, 4, 1 > const &v)
constexpr int kelvin_vector_dimensions(int const displacement_dim)
Kelvin vector dimensions for given displacement dimension.
constexpr int size(int const displacement_dim)
Vectorized tensor size for given displacement dimension.