Block-Structured AMR Software Framework
Loading...
Searching...
No Matches
AMReX_Parser.H
Go to the documentation of this file.
1#ifndef AMREX_PARSER_H_
2#define AMREX_PARSER_H_
3
9#include <AMReX_Arena.H>
10#include <AMReX_Array.H>
11#include <AMReX_GpuDevice.H>
12#include <AMReX_Parser_Exe.H>
13#include <AMReX_REAL.H>
14#include <AMReX_Vector.H>
15
16#include <map>
17#include <memory>
18#include <string>
19#include <set>
20#include <utility>
21
22namespace amrex {
23
34template <int N>
36{
44 template <int M=N, std::enable_if_t<M==0,int> = 0>
46 double operator() () const noexcept
47 {
48 AMREX_IF_ON_DEVICE((return parser_exe_eval(m_device_executor, nullptr);))
49 AMREX_IF_ON_HOST((return parser_exe_eval(m_host_executor, nullptr);))
50 }
51
58 template <typename... Ts>
60 std::enable_if_t<sizeof...(Ts) == N && !amrex::Same<float,Ts...>::value, double>
61 operator() (Ts... var) const noexcept
62 {
63 amrex::GpuArray<double,N> l_var{var...};
64 AMREX_IF_ON_DEVICE((return parser_exe_eval(m_device_executor, l_var.data());))
65 AMREX_IF_ON_HOST((return parser_exe_eval(m_host_executor, l_var.data());))
66 }
67
75 template <typename... Ts>
77 std::enable_if_t<sizeof...(Ts) == N && amrex::Same<float,Ts...>::value, float>
78 operator() (Ts... var) const noexcept
79 {
80 amrex::GpuArray<double,N> l_var{var...};
81 AMREX_IF_ON_DEVICE((return static_cast<float>(parser_exe_eval(m_device_executor, l_var.data()));))
82 AMREX_IF_ON_HOST((return static_cast<float>(parser_exe_eval(m_host_executor, l_var.data()));))
83 }
84
91 double operator() (GpuArray<double,N> const& var) const noexcept
92 {
93 AMREX_IF_ON_DEVICE((return parser_exe_eval(m_device_executor, var.data());))
94 AMREX_IF_ON_HOST((return parser_exe_eval(m_host_executor, var.data());))
95 }
96
101 explicit operator bool () const {
102 AMREX_IF_ON_DEVICE((return m_device_executor != nullptr;))
103 AMREX_IF_ON_HOST((return m_host_executor != nullptr;))
104 }
105
106 char* m_host_executor = nullptr;
107#ifdef AMREX_USE_GPU
108 char* m_device_executor = nullptr;
109#endif
110};
111
113
122{
123public:
128 Parser (std::string const& func_body);
130 Parser () = default;
135 void define (std::string const& func_body);
136
138 explicit operator bool () const;
139
145 void setConstant (std::string const& name, double c);
146
154 void registerVariables (Vector<std::string> const& vars);
155
162 void registerUserFn1 (std::string const& name, ParserUserFn1 fh, ParserUserFn1 fd);
169 void registerUserFn2 (std::string const& name, ParserUserFn2 fh, ParserUserFn2 fd);
176 void registerUserFn3 (std::string const& name, ParserUserFn3 fh, ParserUserFn3 fd);
183 void registerUserFn4 (std::string const& name, ParserUserFn4 fh, ParserUserFn4 fd);
184
186 void print () const;
188 void printExe () const;
189
194 [[nodiscard]] int depth () const;
199 [[nodiscard]] int maxStackSize () const;
200
205 [[nodiscard]] std::string expr () const;
206
211 [[nodiscard]] std::set<std::string> symbols () const;
212
217 [[nodiscard]] std::map<std::string,int> const& userFunctions () const;
218
224 template <int N> [[nodiscard]] ParserExecutor<N> compile () const;
225
231 template <int N> [[nodiscard]] ParserExecutor<N> compileHost () const;
232
233private:
234
235 template <int argc, typename F>
236 void register_user_fn (std::string const& name, F fh, F fd);
237
239 struct Data {
240 std::string m_expression;
241 struct amrex_parser* m_parser = nullptr;
242 int m_nvars = 0;
243 bool m_use_arena = true;
244 char* m_host_executor = nullptr;
245#ifdef AMREX_USE_GPU
246 char* m_device_executor = nullptr;
247#endif
248 int m_max_stack_size = 0;
249 int m_exe_size = 0;
250 Vector<char const*> m_locals;
251 Data () = default;
252 ~Data ();
253 Data (Data const&) = delete;
254 Data (Data &&) = delete;
255 Data& operator= (Data const&) = delete;
256 Data& operator= (Data &&) = delete;
257 };
259
260 std::shared_ptr<Data> m_data;
261 std::map<std::string,int> m_ufs;
262 std::map<std::string,std::pair<void*,void*>> m_uf_ptrs;
263 Vector<std::string> m_vars;
264};
265
266template <int N>
267ParserExecutor<N>
269{
270 if (m_data && m_data->m_parser) {
271 AMREX_ALWAYS_ASSERT(N == m_data->m_nvars);
272
273 // Make sure all user functions have been registered.
274 for (auto const& [ufname, nargs] : m_ufs) {
275 if (m_uf_ptrs.find(ufname) == m_uf_ptrs.cend()) {
276 amrex::Abort("amrex::Parser: Unknown user function "+ufname
277 + " in " + m_data->m_expression);
278 }
280 }
281
282 if (!(m_data->m_host_executor)) {
283 int stack_size;
284 m_data->m_exe_size = static_cast<int>
285 (parser_exe_size(m_data->m_parser, m_data->m_max_stack_size,
286 stack_size));
287
288 if (m_data->m_max_stack_size > AMREX_PARSER_STACK_SIZE) {
289 amrex::Abort("amrex::Parser: AMREX_PARSER_STACK_SIZE, "
290 + std::to_string(AMREX_PARSER_STACK_SIZE) + ", is too small for "
291 + m_data->m_expression);
292 }
293 if (stack_size != 0) {
294 amrex::Abort("amrex::Parser: something went wrong with parser stack! "
295 + std::to_string(stack_size));
296 }
297
298 m_data->m_host_executor = (char*)The_Pinned_Arena()->alloc(m_data->m_exe_size);
299 if (m_data->m_host_executor == nullptr) { // Arena is not ready yet
300 m_data->m_host_executor = (char*) std::malloc(m_data->m_exe_size);
301 m_data->m_use_arena = false;
302 }
303
304 try {
305 m_data->m_locals = parser_compile(m_data->m_parser, m_uf_ptrs,
306 m_data->m_host_executor);
307 } catch (const std::runtime_error& e) {
308 throw std::runtime_error(std::string(e.what()) + " in Parser expression \""
309 + m_data->m_expression + "\"");
310 }
311 }
312
313#ifdef AMREX_USE_GPU
314 return ParserExecutor<N>{m_data->m_host_executor, m_data->m_device_executor};
315#else
316 return ParserExecutor<N>{m_data->m_host_executor};
317#endif
318 } else {
319 return ParserExecutor<N>{};
320 }
321}
322
323template <int N>
326{
327 auto exe = compileHost<N>();
328
329#ifdef AMREX_USE_GPU
330 if (m_data && m_data->m_parser && !(m_data->m_device_executor)
331 && m_data->m_use_arena)
332 {
333 m_data->m_device_executor = (char*)The_Arena()->alloc(m_data->m_exe_size);
334 Gpu::htod_memcpy_async(m_data->m_device_executor, m_data->m_host_executor,
335 m_data->m_exe_size);
337 exe.m_device_executor = m_data->m_device_executor;
338 }
339#endif
340
341 return exe;
342}
343
344template <int argc, typename F>
345void
346Parser::register_user_fn (std::string const& name, F fh, F fd)
347{
348#if !defined(AMREX_USE_GPU)
349 // For pure CPU builds, we allow the user to pass the function pointer with either fh or fd
350 if (fh == nullptr) { std::swap(fh, fd); }
351#endif
352
353 auto it = m_ufs.find(name);
354 if (it != m_ufs.end()) {
355 if (it->second == argc) {
356 m_uf_ptrs[name] = std::make_pair((void*)fh, (void*)fd);
357 } else {
358 amrex::Abort("Parser::registerUserFn: incorrect no. of arguments in "+name);
359 }
360 } else {
361 amrex::Abort("Parser::registerUserFn: unknown user define function "+name);
362 }
363}
364
365}
366
367#endif
#define AMREX_ALWAYS_ASSERT(EX)
Definition AMReX_BLassert.H:50
#define AMREX_FORCE_INLINE
Definition AMReX_Extension.H:119
#define AMREX_IF_ON_DEVICE(CODE)
Definition AMReX_GpuQualifiers.H:56
#define AMREX_IF_ON_HOST(CODE)
Definition AMReX_GpuQualifiers.H:58
#define AMREX_GPU_HOST_DEVICE
Definition AMReX_GpuQualifiers.H:20
virtual void * alloc(std::size_t sz)=0
Front-end for parsing scalar expressions into GPU/CPU executors.
Definition AMReX_Parser.H:122
std::set< std::string > symbols() const
Return the set of symbols (variables and functions) referenced by the expression.
Definition AMReX_Parser.cpp:150
void registerUserFn3(std::string const &name, ParserUserFn3 fh, ParserUserFn3 fd)
Register a user-defined ternary function.
Definition AMReX_Parser.cpp:100
void registerUserFn1(std::string const &name, ParserUserFn1 fh, ParserUserFn1 fd)
Register a user-defined unary function available to expressions.
Definition AMReX_Parser.cpp:88
void print() const
Print a human-readable representation of the parser tree to stdout.
Definition AMReX_Parser.cpp:112
int maxStackSize() const
Return the maximum stack usage recorded during compilation.
Definition AMReX_Parser.cpp:130
ParserExecutor< N > compileHost() const
Compile the current expression into a host-only executor.
Definition AMReX_Parser.H:268
void registerUserFn4(std::string const &name, ParserUserFn4 fh, ParserUserFn4 fd)
Register a user-defined function with four arguments.
Definition AMReX_Parser.cpp:106
std::string expr() const
Return the sanitized expression string currently managed by the Parser.
Definition AMReX_Parser.cpp:140
void define(std::string const &func_body)
Parse and own a new expression, replacing any previous state.
Definition AMReX_Parser.cpp:18
ParserExecutor< N > compile() const
Compile the current expression into a host/device executor.
Definition AMReX_Parser.H:325
Parser()=default
Default-construct; call define() before compilation.
void printExe() const
Dump the compiled bytecode to stdout for debugging.
Definition AMReX_Parser.cpp:166
void setConstant(std::string const &name, double c)
Bind a named constant to c.
Definition AMReX_Parser.cpp:68
void registerVariables(Vector< std::string > const &vars)
Register the ordered list of variable names used by the expression.
Definition AMReX_Parser.cpp:76
std::map< std::string, int > const & userFunctions() const
Access the map of registered user-defined functions.
Definition AMReX_Parser.cpp:160
int depth() const
Return the maximum tree depth of the parsed expression.
Definition AMReX_Parser.cpp:120
void registerUserFn2(std::string const &name, ParserUserFn2 fh, ParserUserFn2 fd)
Register a user-defined binary function.
Definition AMReX_Parser.cpp:94
This class is a thin wrapper around std::vector. Unlike vector, Vector::operator[] provides bound che...
Definition AMReX_Vector.H:28
Arena * The_Pinned_Arena()
Definition AMReX_Arena.cpp:845
Arena * The_Arena()
Definition AMReX_Arena.cpp:805
void streamSynchronize() noexcept
Definition AMReX_GpuDevice.H:310
void htod_memcpy_async(void *p_d, const void *p_h, const std::size_t sz) noexcept
Definition AMReX_GpuDevice.H:421
Definition AMReX_Amr.cpp:49
__host__ __device__ void ignore_unused(const Ts &...)
This shuts up the compiler about unused variables.
Definition AMReX.H:139
void Abort(const std::string &msg)
Print out message to cerr and exit via abort().
Definition AMReX.cpp:240
Fixed-size array that can be used on GPU.
Definition AMReX_Array.H:43
Callable wrapper around a compiled parser expression with N variables.
Definition AMReX_Parser.H:36
char * m_host_executor
Pointer to host-visible bytecode.
Definition AMReX_Parser.H:106
__host__ __device__ double operator()() const noexcept
Evaluate the expression with no arguments.
Definition AMReX_Parser.H:46
char * m_device_executor
Pointer to device-visible bytecode (if copied).
Definition AMReX_Parser.H:108
Definition AMReX_TypeTraits.H:138