Skip to content

Commit

Permalink
Use parser for input parameters of type long
Browse files Browse the repository at this point in the history
  • Loading branch information
NeilZaim committed Oct 27, 2021
1 parent 0af988b commit 9573bb3
Show file tree
Hide file tree
Showing 4 changed files with 144 additions and 135 deletions.
2 changes: 1 addition & 1 deletion Source/Initialization/PlasmaInjector.cpp
Expand Up @@ -199,7 +199,7 @@ PlasmaInjector::PlasmaInjector (int ispecies, const std::string& name)
queryWithParser(pp_species_name, "y_cut", y_cut);
queryWithParser(pp_species_name, "z_cut", z_cut);
getWithParser(pp_species_name, "q_tot", q_tot);
pp_species_name.get("npart", npart);
getWithParser(pp_species_name, "npart", npart);
pp_species_name.query("do_symmetrize", do_symmetrize);
gaussian_beam = true;
parseMomentum(pp_species_name);
Expand Down
2 changes: 1 addition & 1 deletion Source/Particles/LaserParticleContainer.cpp
Expand Up @@ -113,7 +113,7 @@ LaserParticleContainer::LaserParticleContainer (AmrCore* amr_core, int ispecies,
);

pp_laser_name.query("do_continuous_injection", do_continuous_injection);
pp_laser_name.query("min_particles_per_mode", m_min_particles_per_mode);
queryWithParser(pp_laser_name, "min_particles_per_mode", m_min_particles_per_mode);

if (m_e_max == amrex::Real(0.)){
WarpX::GetInstance().RecordWarning("Laser",
Expand Down
213 changes: 142 additions & 71 deletions Source/Utils/WarpXUtil.H
Expand Up @@ -197,16 +197,110 @@ void getCellCoordinates (int i, int j, int k,

}

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;
}

}

