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
4#include <AMReX_Arena.H>
5#include <AMReX_Array.H>
6#include <AMReX_GpuDevice.H>
7#include <AMReX_Parser_Exe.H>
8#include <AMReX_REAL.H>
9#include <AMReX_Vector.H>
10
11#include <map>
12#include <memory>
13#include <string>
14#include <set>
15#include <utility>
16
17namespace amrex {
18
19template <int N>
21{
22 template <int M=N, std::enable_if_t<M==0,int> = 0>
24 double operator() () const noexcept
25 {
26 AMREX_IF_ON_DEVICE((return parser_exe_eval(m_device_executor, nullptr);))
27 AMREX_IF_ON_HOST((return parser_exe_eval(m_host_executor, nullptr);))
28 }
29
30 template <typename... Ts>
32 std::enable_if_t<sizeof...(Ts) == N && !amrex::Same<float,Ts...>::value, double>
33 operator() (Ts... var) const noexcept
34 {
35 amrex::GpuArray<double,N> l_var{var...};
36 AMREX_IF_ON_DEVICE((return parser_exe_eval(m_device_executor, l_var.data());))
37 AMREX_IF_ON_HOST((return parser_exe_eval(m_host_executor, l_var.data());))
38 }
39
40 template <typename... Ts>
42 std::enable_if_t<sizeof...(Ts) == N && amrex::Same<float,Ts...>::value, float>
43 operator() (Ts... var) const noexcept
44 {
45 amrex::GpuArray<double,N> l_var{var...};
46 AMREX_IF_ON_DEVICE((return static_cast<float>(parser_exe_eval(m_device_executor, l_var.data()));))
47 AMREX_IF_ON_HOST((return static_cast<float>(parser_exe_eval(m_host_executor, l_var.data()));))
48 }
49
51 double operator() (GpuArray<double,N> const& var) const noexcept
52 {
53 AMREX_IF_ON_DEVICE((return parser_exe_eval(m_device_executor, var.data());))
54 AMREX_IF_ON_HOST((return parser_exe_eval(m_host_executor, var.data());))
55 }
56
58 explicit operator bool () const {
59 AMREX_IF_ON_DEVICE((return m_device_executor != nullptr;))
60 AMREX_IF_ON_HOST((return m_host_executor != nullptr;))
61 }
62
63 char* m_host_executor = nullptr;
64#ifdef AMREX_USE_GPU
65 char* m_device_executor = nullptr;
66#endif
67};
68
70class Parser
71{
72public:
73 Parser (std::string const& func_body);
74 Parser () = default;
75 void define (std::string const& func_body);
76
77 explicit operator bool () const;
78
79 void setConstant (std::string const& name, double c);
80
81 void registerVariables (Vector<std::string> const& vars);
82
84 void registerUserFn1 (std::string const& name, ParserUserFn1 fh, ParserUserFn1 fd);
86 void registerUserFn2 (std::string const& name, ParserUserFn2 fh, ParserUserFn2 fd);
88 void registerUserFn3 (std::string const& name, ParserUserFn3 fh, ParserUserFn3 fd);
90 void registerUserFn4 (std::string const& name, ParserUserFn4 fh, ParserUserFn4 fd);
91
92 void print () const;
93 void printExe () const;
94
95 [[nodiscard]] int depth () const;
96 [[nodiscard]] int maxStackSize () const;
97
98 [[nodiscard]] std::string expr () const;
99
100 [[nodiscard]] std::set<std::string> symbols () const;
101
103 [[nodiscard]] std::map<std::string,int> const& userFunctions () const;
104
106 template <int N> [[nodiscard]] ParserExecutor<N> compile () const;
107
109 template <int N> [[nodiscard]] ParserExecutor<N> compileHost () const;
110
111private:
112
113 template <int argc, typename F>
114 void register_user_fn (std::string const& name, F fh, F fd);
115
117 struct Data {
118 std::string m_expression;
119 struct amrex_parser* m_parser = nullptr;
120 int m_nvars = 0;
121 bool m_use_arena = true;
122 char* m_host_executor = nullptr;
123#ifdef AMREX_USE_GPU
124 char* m_device_executor = nullptr;
125#endif
126 int m_max_stack_size = 0;
127 int m_exe_size = 0;
128 Vector<char const*> m_locals;
129 Data () = default;
130 ~Data ();
131 Data (Data const&) = delete;
132 Data (Data &&) = delete;
133 Data& operator= (Data const&) = delete;
134 Data& operator= (Data &&) = delete;
135 };
137
138 std::shared_ptr<Data> m_data;
139 std::map<std::string,int> m_ufs;
140 std::map<std::string,std::pair<void*,void*>> m_uf_ptrs;
141 Vector<std::string> m_vars;
142};
143
144template <int N>
145ParserExecutor<N>
147{
148 if (m_data && m_data->m_parser) {
149 AMREX_ALWAYS_ASSERT(N == m_data->m_nvars);
150
151 // Make sure all user functions have been registered.
152 for (auto const& [ufname, nargs] : m_ufs) {
153 if (m_uf_ptrs.find(ufname) == m_uf_ptrs.cend()) {
154 amrex::Abort("amrex::Parser: Unknown user function "+ufname
155 + " in " + m_data->m_expression);
156 }
158 }
159
160 if (!(m_data->m_host_executor)) {
161 int stack_size;
162 m_data->m_exe_size = static_cast<int>
163 (parser_exe_size(m_data->m_parser, m_data->m_max_stack_size,
164 stack_size));
165
166 if (m_data->m_max_stack_size > AMREX_PARSER_STACK_SIZE) {
167 amrex::Abort("amrex::Parser: AMREX_PARSER_STACK_SIZE, "
168 + std::to_string(AMREX_PARSER_STACK_SIZE) + ", is too small for "
169 + m_data->m_expression);
170 }
171 if (stack_size != 0) {
172 amrex::Abort("amrex::Parser: something went wrong with parser stack! "
173 + std::to_string(stack_size));
174 }
175
176 m_data->m_host_executor = (char*)The_Pinned_Arena()->alloc(m_data->m_exe_size);
177 if (m_data->m_host_executor == nullptr) { // Arena is not ready yet
178 m_data->m_host_executor = (char*) std::malloc(m_data->m_exe_size);
179 m_data->m_use_arena = false;
180 }
181
182 try {
183 m_data->m_locals = parser_compile(m_data->m_parser, m_uf_ptrs,
184 m_data->m_host_executor);
185 } catch (const std::runtime_error& e) {
186 throw std::runtime_error(std::string(e.what()) + " in Parser expression \""
187 + m_data->m_expression + "\"");
188 }
189 }
190
191#ifdef AMREX_USE_GPU
192 return ParserExecutor<N>{m_data->m_host_executor, m_data->m_device_executor};
193#else
194 return ParserExecutor<N>{m_data->m_host_executor};
195#endif
196 } else {
197 return ParserExecutor<N>{};
198 }
199}
200
201template <int N>
204{
205 auto exe = compileHost<N>();
206
207#ifdef AMREX_USE_GPU
208 if (m_data && m_data->m_parser && !(m_data->m_device_executor)
209 && m_data->m_use_arena)
210 {
211 m_data->m_device_executor = (char*)The_Arena()->alloc(m_data->m_exe_size);
212 Gpu::htod_memcpy_async(m_data->m_device_executor, m_data->m_host_executor,
213 m_data->m_exe_size);
215 exe.m_device_executor = m_data->m_device_executor;
216 }
217#endif
218
219 return exe;
220}
221
222template <int argc, typename F>
223void
224Parser::register_user_fn (std::string const& name, F fh, F fd)
225{
226#if !defined(AMREX_USE_GPU)
227 // For pure CPU builds, we allow the user to pass the function pointer with either fh or fd
228 if (fh == nullptr) { std::swap(fh, fd); }
229#endif
230
231 auto it = m_ufs.find(name);
232 if (it != m_ufs.end()) {
233 if (it->second == argc) {
234 m_uf_ptrs[name] = std::make_pair((void*)fh, (void*)fd);
235 } else {
236 amrex::Abort("Parser::registerUserFn: incorrect no. of arguments in "+name);
237 }
238 } else {
239 amrex::Abort("Parser::registerUserFn: unknown user define function "+name);
240 }
241}
242
243}
244
245#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
Definition AMReX_Parser.H:71
std::set< std::string > symbols() const
Definition AMReX_Parser.cpp:150
void registerUserFn3(std::string const &name, ParserUserFn3 fh, ParserUserFn3 fd)
Register user defined host and functions with three arguments.
Definition AMReX_Parser.cpp:100
void registerUserFn1(std::string const &name, ParserUserFn1 fh, ParserUserFn1 fd)
Register user defined host and functions with one argument.
Definition AMReX_Parser.cpp:88
void print() const
Definition AMReX_Parser.cpp:112
int maxStackSize() const
Definition AMReX_Parser.cpp:130
ParserExecutor< N > compileHost() const
This compiles for CPU only.
Definition AMReX_Parser.H:146
void registerUserFn4(std::string const &name, ParserUserFn4 fh, ParserUserFn4 fd)
Register user defined host and functions with four arguments.
Definition AMReX_Parser.cpp:106
std::string expr() const
Definition AMReX_Parser.cpp:140
void define(std::string const &func_body)
Definition AMReX_Parser.cpp:18
ParserExecutor< N > compile() const
This compiles for both GPU and CPU.
Definition AMReX_Parser.H:203
Parser()=default
void printExe() const
Definition AMReX_Parser.cpp:166
void setConstant(std::string const &name, double c)
Definition AMReX_Parser.cpp:68
void registerVariables(Vector< std::string > const &vars)
Definition AMReX_Parser.cpp:76
std::map< std::string, int > const & userFunctions() const
User defined functions in std::map<name, # of args>
Definition AMReX_Parser.cpp:160
int depth() const
Definition AMReX_Parser.cpp:120
void registerUserFn2(std::string const &name, ParserUserFn2 fh, ParserUserFn2 fd)
Register user defined host and functions with two arguments.
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:823
Arena * The_Arena()
Definition AMReX_Arena.cpp:783
void streamSynchronize() noexcept
Definition AMReX_GpuDevice.H:263
void htod_memcpy_async(void *p_d, const void *p_h, const std::size_t sz) noexcept
Definition AMReX_GpuDevice.H:301
Definition AMReX_Amr.cpp:49
__host__ __device__ void ignore_unused(const Ts &...)
This shuts up the compiler about unused variables.
Definition AMReX.H:138
void Abort(const std::string &msg)
Print out message to cerr and exit via abort().
Definition AMReX.cpp:230
Fixed-size array that can be used on GPU.
Definition AMReX_Array.H:41
Definition AMReX_Parser.H:21
char * m_host_executor
Definition AMReX_Parser.H:63
__host__ __device__ double operator()() const noexcept
Definition AMReX_Parser.H:24
char * m_device_executor
Definition AMReX_Parser.H:65
Definition AMReX_TypeTraits.H:138