PolyFEM
Loading...
Searching...
No Matches
ExpressionValue.cpp
Go to the documentation of this file.
1#include "ExpressionValue.hpp"
2
5
6#include <units/units.hpp>
7
8#include <igl/PI.h>
9
10#include <tinyexpr.h>
11#include <filesystem>
12
13#include <iostream>
14
15namespace polyfem
16{
17 using namespace io;
18
19 namespace utils
20 {
21 static double min(double a, double b) { return a < b ? a : b; }
22 static double max(double a, double b) { return a > b ? a : b; }
23 static double smoothstep(double a)
24 {
25 if (a < 0)
26 return 0;
27 else if (a > 1)
28 return 1;
29 else
30 return (3 * pow(a, 2)) - (2 * pow(a, 3));
31 }
32 static double half_smoothstep(double a)
33 {
34 double b = (a + 1.) / 2.;
35 return 2. * smoothstep(b) - 1.;
36 }
37 static double deg2rad(double d) { return d * igl::PI / 180.0; }
38 static double rotate_2D_x(double x, double y, double theta)
39 {
40 return x * cos(theta) - y * sin(theta);
41 }
42 static double rotate_2D_y(double x, double y, double theta)
43 {
44 return x * sin(theta) + y * cos(theta);
45 }
46 static double smooth_abs(double x, double k)
47 {
48 return tanh(k * x) * x;
49 }
50 static double iflargerthanzerothenelse(double check, double ttrue, double ffalse)
51 {
52 return check >= 0 ? ttrue : ffalse;
53 }
54 static double sign(double x)
55 {
56 return (0 < x) - (x < 0);
57 }
58 static double compare(double a, double b)
59 {
60 return a < b ? 1.0 : 0.0;
61 }
62
67
69 {
70 expr_ = "";
71 mat_.resize(0, 0);
72 mat_expr_ = {};
73 sfunc_ = nullptr;
74 tfunc_ = nullptr;
75 value_ = 0;
76 }
77
78 void ExpressionValue::init(const double val)
79 {
80 clear();
81
82 value_ = val;
83 }
84
85 void ExpressionValue::init(const Eigen::MatrixXd &val)
86 {
87 clear();
88
89 mat_ = val;
90 }
91
92 void ExpressionValue::init(const std::string &expr)
93 {
94 clear();
95
96 if (expr.empty())
97 {
98 return;
99 }
100
101 const auto path = std::filesystem::path(expr);
102
103 try
104 {
105 /* code */
106 if (std::filesystem::is_regular_file(path))
107 {
108 read_matrix(expr, mat_);
109 return;
110 }
111 }
112 catch (const std::filesystem::filesystem_error &e)
113 {
114 }
115
116 expr_ = expr;
117
118 double x = 0, y = 0, z = 0, t = 0;
119
120 std::vector<te_variable> vars = {
121 {"x", &x, TE_VARIABLE},
122 {"y", &y, TE_VARIABLE},
123 {"z", &z, TE_VARIABLE},
124 {"t", &t, TE_VARIABLE},
125 {"min", (const void *)min, TE_FUNCTION2},
126 {"max", (const void *)max, TE_FUNCTION2},
127 {"smoothstep", (const void *)smoothstep, TE_FUNCTION1},
128 {"half_smoothstep", (const void *)half_smoothstep, TE_FUNCTION1},
129 {"deg2rad", (const void *)deg2rad, TE_FUNCTION1},
130 {"rotate_2D_x", (const void *)rotate_2D_x, TE_FUNCTION3},
131 {"rotate_2D_y", (const void *)rotate_2D_y, TE_FUNCTION3},
132 {"if", (const void *)iflargerthanzerothenelse, TE_FUNCTION3},
133 {"compare", (const void *)compare, TE_FUNCTION2},
134 {"smooth_abs", (const void *)smooth_abs, TE_FUNCTION2},
135 {"sign", (const void *)sign, TE_FUNCTION1},
136 };
137
138 int err;
139 te_expr *tmp = te_compile(expr.c_str(), vars.data(), vars.size(), &err);
140 if (!tmp)
141 {
142 logger().error("Unable to parse: {}", expr);
143 logger().error("Error near here: {0: >{1}}", "^", err - 1);
144 assert(false);
145 }
146 te_free(tmp);
147 }
148
150 {
151 clear();
152
153 if (vals.is_number())
154 {
155 init(vals.get<double>());
156 }
157 else if (vals.is_array())
158 {
159 mat_.resize(vals.size(), 1);
160
161 for (int i = 0; i < mat_.size(); ++i)
162 {
163 if (vals[i].is_string())
164 break;
165 mat_(i) = vals[i];
166 }
167
168 if (vals.size() > 0 && vals[0].is_string())
169 {
170 mat_.resize(0, 0);
171 mat_expr_ = std::vector<ExpressionValue>(vals.size());
172
173 for (int i = 0; i < vals.size(); ++i)
174 {
175 mat_expr_[i].init(vals[i]);
176 }
177 }
178
179 if (t_index_.size() > 0)
180 if (mat_.size() != t_index_.size() && mat_expr_.size() != t_index_.size())
181 logger().error("Specifying varying dirichlet over time, however 'time_reference' does not match dirichlet boundary conditions.");
182 }
183 else if (vals.is_object())
184 {
185
186 unit_ = units::unit_from_string(vals["unit"].get<std::string>());
187 init(vals["value"]);
188 }
189 else
190 {
191 init(vals.get<std::string>());
192 }
193 }
194
195 void ExpressionValue::init(const std::function<double(double x, double y, double z)> &func)
196 {
197 clear();
198
199 sfunc_ = [func](double x, double y, double z, double t, int index) { return func(x, y, z); };
200 }
201
202 void ExpressionValue::init(const std::function<double(double x, double y, double z, double t)> &func)
203 {
204 clear();
205 sfunc_ = [func](double x, double y, double z, double t, double index) { return func(x, y, z, t); };
206 }
207
208 void ExpressionValue::init(const std::function<double(double x, double y, double z, double t, int index)> &func)
209 {
210 clear();
211 sfunc_ = func;
212 }
213
214 void ExpressionValue::init(const std::function<Eigen::MatrixXd(double x, double y, double z)> &func, const int coo)
215 {
216 clear();
217
218 tfunc_ = [func](double x, double y, double z, double t) { return func(x, y, z); };
219 tfunc_coo_ = coo;
220 }
221
222 void ExpressionValue::init(const std::function<Eigen::MatrixXd(double x, double y, double z, double t)> &func, const int coo)
223 {
224 clear();
225
226 tfunc_ = func;
227 tfunc_coo_ = coo;
228 }
229
231 {
232 if (t.is_array())
233 {
234 for (int i = 0; i < t.size(); ++i)
235 {
236 t_index_[std::round(t[i].get<double>() * 1000.) / 1000.] = i;
237 }
238
239 if (mat_.size() != t_index_.size() && mat_expr_.size() != t_index_.size())
240 logger().error("Specifying varying dirichlet over time, however 'time_reference' does not match dirichlet boundary conditions.");
241 }
242 }
243
244 double ExpressionValue::operator()(double x, double y, double z, double t, int index) const
245 {
246 assert(unit_type_set_);
247
248 double result;
249 if (expr_.empty())
250 {
251 if (t_index_.size() > 0)
252 {
253 t = std::round(t * 1000.) / 1000.;
254 if (t_index_.count(t) != 0)
255 {
256 if (mat_.size() > 0)
257 return mat_(t_index_.at(t));
258 else if (mat_expr_.size() > 0)
259 return mat_expr_[t_index_.at(t)](x, y, z, t, index);
260 }
261 else
262 {
263 logger().error("Cannot find dirichlet condition for time step {}.", t);
264 return 0;
265 }
266 }
267
268 if (mat_.size() > 0)
269 result = mat_(index);
270 else if (sfunc_)
271 result = sfunc_(x, y, z, t, index);
272 else if (tfunc_)
273 result = tfunc_(x, y, z, t)(tfunc_coo_);
274 else
275 result = value_;
276 }
277 else
278 {
279
280 std::vector<te_variable> vars = {
281 {"x", &x, TE_VARIABLE},
282 {"y", &y, TE_VARIABLE},
283 {"z", &z, TE_VARIABLE},
284 {"t", &t, TE_VARIABLE},
285 {"min", (const void *)min, TE_FUNCTION2},
286 {"max", (const void *)max, TE_FUNCTION2},
287 {"smoothstep", (const void *)smoothstep, TE_FUNCTION1},
288 {"half_smoothstep", (const void *)half_smoothstep, TE_FUNCTION1},
289 {"deg2rad", (const void *)deg2rad, TE_FUNCTION1},
290 {"rotate_2D_x", (const void *)rotate_2D_x, TE_FUNCTION3},
291 {"rotate_2D_y", (const void *)rotate_2D_y, TE_FUNCTION3},
292 {"if", (const void *)iflargerthanzerothenelse, TE_FUNCTION3},
293 {"compare", (const void *)compare, TE_FUNCTION2},
294 {"smooth_abs", (const void *)smooth_abs, TE_FUNCTION2},
295 {"sign", (const void *)sign, TE_FUNCTION1},
296 };
297
298 int err;
299 te_expr *tmp = te_compile(expr_.c_str(), vars.data(), vars.size(), &err);
300 assert(tmp != nullptr);
301 result = te_eval(tmp);
302 te_free(tmp);
303 }
304
305 if (!unit_.base_units().empty())
306 {
307 if (!unit_.is_convertible(unit_type_))
308 log_and_throw_error(fmt::format("Cannot convert {} to {}", units::to_string(unit_), units::to_string(unit_type_)));
309
310 result = units::convert(result, unit_, unit_type_);
311 }
312
313 return result;
314 }
315 } // namespace utils
316} // namespace polyfem
double val
Definition Assembler.cpp:86
ElementAssemblyValues vals
Definition Assembler.cpp:22
int y
int z
int x
std::vector< ExpressionValue > mat_expr_
std::function< double(double x, double y, double z, double t, int index)> sfunc_
std::function< Eigen::MatrixXd(double x, double y, double z, double t)> tfunc_
std::map< double, int > t_index_
double operator()(double x, double y, double z=0, double t=0, int index=-1) const
bool read_matrix(const std::string &path, Eigen::Matrix< T, Eigen::Dynamic, Eigen::Dynamic > &mat)
Reads a matrix from a file. Determines the file format based on the path's extension.
Definition MatrixIO.cpp:18
spdlog::logger & logger()
Retrieves the current logger.
Definition Logger.cpp:42
nlohmann::json json
Definition Common.hpp:9
void log_and_throw_error(const std::string &msg)
Definition Logger.cpp:71