version 3.11-dev
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages Concepts
functionfromstringexpression.hh
Go to the documentation of this file.
1// -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2// vi: set et ts=4 sw=4 sts=4:
3//
4// SPDX-FileCopyrightText: Copyright © DuMux Project contributors, see AUTHORS.md in root folder
5// SPDX-License-Identifier: GPL-3.0-or-later
6//
12#ifndef DUMUX_COMMON_FUNCTION_FROM_STRING_EXPRESSION_HH
13#define DUMUX_COMMON_FUNCTION_FROM_STRING_EXPRESSION_HH
14
15#include <array>
16#include <mutex>
17#include <string>
18#include <string_view>
19#include <type_traits>
20#include <iostream>
21
22#include <dune/common/exceptions.hh>
23#include <dune/common/fvector.hh>
24
25#include <dumux/io/format.hh>
26#include <dumux/io/expression/exprtk.hpp>
27
28namespace Dumux {
29
56template<std::size_t numVars, class Scalar = double>
58{
59 using SymbolTable = exprtk::symbol_table<Scalar>;
60 using Expression = exprtk::expression<Scalar>;
61 using Parser = exprtk::parser<Scalar>;
62
63public:
64 static constexpr std::size_t numVariables = numVars;
65
67 FunctionFromStringExpression(const std::string& expression, const std::array<std::string, numVars>& variableNames)
68 { initialize_(expression, variableNames); }
69
72 FunctionFromStringExpression(const std::string& expression, std::string_view variableNames)
73 : FunctionFromStringExpression(expression, extractVariableNames_(variableNames, std::make_index_sequence<numVars>{})) {}
74
75 template<class S, std::enable_if_t<std::is_convertible_v<Scalar, S>, int> = 0>
76 Scalar operator() (const std::array<S, numVars>& params) const
77 { return evalRandomAcessImpl_(params); }
78
79 template<class S, std::enable_if_t<std::is_convertible_v<Scalar, S>, int> = 0>
80 Scalar operator() (const Dune::FieldVector<S, numVars>& params) const
81 { return evalRandomAcessImpl_(params); }
82
83 template<class ...Params, std::enable_if_t<(sizeof...(Params) == numVars) && (std::is_convertible_v<Scalar, std::decay_t<Params>> && ...), int> = 0>
84 Scalar operator() (Params&&... params) const
85 { return evalRandomAcessImpl_(std::array<Scalar, numVars>{ std::forward<Params>(params)... }); }
86
87 void setVerbosity(unsigned int v)
88 { verbosity_ = v; }
89
90private:
91 template<class RandomAccessContainer>
92 Scalar evalRandomAcessImpl_(const RandomAccessContainer& params) const
93 {
94 if constexpr (numVars > 0)
95 {
96 std::lock_guard lock(evalMutex_);
97 for (std::size_t i = 0; i < numVars; ++i)
98 variables_[i] = params[i];
99 return expression_.value();
100 }
101 else
102 return expression_.value();
103 }
104
105 template<std::size_t... I>
106 std::array<std::string, numVars> extractVariableNames_(std::string_view names, std::index_sequence<I...>) const
107 {
108 static_assert(numVars == sizeof...(I), "Number of variables has to match size of index set.");
109 if (names.size() != numVars)
110 DUNE_THROW(Dune::IOError, "Number of variables in '"
111 << names << "' does not match number of function arguments: " << numVars);
112 return { std::string(1, names.at(I))... };
113 }
114
116 void initialize_(const std::string& expression, const std::array<std::string, numVars>& variableNames)
117 {
118 for (std::size_t i = 0; i < numVars; ++i)
119 symbolTable_.add_variable(std::string{variableNames[i]}, variables_[i]);
120 symbolTable_.add_constants();
121 expression_.register_symbol_table(symbolTable_);
122
123 if (!parser_.compile(expression, expression_))
124 {
125 std::stringstream ss;
126 ss << Fmt::format("Parsing expression '{}' failed.\n", expression);
127
128 if (verbosity_ >= 1)
129 {
130 for (std::size_t i = 0; i < parser_.error_count(); ++i)
131 {
132 const auto error = parser_.get_error(i);
133
134 ss << Fmt::format(
135 "-- error (position: {:02d}, type: {}): {}\n",
136 static_cast<unsigned int>(error.token.position),
137 exprtk::parser_error::to_str(error.mode).c_str(),
138 error.diagnostic.c_str()
139 );
140 }
141 }
142
143 DUNE_THROW(Dune::IOError, ss.str());
144 }
145 else if (verbosity_ >= 2)
146 {
147 std::cout << Fmt::format(
148 "Successfully parsed math expression '{}'\n",
149 expression
150 );
151 }
152 }
153
154 unsigned int verbosity_ = 2;
155 SymbolTable symbolTable_;
156 Expression expression_;
157 Parser parser_;
158 mutable std::array<Scalar, numVars> variables_;
159 mutable std::mutex evalMutex_;
160};
161
167template<class Scalar = double>
168Scalar evalStringExpression(const std::string& expression, int verbosity = 0)
169{
170 FunctionFromStringExpression<0, Scalar> f{ expression, "" };
171 f.setVerbosity(verbosity);
172 return f();
173}
174
175} // end namespace Dumux
176
177#endif
Evaluating string math expressions containing named variables.
Definition: functionfromstringexpression.hh:58
void setVerbosity(unsigned int v)
Definition: functionfromstringexpression.hh:87
Scalar operator()(const std::array< S, numVars > &params) const
Definition: functionfromstringexpression.hh:76
static constexpr std::size_t numVariables
Definition: functionfromstringexpression.hh:64
FunctionFromStringExpression(const std::string &expression, std::string_view variableNames)
Delegating constructor using all characters of a string as variables.
Definition: functionfromstringexpression.hh:72
FunctionFromStringExpression(const std::string &expression, const std::array< std::string, numVars > &variableNames)
Constructor from math expression and array of variable names.
Definition: functionfromstringexpression.hh:67
Formatting based on the fmt-library which implements std::format of C++20.
Scalar evalStringExpression(const std::string &expression, int verbosity=0)
Evaluating simple string math expressions.
Definition: functionfromstringexpression.hh:168
Definition: adapt.hh:17