OGS
ExprtkUtils.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#include "ExprtkUtils.h"
5
6#include <cassert>
7
8#include "BaseLib/Algorithm.h"
9
10namespace ParameterLib
11{
12
14 SpatialPosition const& pos) const
15{
16 // t_ptr is null only on a default-constructed cache, which exists solely
17 // to satisfy compilation of PerThreadData's (forbidden, OGS_FATAL) move
18 // ctor and is never evaluated against.
19 assert(t_ptr != nullptr);
20 *t_ptr = t;
21 // x_ptr is non-null iff the constructor was called with
22 // spatial_position_is_required=true; use it as the sentinel.
23 if (x_ptr != nullptr)
24 {
25 // Invariant: all three spatial pointers are set together.
26 assert(y_ptr != nullptr && z_ptr != nullptr);
27 if (!pos.getCoordinates())
28 {
30 "An expression requires spatial position (x, y, z), "
31 "but no coordinates have been set.");
32 }
33 auto const coords = pos.getCoordinates().value();
34 *x_ptr = coords[0];
35 *y_ptr = coords[1];
36 *z_ptr = coords[2];
37 }
38}
39
40bool isBuiltinSymbol(std::string_view const name)
41{
42 return name == "t" || name == "x" || name == "y" || name == "z";
43}
44
45bool hasSpatialVariables(std::vector<std::string> const& variables)
46{
47 return std::ranges::any_of(variables, [](std::string const& v)
48 { return v == "x" || v == "y" || v == "z"; });
49}
50
51exprtk::symbol_table<double> createBaseSymbolTable(
52 bool spatial_position_is_required)
53{
54 exprtk::symbol_table<double> symbol_table;
55 symbol_table.add_constants();
56 symbol_table.create_variable("t");
57 if (spatial_position_is_required)
58 {
59 symbol_table.create_variable("x");
60 symbol_table.create_variable("y");
61 symbol_table.create_variable("z");
62 }
63 return symbol_table;
64}
65
67 exprtk::symbol_table<double>& symbol_table,
68 std::vector<std::string> const& curve_names,
69 std::map<std::string,
70 std::unique_ptr<MathLib::PiecewiseLinearInterpolation>> const&
71 curves,
72 std::map<std::string, CurveWrapper>& curve_wrappers)
73{
74 for (auto const& name : curve_names)
75 {
76 if (exprtk::details::is_reserved_symbol(name))
77 {
79 "Curve name '{:s}' collides with an exprtk reserved symbol "
80 "(built-in function or keyword). Such a curve cannot be "
81 "registered: the built-in would silently be used instead. "
82 "Please rename the curve.",
83 name);
84 }
85 curve_wrappers.emplace(name, CurveWrapper(*curves.at(name)));
86 }
87 for (auto& [name, wrapper] : curve_wrappers)
88 {
89 if (!symbol_table.add_function(name, wrapper))
90 {
92 "Failed to register curve '{:s}' as an exprtk function. The "
93 "name is likely already in use (reserved symbol or duplicate).",
94 name);
95 }
96 }
97}
98
99SymbolTableCache::SymbolTableCache(exprtk::symbol_table<double>& symbol_table,
100 bool const spatial_position_is_required)
101 : spatial_position_is_required_(spatial_position_is_required)
102{
103 reinitialize(symbol_table);
104}
105
106void SymbolTableCache::reinitialize(exprtk::symbol_table<double>& symbol_table)
107{
108 t_ptr = &(symbol_table.get_variable("t")->ref());
110 {
111 x_ptr = &(symbol_table.get_variable("x")->ref());
112 y_ptr = &(symbol_table.get_variable("y")->ref());
113 z_ptr = &(symbol_table.get_variable("z")->ref());
114 }
115 else
116 {
117 x_ptr = nullptr;
118 y_ptr = nullptr;
119 z_ptr = nullptr;
120 }
121}
122
123template std::vector<exprtk::expression<double>> compileExpressions<double>(
124 exprtk::symbol_table<double>&, std::vector<std::string> const&);
125
126std::vector<std::string> collectVariables(
127 std::vector<std::string> const& expression_strings)
128{
129 std::vector<std::string> expression_symbol_names;
130 for (auto const& expr : expression_strings)
131 {
132 if (!exprtk::collect_variables(expr, expression_symbol_names))
133 {
134 OGS_FATAL("Collecting variables from expression '{}' didn't work.",
135 expr);
136 }
137 }
138 BaseLib::makeVectorUnique(expression_symbol_names);
139
140 // exprtk::collect_variables reports the named constants added by
141 // add_constants() (pi, epsilon, inf) as variables. Drop them so that
142 // downstream code does not try to (re)create them as variables and clash
143 // with the constants. A base symbol table is used so the set of constants
144 // is queried from exprtk itself rather than hard-coded.
145 auto const constants = createBaseSymbolTable(false);
146 std::erase_if(expression_symbol_names,
147 [&constants](std::string const& name)
148 { return constants.is_constant_node(name); });
149
150 return expression_symbol_names;
151}
152
153std::vector<std::string> collectUsedCurveNames(
154 std::vector<std::string> const& expression_symbol_names,
155 std::map<std::string,
156 std::unique_ptr<MathLib::PiecewiseLinearInterpolation>> const&
157 curves)
158{
159 std::vector<std::string> used;
160 for (auto const& v : expression_symbol_names)
161 {
162 if (curves.contains(v))
163 {
164 used.push_back(v);
165 }
166 }
167 return used;
168}
169
170} // namespace ParameterLib
#define OGS_FATAL(...)
Definition Error.h:10
std::optional< MathLib::Point3d > const getCoordinates() const
void makeVectorUnique(std::vector< T > &v)
Definition Algorithm.h:198
bool isBuiltinSymbol(std::string_view const name)
exprtk::symbol_table< double > createBaseSymbolTable(bool spatial_position_is_required)
void registerCurveWrappers(exprtk::symbol_table< double > &symbol_table, std::vector< std::string > const &curve_names, std::map< std::string, std::unique_ptr< MathLib::PiecewiseLinearInterpolation > > const &curves, std::map< std::string, CurveWrapper > &curve_wrappers)
std::vector< std::string > collectVariables(std::vector< std::string > const &expression_strings)
template std::vector< exprtk::expression< double > > compileExpressions< double >(exprtk::symbol_table< double > &, std::vector< std::string > const &)
std::vector< std::string > collectUsedCurveNames(std::vector< std::string > const &expression_symbol_names, std::map< std::string, std::unique_ptr< MathLib::PiecewiseLinearInterpolation > > const &curves)
Returns the subset of expression_symbol_names that are keys in curves.
bool hasSpatialVariables(std::vector< std::string > const &variables)
void setTimeAndPosition(double t, SpatialPosition const &pos) const
void reinitialize(exprtk::symbol_table< double > &symbol_table)
Re-caches pointers from a (possibly moved) symbol_table.