1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
|
/* Copyright 2022 Andrew Myers, Burlen Loring, Luca Fedeli
* Maxence Thevenet, Remi Lehe, Revathi Jambunathan
*
* This file is part of WarpX.
*
* License: BSD-3-Clause-LBNL
*/
#ifndef WARPX_UTILS_PARSER_PARSERUTILS_H_
#define WARPX_UTILS_PARSER_PARSERUTILS_H_
#include <AMReX_ParmParse.H>
#include <AMReX_Parser.H>
#include <AMReX_REAL.H>
#include <AMReX_Vector.H>
#include <cmath>
#include <string>
#include <type_traits>
namespace utils::parser
{
/**
* \brief Do a safe cast of a real to an int
* This ensures that the float value is within the range of ints and if not,
* raises an exception.
*
* \param x Real value to cast
* \param real_name String, the name of the variable being casted to use in the error message
*/
int
safeCastToInt(amrex::Real x, const std::string& real_name);
/**
* \brief Do a safe cast of a real to a long
* This ensures that the float value is within the range of longs and if not,
* raises an exception.
*
* \param x Real value to cast
* \param real_name String, the name of the variable being casted to use in the error message
*/
long
safeCastToLong(amrex::Real x, const std::string& real_name);
/**
* \brief Initialize an amrex::Parser object from a string containing a math expression
*
* \param parse_function String to read to initialize the parser.
* \param varnames A list of predefined independent variables
*/
amrex::Parser makeParser (
std::string const& parse_function,
amrex::Vector<std::string> const& varnames);
/**
* \brief Parse a string (typically a mathematical expression) from the
* input file and store it into a variable.
*
* \param pp used to read the query_string `pp.<function>=string`
* \param query_string ParmParse.query will look for this string
* \param stored_string variable in which the string to parse is stored
*/
void Store_parserString(
const amrex::ParmParse &pp,
std::string query_string,
std::string& stored_string);
/** Parse a string and return as a double precision floating point number
*
* In case the string cannot be interpreted as a double,
* this function ... <throws an exception? aborts with error message?>
*
* \param str The string to be parsed
* \return representation as a double
*/
double parseStringtoDouble(const std::string& str);
/** Parse a string and return an int
*
* In case the string cannot be interpreted as Real,
* this function ... <throws an exception? aborts with error message?>
*
* \param str The string to be parsed
* \param name For integers, the name, to be used in error messages
* \return rounded closest integer
*/
int parseStringtoInt(const std::string& str, const std::string& name);
template <int N>
amrex::ParserExecutor<N> compileParser (amrex::Parser const* parser)
{
if (parser) {
return parser->compile<N>();
} else {
return amrex::ParserExecutor<N>{};
}
}
/** Similar to amrex::ParmParse::query, but also supports math expressions for the value.
*
* amrex::ParmParse::query reads a name and a value from the input file. This function does the
* same, and applies the amrex::Parser to the value, so the user has the choice to specify a value or
* a math expression (including user-defined constants).
* Works for amrex::Real numbers and integers.
*
* \param[in] a_pp amrex::ParmParse object
* \param[in] str name of the parameter to read
* \param[out] val where the value queried and parsed is stored, either a scalar or vector
*/
template <typename T>
int queryWithParser (const amrex::ParmParse& a_pp, char const * const str, T& val)
{
// call amrex::ParmParse::query, check if the user specified str.
std::string tmp_str;
int is_specified = a_pp.query(str, tmp_str);
if (is_specified)
{
// If so, create a parser object and apply it to the value provided by the user.
std::string str_val;
Store_parserString(a_pp, str, str_val);
auto parser = makeParser(str_val, {});
if (std::is_same<T, int>::value) {
val = safeCastToInt(std::round(parser.compileHost<0>()()), str);
}
else {
val = static_cast<T>(parser.compileHost<0>()());
}
}
// return the same output as amrex::ParmParse::query
return is_specified;
}
template <typename T>
int queryArrWithParser (const amrex::ParmParse& a_pp, char const * const str, std::vector<T>& val)
{
// call amrex::ParmParse::query, check if the user specified str.
std::vector<std::string> tmp_str_arr;
int is_specified = a_pp.queryarr(str, tmp_str_arr);
if (is_specified)
{
// If so, create parser objects and apply them to the values provided by the user.
int const n = static_cast<int>(tmp_str_arr.size());
val.resize(n);
for (int i=0 ; i < n ; i++) {
auto parser = makeParser(tmp_str_arr[i], {});
if (std::is_same<T, int>::value) {
val[i] = safeCastToInt(std::round(parser.compileHost<0>()()), str);
}
else {
val[i] = static_cast<T>(parser.compileHost<0>()());
}
}
}
// return the same output as amrex::ParmParse::query
return is_specified;
}
/** Similar to amrex::ParmParse::query, but also supports math expressions for the value.
*
* amrex::ParmParse::query reads a name and a value from the input file. This function does the
* same, and applies the amrex::Parser to the value, so the user has the choice to specify a value or
* a math expression (including user-defined constants).
* Works for amrex::Real numbers and integers.
*
* \param[in] a_pp amrex::ParmParse object
* \param[in] str name of the parameter to read
* \param[out] val where the value queried and parsed is stored, either a scalar or vector
* \param[in] start_ix start index in the list of inputs values (optional with arrays, default is
* amrex::ParmParse::FIRST for starting with the first input value)
* \param[in] num_val number of input values to use (optional with arrays, default is
* amrex::ParmParse::LAST for reading until the last input value)
*/
template <typename T>
int queryArrWithParser (const amrex::ParmParse& a_pp, char const * const str, std::vector<T>& val,
const int start_ix, const int num_val)
{
// call amrex::ParmParse::query, check if the user specified str.
std::vector<std::string> tmp_str_arr;
int is_specified = a_pp.queryarr(str, tmp_str_arr, start_ix, num_val);
if (is_specified)
{
// If so, create parser objects and apply them to the values provided by the user.
int const n = static_cast<int>(tmp_str_arr.size());
val.resize(n);
for (int i=0 ; i < n ; i++) {
auto parser = makeParser(tmp_str_arr[i], {});
if (std::is_same<T, int>::value) {
val[i] = safeCastToInt(std::round(parser.compileHost<0>()()), str);
}
else {
val[i] = static_cast<T>(parser.compileHost<0>()());
}
}
}
// return the same output as amrex::ParmParse::query
return is_specified;
}
/** Similar to amrex::ParmParse::get, but also supports math expressions for the value.
*
* amrex::ParmParse::get reads a name and a value from the input file. This function does the
* same, and applies the Parser to the value, so the user has the choice to specify a value or
* a math expression (including user-defined constants).
* Works for amrex::Real numbers and integers.
*
* \param[in] a_pp amrex::ParmParse object
* \param[in] str name of the parameter to read
* \param[out] val where the value queried and parsed is stored
*/
template <typename T>
void getWithParser (const amrex::ParmParse& a_pp, char const * const str, T& val)
{
// If so, create a parser object and apply it to the value provided by the user.
std::string str_val;
Store_parserString(a_pp, str, str_val);
auto parser = makeParser(str_val, {});
if (std::is_same<T, int>::value) {
val = safeCastToInt(std::round(parser.compileHost<0>()()), str);
}
else {
val = static_cast<T>(parser.compileHost<0>()());
}
}
template <typename T>
void getArrWithParser (const amrex::ParmParse& a_pp, char const * const str, std::vector<T>& val)
{
// Create parser objects and apply them to the values provided by the user.
std::vector<std::string> tmp_str_arr;
a_pp.getarr(str, tmp_str_arr);
int const n = static_cast<int>(tmp_str_arr.size());
val.resize(n);
for (int i=0 ; i < n ; i++) {
auto parser = makeParser(tmp_str_arr[i], {});
if (std::is_same<T, int>::value) {
val[i] = safeCastToInt(std::round(parser.compileHost<0>()()), str);
}
else {
val[i] = static_cast<T>(parser.compileHost<0>()());
}
}
}
/** Similar to amrex::ParmParse::get, but also supports math expressions for the value.
*
* amrex::ParmParse::get reads a name and a value from the input file. This function does the
* same, and applies the Parser to the value, so the user has the choice to specify a value or
* a math expression (including user-defined constants).
* Works for amrex::Real numbers and integers.
*
* \param[in] a_pp amrex::ParmParse object
* \param[in] str name of the parameter to read
* \param[out] val where the value queried and parsed is stored
* \param[in] start_ix start index in the list of inputs values (optional with arrays, default is
* amrex::ParmParse::FIRST for starting with the first input value)
* \param[in] num_val number of input values to use (optional with arrays, default is
* amrex::ParmParse::LAST for reading until the last input value)
*/
template <typename T>
void getArrWithParser (const amrex::ParmParse& a_pp, char const * const str, std::vector<T>& val,
const int start_ix, const int num_val)
{
// Create parser objects and apply them to the values provided by the user.
std::vector<std::string> tmp_str_arr;
a_pp.getarr(str, tmp_str_arr, start_ix, num_val);
int const n = static_cast<int>(tmp_str_arr.size());
val.resize(n);
for (int i=0 ; i < n ; i++) {
auto parser = makeParser(tmp_str_arr[i], {});
if (std::is_same<T, int>::value) {
val[i] = safeCastToInt(std::round(parser.compileHost<0>()()), str);
}
else {
val[i] = static_cast<T>(parser.compileHost<0>()());
}
}
}
}
#endif // WARPX_UTILS_PARSER_PARSERUTILS_H_
|