Skip to content

Commit

Permalink
ParmParse::queryAsDouble: Support bool and std::optional (AMReX-Codes…
Browse files Browse the repository at this point in the history
…#4152)

This is needed in WarpX.
  • Loading branch information
WeiqunZhang authored Sep 17, 2024
1 parent dfe1747 commit 97fcea3
Show file tree
Hide file tree
Showing 3 changed files with 94 additions and 25 deletions.
103 changes: 78 additions & 25 deletions Src/Base/AMReX_ParmParse.H
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,11 @@

#include <array>
#include <iosfwd>
#include <unordered_map>
#include <optional>
#include <set>
#include <string>
#include <string_view>
#include <unordered_map>
#include <vector>

namespace amrex {
Expand All @@ -27,6 +28,32 @@ class IntVectND;
using IntVect = IntVectND<AMREX_SPACEDIM>;
class RealVect;

namespace ppdetail {
template <class T, class Enable = void>
struct ArithmeticOptional_TT : std::false_type {};

template <class T>
struct ArithmeticOptional_TT<T, std::enable_if_t<std::is_arithmetic_v<T>>>
: std::true_type
{
using value_type = T;
};

template <class T>
struct ArithmeticOptional_TT<std::optional<T>,
std::enable_if_t<std::is_arithmetic_v<T>>>
: std::true_type
{
using value_type = T;
};

template <class T>
inline constexpr bool IsArithmeticOptional_v = ArithmeticOptional_TT<T>::value;

template <class T>
using underlying_type_t = typename ArithmeticOptional_TT<T>::value_type;
}

//
// ParmParse class implements a simple database for the storage and
// retrieval of command-line and input-file arguments. The entries are
Expand Down Expand Up @@ -1428,49 +1455,71 @@ public:
}
}

//! \brief Query integer with Parser, but treat the number as double
//! precision during parsing. The final result is cast to integer. It
//! may result in a runtime error if the conversion is not safe.
template <typename T, std::enable_if_t<std::is_integral_v<T>,int> = 0>
/**
* \brief Query T with Parser, but treat the number as double precision
* during parsing.
*
* The final result is cast to T. It may result in a runtime error if
* the conversion is not safe. T is either arithmetic type or
* std::optional of arithmetic type.
*/
template <typename T, std::enable_if_t<ppdetail::IsArithmeticOptional_v<T>, int> = 0>
int queryAsDouble (const char* name, T& ref) const
{
using value_type = ppdetail::underlying_type_t<T>;
double dref;
int exist = queryWithParser(name, dref);
if (exist) {
dref = std::round(dref);
ref = static_cast<T>(dref);
if (static_cast<double>(ref) != dref) {
amrex::Abort("ParmParse:: queryAsDouble is not safe");
auto vref = static_cast<value_type>(dref);
if constexpr (!std::is_same_v<value_type,bool>) {
if (static_cast<double>(vref) != dref) {
amrex::Abort("ParmParse:: queryAsDouble is not safe");
}
}
ref = vref;
}
return exist;
}

//! \brief Query integer array with Parser, but treat the numbers as
//! double precision uring parsing. The final results are cast to
//! integers. It may result in a runtime error if the conversion is not
//! safe.
template <typename T, std::enable_if_t<std::is_integral_v<T>,int> = 0>
/**
* \brief Query T array with Parser, but treat the number as double
* precision during parsing.
*
* The final result is cast to T's. It may result in a runtime error if
* the conversion is not safe. T is either arithmetic type or
* std::optional of arithmetic type.
*/
template <typename T, std::enable_if_t<ppdetail::IsArithmeticOptional_v<T>, int> = 0>
int queryarrAsDouble (const char* name, int nvals, T* ref) const
{
using value_type = ppdetail::underlying_type_t<T>;
std::vector<double> dref(nvals);
int exist = queryarrWithParser(name, nvals, dref.data());
if (exist) {
for (int i = 0; i < nvals; ++i) {
dref[i] = std::round(dref[i]);
ref[i] = static_cast<T>(dref[i]);
if (static_cast<double>(ref[i]) != dref[i]) {
amrex::Abort("ParmParse:: queryarrAsDouble is not safe");
auto vref = static_cast<value_type>(dref[i]);
if constexpr (!std::is_same_v<value_type,bool>) {
if (static_cast<double>(vref) != dref[i]) {
amrex::Abort("ParmParse:: queryarrAsDouble is not safe");
}
}
ref[i] = vref;
}
}
return exist;
}

//! \brief Get integer with Parser, but treat the number as double
//! precision during parsing. The final result is cast to integer. It
//! may result in a runtime error if the conversion is not safe.
template <typename T, std::enable_if_t<std::is_integral_v<T>,int> = 0>
/**
* \brief Get T with Parser, but treat the number as double precision
* during parsing.
*
* The final result is cast to T. It may result in a runtime error if
* the conversion is not safe. T is either arithmetic type or
* std::optional of arithmetic type.
*/
template <typename T, std::enable_if_t<ppdetail::IsArithmeticOptional_v<T>, int> = 0>
void getAsDouble (const char* name, T& ref) const
{
int exist = this->queryAsDouble(name, ref);
Expand All @@ -1479,11 +1528,15 @@ public:
}
}

//! \brief Get integer array with Parser, but treat the numbers as
//! double precision uring parsing. The final results are cast to
//! integers. It may result in a runtime error if the conversion is not
//! safe.
template <typename T, std::enable_if_t<std::is_integral_v<T>,int> = 0>
/**
* \brief Get T array with Parser, but treat the number as double
* precision during parsing.
*
* The final result is cast to T's. It may result in a runtime error if
* the conversion is not safe. T is either arithmetic type or
* std::optional of arithmetic type.
*/
template <typename T, std::enable_if_t<ppdetail::IsArithmeticOptional_v<T>, int> = 0>
void getarrAsDouble (const char* name, int nvals, T* ref) const
{
int exist = this->queryarrAsDouble(name, nvals, ref);
Expand Down
2 changes: 2 additions & 0 deletions Tests/ParmParse/inputs
Original file line number Diff line number Diff line change
Expand Up @@ -60,3 +60,5 @@ my_constants.dx = 6.25e-7
my_constants.nx = lx/dx
n_cell = nx nx nx
ny = nx

do_this = 1
14 changes: 14 additions & 0 deletions Tests/ParmParse/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,20 @@ int main(int argc, char* argv[])
pp.queryarrAsDouble("n_cell", 3, n_cell.data());
AMREX_ALWAYS_ASSERT(n_cell[0] == 64 && n_cell[1] == 64 && n_cell[2] == 64);
}
{
ParmParse pp;
bool b_do_this = false;
pp.queryAsDouble("do_this", b_do_this);
AMREX_ALWAYS_ASSERT(b_do_this);

std::optional<int> o_do_this;
pp.queryAsDouble("do_this", o_do_this);
AMREX_ALWAYS_ASSERT(o_do_this.has_value() && o_do_this.value());

std::optional<int> o_do_that;
pp.queryAsDouble("do_that", o_do_that);
AMREX_ALWAYS_ASSERT(!o_do_that.has_value());
}
{
amrex::Print() << "SUCCESS\n";
}
Expand Down

0 comments on commit 97fcea3

Please sign in to comment.