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 <typeinfo>
17
18#include "BaseLib/Algorithm.h"
21
22namespace MaterialPropertyLib
23{
24// Passing symbol table by reference as required by register_symbol_table()
25// call.
26template <typename T>
27static std::vector<exprtk::expression<T>> compileExpressions(
28 exprtk::symbol_table<T>& symbol_table,
29 std::vector<std::string> const& string_expressions)
30{
31 exprtk::parser<T> parser;
32
33 std::vector<exprtk::expression<T>> expressions(string_expressions.size());
34 for (unsigned i = 0; i < string_expressions.size(); ++i)
35 {
36 expressions[i].register_symbol_table(symbol_table);
37 if (!parser.compile(string_expressions[i], expressions[i]))
38 {
39 OGS_FATAL("Error: {:s}\tExpression: {:s}\n",
40 parser.error(),
41 string_expressions[i]);
42 }
43 }
44 return expressions;
45}
46
47template <int D>
48class Function::Implementation
49{
50public:
51 using Expression = exprtk::expression<double>;
52
53public:
55 std::vector<std::string> const& variables,
56 std::vector<std::string> const& value_string_expressions,
57 std::vector<std::pair<std::string, std::vector<std::string>>> const&
58 dvalue_string_expressions);
59
60private:
63 exprtk::symbol_table<double> createSymbolTable(
64 std::vector<std::string> const& variables);
65
66public:
69 std::vector<Expression> value_expressions;
70
73 std::vector<std::pair<Variable, std::vector<Expression>>>
75
79};
80
81template <int D>
83 std::vector<std::string> const& variables)
84{
85 exprtk::symbol_table<double> symbol_table;
86
87 for (auto const& v : variables)
88 {
89 auto add_scalar = [&v, &symbol_table](double& value)
90 { symbol_table.add_variable(v, value); };
91
92 auto add_vector =
93 [&v, &symbol_table](double* ptr, std::size_t const size)
94 { symbol_table.add_vector(v, ptr, size); };
95
96 auto add_any_variable = BaseLib::Overloaded{
97 [&add_scalar](VariableArray::Scalar* address)
98 { add_scalar(*address); },
99 [&add_vector](VariableArray::KelvinVector* address)
100 {
101 auto constexpr size =
103 auto& result =
104 address->template emplace<Eigen::Matrix<double, size, 1>>();
105 add_vector(result.data(), size);
106 },
107 [&add_vector](VariableArray::DeformationGradient* address)
108 {
109 auto constexpr size = MathLib::VectorizedTensor::size(D);
110 auto& result =
111 address->template emplace<Eigen::Matrix<double, size, 1>>();
112 add_vector(result.data(), size);
113 }};
114
115 Variable const variable = convertStringToVariable(v);
116 variable_array.visitVariable(add_any_variable, variable);
117 }
118 return symbol_table;
119}
120
121template <int D>
123 std::vector<std::string> const& variables,
124 std::vector<std::string> const& value_string_expressions,
125 std::vector<std::pair<std::string, std::vector<std::string>>> const&
126 dvalue_string_expressions)
127{
128 auto symbol_table = createSymbolTable(variables);
129
130 // value expressions.
131 value_expressions =
132 compileExpressions(symbol_table, value_string_expressions);
133
134 // dValue expressions.
135 for (auto const& [variable_name, string_expressions] :
136 dvalue_string_expressions)
137 {
138 dvalue_expressions.emplace_back(
139 convertStringToVariable(variable_name),
140 compileExpressions(symbol_table, string_expressions));
141 }
142}
143
144static void updateVariableArrayValues(std::vector<Variable> const& variables,
145 VariableArray const& new_variable_array,
146 VariableArray& variable_array)
147{
148 for (auto const& variable : variables)
149 {
150 auto assign_scalar =
151 [&variable, &new_variable_array](VariableArray::Scalar* address)
152 {
153 double const value = *std::get<VariableArray::Scalar const*>(
154 new_variable_array.address_of(variable));
155
156 if (std::isnan(value))
157 {
158 OGS_FATAL(
159 "Function property: Scalar variable '{:s}' is not "
160 "initialized.",
161 variable_enum_to_string[static_cast<int>(variable)]);
162 }
163
164 *address = value;
165 };
166 auto assign_kelvin_vector = [&variable, &new_variable_array](
168 {
169 auto assign_value = [&destination = *address,
170 &variable]<typename S>(S const& source)
171 {
172 if constexpr (std::is_same_v<S, std::monostate>)
173 {
174 OGS_FATAL(
175 "Function property: Kelvin vector variable '{:s}' is "
176 "not initialized.",
177 variable_enum_to_string[static_cast<int>(variable)]);
178 }
179 else
180 {
181 if (std::holds_alternative<S>(destination))
182 {
183 std::get<S>(destination) = MathLib::KelvinVector::
185 }
186 else
187 {
188 OGS_FATAL(
189 "Function property: Mismatch of Kelvin vector "
190 "sizes for variable {:s}.",
191 variable_enum_to_string[static_cast<int>(
192 variable)]);
193 }
194 }
195 };
196 std::visit(assign_value,
197 *std::get<VariableArray::KelvinVector const*>(
198 new_variable_array.address_of(variable)));
199 };
200 auto assign_deformation_gradient =
201 [&variable,
202 &new_variable_array](VariableArray::DeformationGradient* address)
203 {
204 auto assign_value = [&destination = *address,
205 &variable]<typename S>(S const& source)
206 {
207 if constexpr (std::is_same_v<S, std::monostate>)
208 {
209 OGS_FATAL(
210 "Function property: Vectorized tensor variable '{:s}' "
211 "is not initialized.",
212 variable_enum_to_string[static_cast<int>(variable)]);
213 }
214 else
215 {
216 if (std::holds_alternative<S>(destination))
217 {
218 std::get<S>(destination) = source;
219 }
220 else
221 {
222 OGS_FATAL(
223 "Function property: Mismatch of vectorized tensor "
224 "sizes for variable {:s}.",
225 variable_enum_to_string[static_cast<int>(
226 variable)]);
227 }
228 }
229 };
230 std::visit(assign_value,
231 *std::get<VariableArray::DeformationGradient const*>(
232 new_variable_array.address_of(variable)));
233 };
234
235 variable_array.visitVariable(
236 BaseLib::Overloaded{assign_scalar, assign_kelvin_vector,
237 assign_deformation_gradient},
238 variable);
239 }
240}
241
243 std::vector<Variable> const& variables,
244 VariableArray const& new_variable_array,
245 std::vector<exprtk::expression<double>> const& expressions,
246 VariableArray& variable_array,
247 std::mutex& mutex)
248{
249 std::vector<double> result(expressions.size());
250
251 {
252 std::lock_guard lock_guard(mutex);
253 updateVariableArrayValues(variables, new_variable_array,
254 variable_array);
255
256 std::transform(begin(expressions), end(expressions), begin(result),
257 [](auto const& e) { return e.value(); });
258 }
259
260 switch (result.size())
261 {
262 case 1:
263 {
264 return result[0];
265 }
266 case 2:
267 {
268 return Eigen::Vector2d{result[0], result[1]};
269 }
270 case 3:
271 {
272 return Eigen::Vector3d{result[0], result[1], result[2]};
273 }
274 case 4:
275 {
276 Eigen::Matrix<double, 2, 2> m;
277 m = Eigen::Map<Eigen::Matrix<double, 2, 2> const>(result.data(), 2,
278 2);
279 return m;
280 }
281 case 9:
282 {
283 Eigen::Matrix<double, 3, 3> m;
284 m = Eigen::Map<Eigen::Matrix<double, 3, 3> const>(result.data(), 3,
285 3);
286 return m;
287 }
288 }
289 OGS_FATAL("Cannot convert a vector of size {} to a PropertyDataType",
290 result.size());
291}
292
293static std::vector<std::string> collectVariables(
294 std::vector<std::string> const& value_string_expressions,
295 std::vector<std::pair<std::string, std::vector<std::string>>> const&
296 dvalue_string_expressions)
297{
298 std::vector<std::string> variables;
299
300 auto collect_variables = [&](auto string_expressions)
301 {
302 for (auto const& string_expression : string_expressions)
303 {
304 if (!exprtk::collect_variables(string_expression, variables))
305 {
306 OGS_FATAL(
307 "Collecting variables from expression '{}' didn't work.",
308 string_expression);
309 }
310 }
311 };
312
313 collect_variables(value_string_expressions);
314 for (auto const& var_name_string_expression : dvalue_string_expressions)
315 {
316 collect_variables(var_name_string_expression.second);
317 }
318
319 BaseLib::makeVectorUnique(variables);
320 return variables;
321}
322
324 std::string name,
325 std::vector<std::string> const& value_string_expressions,
326 std::vector<std::pair<std::string, std::vector<std::string>>> const&
327 dvalue_string_expressions)
328{
329 name_ = std::move(name);
330
331 auto const variables =
332 collectVariables(value_string_expressions, dvalue_string_expressions);
333 variables_ =
334 variables |
335 ranges::views::transform([](std::string const& s)
336 { return convertStringToVariable(s); }) |
337 ranges::to<std::vector>;
338
339 impl2_ = std::make_unique<Implementation<2>>(
340 variables, value_string_expressions, dvalue_string_expressions);
341 impl3_ = std::make_unique<Implementation<3>>(
342 variables, value_string_expressions, dvalue_string_expressions);
343}
344
345std::variant<Function::Implementation<2>*, Function::Implementation<3>*>
347 VariableArray const& variable_array) const
348{
349 if (variable_array.is2D())
350 {
351 return impl2_.get();
352 }
353 if (variable_array.is3D())
354 {
355 return impl3_.get();
356 }
357
358 OGS_FATAL(
359 "Variable array has vectors for 2 and 3 dimensions simultaneously. "
360 "Mixed dimensions cannot be dealt within Function evaluation.");
361}
362
364 ParameterLib::SpatialPosition const& /*pos*/,
365 double const /*t*/, double const /*dt*/) const
366{
367 return std::visit(
368 [&](auto&& impl_ptr)
369 {
370 return evaluateExpressions(variables_, variable_array,
371 impl_ptr->value_expressions,
372 impl_ptr->variable_array, mutex_);
373 },
375}
376
378 Variable const variable,
379 ParameterLib::SpatialPosition const& /*pos*/,
380 double const /*t*/, double const /*dt*/) const
381{
382 return std::visit(
383 [&](auto&& impl_ptr)
384 {
385 auto const it = std::find_if(begin(impl_ptr->dvalue_expressions),
386 end(impl_ptr->dvalue_expressions),
387 [&variable](auto const& v)
388 { return v.first == variable; });
389
390 if (it == end(impl_ptr->dvalue_expressions))
391 {
392 OGS_FATAL(
393 "Requested derivative with respect to the variable {:s} "
394 "not "
395 "provided for Function-type property {:s}.",
396 variable_enum_to_string[static_cast<int>(variable)], name_);
397 }
398
399 return evaluateExpressions(variables_, variable_array, it->second,
400 impl_ptr->variable_array, mutex_);
401 },
403}
404
405Function::~Function() = default;
406
407} // namespace MaterialPropertyLib
#define OGS_FATAL(...)
Definition Error.h:26
std::vector< Expression > value_expressions
Definition Function.cpp:69
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:122
exprtk::symbol_table< double > createSymbolTable(std::vector< std::string > const &variables)
Definition Function.cpp:82
std::vector< std::pair< Variable, std::vector< Expression > > > dvalue_expressions
Definition Function.cpp:74
exprtk::expression< double > Expression
Definition Function.cpp:51
std::unique_ptr< Implementation< 3 > > impl3_
Definition Function.h:52
std::vector< Variable > variables_
Variables used in the exprtk expressions.
Definition Function.h:59
std::variant< Function::Implementation< 2 > *, Function::Implementation< 3 > * > getImplementationForDimensionOfVariableArray(VariableArray const &variable_array) const
Definition Function.cpp:346
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:323
PropertyDataType dValue(VariableArray const &variable_array, Variable const variable, ParameterLib::SpatialPosition const &pos, double const t, double const dt) const override
Definition Function.cpp:377
std::unique_ptr< Implementation< 2 > > impl2_
Definition Function.h:51
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)
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:27
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:293
static PropertyDataType evaluateExpressions(std::vector< Variable > const &variables, VariableArray const &new_variable_array, std::vector< exprtk::expression< double > > const &expressions, VariableArray &variable_array, std::mutex &mutex)
Definition Function.cpp:242
static void updateVariableArrayValues(std::vector< Variable > const &variables, VariableArray const &new_variable_array, VariableArray &variable_array)
Definition Function.cpp:144
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.