version 3.10-dev
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-FileCopyrightInfo: 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 std::lock_guard lock(evalMutex_);
95 for (std::size_t i = 0; i < numVars; ++i)
96 variables_[i] = params[i];
97 return expression_.value();
98 }
99
100 template<std::size_t... I>
101 std::array<std::string, numVars> extractVariableNames_(std::string_view names, std::index_sequence<I...>) const
102 {
103 static_assert(numVars == sizeof...(I), "Number of variables has to match size of index set.");
104 if (names.size() != numVars)
105 DUNE_THROW(Dune::IOError, "Number of variables in '"
106 << names << "' does not match number of function arguments: " << numVars);
107 return { std::string(1, names.at(I))... };
108 }
109
111 void initialize_(const std::string& expression, const std::array<std::string, numVars>& variableNames)
112 {
113 for (std::size_t i = 0; i < numVars; ++i)
114 symbolTable_.add_variable(std::string{variableNames[i]}, variables_[i]);
115 symbolTable_.add_constants();
116 expression_.register_symbol_table(symbolTable_);
117
118 if (!parser_.compile(expression, expression_))
119 {
120 std::stringstream ss;
121 ss << Fmt::format("Parsing expression '{}' failed.\n", expression);
122
123 if (verbosity_ >= 1)
124 {
125 for (std::size_t i = 0; i < parser_.error_count(); ++i)
126 {
127 const auto error = parser_.get_error(i);
128
129 ss << Fmt::format(
130 "-- error (position: {:02d}, type: {}): {}\n",
131 static_cast<unsigned int>(error.token.position),
132 exprtk::parser_error::to_str(error.mode).c_str(),
133 error.diagnostic.c_str()
134 );
135 }
136 }
137
138 DUNE_THROW(Dune::IOError, ss.str());
139 }
140 else if (verbosity_ >= 2)
141 {
142 std::cout << Fmt::format(
143 "Successfully parsed math expression '{}'\n",
144 expression
145 );
146 }
147 }
148
149 unsigned int verbosity_ = 2;
150 SymbolTable symbolTable_;
151 Expression expression_;
152 Parser parser_;
153 mutable std::array<Scalar, numVars> variables_;
154 mutable std::mutex evalMutex_;
155};
156
157} // end namespace Dumux
158
159#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.
Definition: adapt.hh:17