/**
* \brief Do a safe cast of a real to an int
* \brief Do a safe cast of a real to an int or a long
* This ensures that the float value is within the range of ints and if not,
* raises an exception.
*
* \tparam int_type the integer type that we cast into, either int or long (int by default).
* \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);
template <typename int_type = int>
int_type safeCastToInt (amrex::Real x, const std::string& real_name)
{
int_type result = 0;
bool error_detected = false;
std::string assert_msg;
// (2.0*(numeric_limits<int_type>::max()/2+1)) converts numeric_limits<int_type>::max()+1 to a
// real ensuring accuracy to all digits/
// For int_type = int, this accepts x = 2**31-1 but rejects 2**31.
if (x < (2.0*(std::numeric_limits<int_type>::max()/2+1))) {
if (std::ceil(x) >= std::numeric_limits<int_type>::min()) {
result = static_cast<int_type>(x);
} else {
error_detected = true;
assert_msg = "Error: Negative overflow detected when casting " + real_name + " = " +
std::to_string(x) + " to int";
}
} else if (x > 0) {
error_detected = true;
assert_msg = "Error: Overflow detected when casting " + real_name + " = " +
std::to_string(x) + " to int";
} else {
error_detected = true;
assert_msg = "Error: NaN detected when casting " + real_name + " to int";
}
WarpXUtilMsg::AlwaysAssert(!error_detected, assert_msg);
return result;
}

/**
* \brief Initialize an amrex::Parser object from a string containing a math expression
Expand Down Expand Up @@ -268,10 +362,35 @@ int queryWithParser (const amrex::ParmParse& a_pp, char const * const str, doubl
int queryArrWithParser (const amrex::ParmParse& a_pp, char const * const str, std::vector<amrex::Real>& val,
const int start_ix = amrex::ParmParse::FIRST,
const int num_val = amrex::ParmParse::LAST);
int queryWithParser (const amrex::ParmParse& a_pp, char const * const str, int& val);
int queryArrWithParser (const amrex::ParmParse& a_pp, char const * const str, std::vector<int>& val,

// Integer verions are templated so that we can parse both int and long input parameters
template <typename int_type>
int queryWithParser (const amrex::ParmParse& a_pp, char const * const str, int_type& val)
{
amrex::Real rval;
const int result = queryWithParser(a_pp, str, rval);
if (result) {
val = safeCastToInt(std::round(rval), str);
}
return result;
}

template <typename int_type>
int queryArrWithParser (const amrex::ParmParse& a_pp, char const * const str,
std::vector<int_type>& val,
const int start_ix = amrex::ParmParse::FIRST,
const int num_val = amrex::ParmParse::LAST);
const int num_val = amrex::ParmParse::LAST)
{
std::vector<amrex::Real> rval;
const int result = queryArrWithParser(a_pp, str, rval, start_ix, num_val);
if (result) {
val.resize(rval.size());
for (unsigned long i = 0 ; i < val.size() ; i++) {
val[i] = safeCastToInt(std::round(rval[i]), str);
}
}
return result;
}

/**
* \brief Similar to amrex::ParmParse::get, but also supports math expressions for the value.
Expand All @@ -294,76 +413,28 @@ void getWithParser (const amrex::ParmParse& a_pp, char const * const str, double
void getArrWithParser (const amrex::ParmParse& a_pp, char const * const str, std::vector<amrex::Real>& val,
const int start_ix = amrex::ParmParse::FIRST,
const int num_val = amrex::ParmParse::LAST);
void getWithParser (const amrex::ParmParse& a_pp, char const * const str, int& val);
void getArrWithParser (const amrex::ParmParse& a_pp, char const * const str, std::vector<int>& val,
const int start_ix = amrex::ParmParse::FIRST,
const int num_val = amrex::ParmParse::LAST);

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);

// Integer verions are templated so that we can parse both int and long input parameters
template <typename int_type>
void getWithParser (const amrex::ParmParse& a_pp, char const * const str, int_type& val)
{
amrex::Real rval;
getWithParser(a_pp, str, rval);
val = safeCastToInt(std::round(rval), str);
}

namespace WarpXUtilStr
template <typename int_type>
void getArrWithParser (const amrex::ParmParse& a_pp, char const * const str,
std::vector<int_type>& val,
const int start_ix = amrex::ParmParse::FIRST,
const int num_val = amrex::ParmParse::LAST)
{
/** 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;
std::vector<amrex::Real> rval;
getArrWithParser(a_pp, str, rval, start_ix, num_val);
val.resize(rval.size());
for (unsigned long i = 0 ; i < val.size() ; i++) {
val[i] = safeCastToInt(std::round(rval[i]), str);
}

}

#endif //WARPX_UTILS_H_
62 changes: 0 additions & 62 deletions Source/Utils/WarpXUtil.cpp
Expand Up @@ -271,30 +271,6 @@ void Store_parserString(const amrex::ParmParse& pp, std::string query_string,
f.clear();
}

int safeCastToInt(const amrex::Real x, const std::string& real_name) {
int result = 0;
bool error_detected = false;
std::string assert_msg;
// (2.0*(numeric_limits<int>::max()/2+1)) converts numeric_limits<int>::max()+1 to a real ensuring accuracy to all digits
// This accepts x = 2**31-1 but rejects 2**31.
if (x < (2.0*(std::numeric_limits<int>::max()/2+1))) {
if (std::ceil(x) >= std::numeric_limits<int>::min()) {
result = static_cast<int>(x);
} else {
error_detected = true;
assert_msg = "Error: Negative overflow detected when casting " + real_name + " = " + std::to_string(x) + " to int";
}
} else if (x > 0) {
error_detected = true;
assert_msg = "Error: Overflow detected when casting " + real_name + " = " + std::to_string(x) + " to int";
} else {
error_detected = true;
assert_msg = "Error: NaN detected when casting " + real_name + " to int";
}
WarpXUtilMsg::AlwaysAssert(!error_detected, assert_msg);
return result;
}

Parser makeParser (std::string const& parse_function, amrex::Vector<std::string> const& varnames)
{
// Since queryWithParser recursively calls this routine, keep track of symbols
Expand Down Expand Up @@ -469,44 +445,6 @@ getArrWithParser (const amrex::ParmParse& a_pp, char const * const str, std::vec
}
}

int queryWithParser (const amrex::ParmParse& a_pp, char const * const str, int& val) {
amrex::Real rval;
const int result = queryWithParser(a_pp, str, rval);
if (result) {
val = safeCastToInt(std::round(rval), str);
}
return result;
}

void getWithParser (const amrex::ParmParse& a_pp, char const * const str, int& val) {
amrex::Real rval;
getWithParser(a_pp, str, rval);
val = safeCastToInt(std::round(rval), str);
}

int queryArrWithParser (const amrex::ParmParse& a_pp, char const * const str, std::vector<int>& val,
const int start_ix, const int num_val) {
std::vector<amrex::Real> rval;
const int result = queryArrWithParser(a_pp, str, rval, start_ix, num_val);
if (result) {
val.resize(rval.size());
for (unsigned long i = 0 ; i < val.size() ; i++) {
val[i] = safeCastToInt(std::round(rval[i]), str);
}
}
return result;
}

void getArrWithParser (const amrex::ParmParse& a_pp, char const * const str, std::vector<int>& val,
const int start_ix, const int num_val) {
std::vector<amrex::Real> rval;
getArrWithParser(a_pp, str, rval, start_ix, num_val);
val.resize(rval.size());
for (unsigned long i = 0 ; i < val.size() ; i++) {
val[i] = safeCastToInt(std::round(rval[i]), str);
}
}

/**
* \brief Ensures that the blocks are setup correctly for the RZ spectral solver
* When using the RZ spectral solver, the Hankel transform cannot be
Expand Down

0 comments on commit 9573bb3

Please sign in to comment.