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
|
/* Copyright 2019-2020 Andrew Myers, Luca Fedeli, Maxence Thevenet
* Revathi Jambunathan
*
* This file is part of WarpX.
*
* License: BSD-3-Clause-LBNL
*/
#ifndef WARPX_UTILS_H_
#define WARPX_UTILS_H_
#include "Parser/WarpXParser.H"
#include <AMReX_REAL.H>
#include <AMReX_Vector.H>
#include <AMReX_MultiFab.H>
#include <AMReX_ParmParse.H>
#include <AMReX_Utility.H>
#include <cstdint>
#include <string>
void ReadBoostedFrameParameters(amrex::Real& gamma_boost, amrex::Real& beta_boost,
amrex::Vector<int>& boost_direction);
void ConvertLabParamsToBoost();
/**
* Reads the user-defined field and particle boundary condition parameters
*/
void ReadBCParams ();
/**
* \brief Ensures that the blocks are setup correctly for the RZ spectral solver
*/
void CheckGriddingForRZSpectral();
void NullifyMF(amrex::MultiFab& mf, int lev, amrex::Real zmin,
amrex::Real zmax);
/**
* \brief Parse a string (typically a mathematical expression) from the
* input file and store it into a variable.
*
* \param ParmParse pp used to read the query_string pp.<function>=string
* \param parmparse_string String used to initialize ParmParse
* \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);
namespace WarpXUtilIO{
/**
* A helper function to write binary data on disk.
* @param[in] filename where to write
* @param[in] data Vector containing binary data to write on disk
* return true if it succeeds, false otherwise
*/
bool WriteBinaryDataOnFile(std::string filename, const amrex::Vector<char>& data);
/** A helper function to derive a globally unique particle ID
*
* @param[in] id AMReX particle ID (on local cpu/rank), AoS .id
* @param[in] cpu AMReX particle CPU (rank) at creation of the particle, AoS .cpu
* @return global particle ID that is unique and permanent in the whole simulation
*/
constexpr uint64_t
localIDtoGlobal(int const id, int const cpu)
{
static_assert(sizeof(int) * 2u <= sizeof(uint64_t),
"int size might cause collisions in global IDs");
// implementation:
// - we cast both 32-bit (or smaller) ints to a 64bit unsigned int
// - this will leave half of the "upper range" bits in the 64bit unsigned int zeroed out
// because the corresponding (extended) value range was not part of the value range in
// the int representation
// - we bit-shift the cpu into the upper half of zero bits in the 64 bit unsigned int
// (imagine this step as "adding a per-cpu/rank offset to the local integers")
// - then we add this offset
// note: the add is expressed as bitwise OR (|) since this saves us from writing
// brackets for operator precedence between + and <<
return uint64_t(id) | uint64_t(cpu) << 32u;
}
}
namespace WarpXUtilAlgo{
/** \brief Returns a pointer to the first element in the range [first, last) that is greater than val
*
* A re-implementation of the upper_bound algorithm suitable for GPU kernels.
*
* @param first: pointer to left limit of the range to consider
* @param last: pointer to right limit of the range to consider
* @param val: value to compare the elements of [first, last) to
*/
template<typename T> AMREX_GPU_DEVICE AMREX_FORCE_INLINE
const T* upper_bound(const T* first, const T* last, const T& val)
{
const T* it;
size_t count, step;
count = last-first;
while(count>0){
it = first;
step = count/2;
it += step;
if (!(val<*it)){
first = ++it;
count -= step + 1;
}
else{
count = step;
}
}
return first;
}
/** \brief Performs a linear interpolation
*
* Performs a linear interpolation at x given the 2 points
* (x0, f0) and (x1, f1)
*/
template<typename T> AMREX_GPU_DEVICE AMREX_FORCE_INLINE
T linear_interp(T x0, T x1, T f0, T f1, T x)
{
return ((x1-x)*f0 + (x-x0)*f1)/(x1-x0);
}
/** \brief Performs a bilinear interpolation
*
* Performs a bilinear interpolation at (x,y) given the 4 points
* (x0, y0, f00), (x0, y1, f01), (x1, y0, f10), (x1, y1, f11).
*/
template<typename T> AMREX_GPU_DEVICE AMREX_FORCE_INLINE
T bilinear_interp(T x0, T x1, T y0, T y1, T f00, T f01, T f10, T f11, T x, T y)
{
const T fx0 = linear_interp(x0, x1, f00, f10, x);
const T fx1 = linear_interp(x0, x1, f01, f11, x);
return linear_interp(y0, y1, fx0, fx1, y);
}
/** \brief Performs a trilinear interpolation
*
* Performs a trilinear interpolation at (x,y,z) given the 8 points
* (x0, y0, z0, f000), (x0, y0, z1, f001), (x0, y1, z0, f010), (x0, y1, z1, f011),
* (x1, y0, z0, f100), (x1, y0, z1, f101), (x1, y1, z0, f110), (x1, y1, z1, f111)
*/
template<typename T> AMREX_GPU_DEVICE AMREX_FORCE_INLINE
T trilinear_interp(T x0, T x1,T y0, T y1, T z0, T z1,
T f000, T f001, T f010, T f011, T f100, T f101, T f110, T f111,
T x, T y, T z)
{
const T fxy0 = bilinear_interp(
x0, x1, y0, y1, f000, f010, f100, f110, x, y);
const T fxy1 = bilinear_interp(
x0, x1, y0, y1, f001, f011, f101, f111, x, y);
return linear_interp(z0, z1, fxy0, fxy1, z);
}
}
/**
* \brief Initialize a WarpXParser object from a string containing a math expression
*
* \param parse_function String to read to initialize the parser.
*/
WarpXParser makeParser (std::string const& parse_function, std::vector<std::string> const& varnames);
/**
* \brief 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 WarpXParser to the value, so the user has the choice to specify a value or
* a math expression (including user-defined constants).
* Only works for amrex::Real numbers, one would need another version for integers etc.
*
* \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
*/
int queryWithParser (const amrex::ParmParse& a_pp, char const * const str, amrex::Real& val);
/**
* \brief 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 WarpXParser to the value, so the user has the choice to specify a value or
* a math expression (including user-defined constants).
* Only works for amrex::Real numbers, one would need another version for integers etc.
*
* \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
*/
void getWithParser (const amrex::ParmParse& a_pp, char const * const str, amrex::Real& val);
namespace WarpXUtilMsg{
/** \brief If is_expression_true is false, this function prints msg and calls amrex::abort()
*
* @param[in] is_expression_true
* @param[in] msg the string to be printed if is_expression_true is false (default value is "ERROR!")
*/
void AlwaysAssert(bool is_expression_true, const std::string& msg);
}
namespace WarpXUtilStr
{
/** Return true if elem is in vect, false otherwise
* @param[in] vect vector of strings, typically names
* @param[in] elem single string
* @return true if elem is in vect, false otherwise
*/
bool is_in(const std::vector<std::string>& vect,
const std::string& elem);
/** Return true if any element in elems is in vect, false otherwise
* @param[in] vect vector of strings, typically names
* @param[in] elems vector of string
* @return true if any element in elems is in vect, false otherwise
*/
bool is_in(const std::vector<std::string>& vect,
const std::vector<std::string>& elems);
/** \brief Splits a string using a string separator. This is somewhat similar to
* amrex::Tokenize. The main difference is that, if the separator ":" is used,
* amrex::Tokenize will split ":3::2" into ["3","2"] while this functio will
* split ":3::2" into ["","3","","2"]. This function can also perform a trimming to
* remove whitespaces (or any other arbitrary string) from the split string.
*
* @tparam Container the type of the split string.
*
* @param[in] instr the input string
* @param[in] separator the separator string
* @param[in] trim true to trim the split string, false otherwise.
* @param[in] trim_space the string to trim if trim is true.
* @return cont the split string
*/
template <typename Container>
auto split (std::string const& instr, std::string const& separator,
bool const trim = false, std::string const& trim_space = " \t")
{
Container cont;
std::size_t current = instr.find(separator);
std::size_t previous = 0;
while (current != std::string::npos) {
if (trim){
cont.push_back(amrex::trim(instr.substr(previous, current - previous),trim_space));}
else{
cont.push_back(instr.substr(previous, current - previous));}
previous = current + separator.size();
current = instr.find(separator, previous);
}
if (trim){
cont.push_back(amrex::trim(instr.substr(previous, current - previous),trim_space));}
else{
cont.push_back(instr.substr(previous, current - previous));}
return cont;
}
}
#endif //WARPX_UTILS_H_
|