Skip to content
1 change: 0 additions & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -396,7 +396,6 @@ set(BOUT_SOURCES
./src/sys/range.cxx
./src/sys/slepclib.cxx
./src/sys/timer.cxx
./src/sys/type_name.cxx
./src/sys/utils.cxx
${CMAKE_CURRENT_BINARY_DIR}/include/bout/revision.hxx
${CMAKE_CURRENT_BINARY_DIR}/include/bout/version.hxx
Expand Down
23 changes: 13 additions & 10 deletions include/bout/field.hxx
Original file line number Diff line number Diff line change
Expand Up @@ -263,8 +263,11 @@ inline T filledFrom(const T& f, Function func, std::string region_string = "RGN_
return result;
}

template <typename T>
concept IsField = std::is_base_of_v<Field, T>;

/// Unary + operator. This doesn't do anything
template <typename T, typename = bout::utils::EnableIfField<T>>
template <IsField T>
T operator+(const T& f) {
return f;
}
Expand Down Expand Up @@ -395,7 +398,7 @@ inline BoutReal min(const BinaryExpr<ResT, L, R, Func>& f, bool allpe = false,
/// @param[in] f The field to check
/// @param[in] allpe Check over all processors
/// @param[in] region The region to check for uniformity over
template <typename T, typename = bout::utils::EnableIfField<T>>
template <IsField T>
inline bool isUniform(const T& f, bool allpe = false,
const std::string& region = "RGN_ALL") {
bool result = true;
Expand Down Expand Up @@ -423,7 +426,7 @@ inline bool isUniform(const T& f, bool allpe = false,
/// @param[in] f The field to check
/// @param[in] allpe Check over all processors
/// @param[in] region The region to assume is uniform
template <typename T, typename = bout::utils::EnableIfField<T>>
template <IsField T>
inline BoutReal getUniform(const T& f, [[maybe_unused]] bool allpe = false,
const std::string& region = "RGN_ALL") {
#if CHECK > 1
Expand All @@ -448,7 +451,7 @@ inline BoutReal getUniform(const T& f, [[maybe_unused]] bool allpe = false,
/// @param[in] f Input field
/// @param[in] allpe Maximum over all processors?
/// @param[in] rgn The region to calculate the result over
template <typename T, typename = bout::utils::EnableIfField<T>>
template <IsField T>
inline BoutReal max(const T& f, bool allpe = false,
const std::string& rgn = "RGN_NOBNDRY") {

Expand Down Expand Up @@ -499,7 +502,7 @@ inline BoutReal max(const BinaryExpr<ResT, L, R, Func>& f, bool allpe = false,
/// @param[in] f Input field
/// @param[in] allpe Mean over all processors?
/// @param[in] rgn The region to calculate the result over
template <typename T, typename = bout::utils::EnableIfField<T>>
template <IsField T>
inline BoutReal mean(const T& f, bool allpe = false,
const std::string& rgn = "RGN_NOBNDRY") {

Expand Down Expand Up @@ -838,7 +841,7 @@ std::optional<int> getPerpYIndex(const BinaryExpr<ResT, L, R, Func>& expr) {
} \
}; \
}; \
template <typename T, typename = bout::utils::EnableIfField<T>> \
template <IsField T> \
inline auto name(const T& f, const std::string& rgn = "RGN_ALL") { \
using ResT = bout::detail::UnaryFieldResult_t<T>; \
return BinaryExpr<ResT, T, T, bout::op::name>{ \
Expand Down Expand Up @@ -908,7 +911,7 @@ struct Floor {
};
}; // namespace bout::op

template <typename T, typename = bout::utils::EnableIfField<T>>
template <IsField T>
inline auto SQ(const T& f, const std::string& rgn = "RGN_ALL") {
using ResT = bout::detail::UnaryFieldResult_t<T>;
return BinaryExpr<ResT, T, T, bout::op::Square>{
Expand Down Expand Up @@ -1050,7 +1053,7 @@ FIELD_FUNC(tanh, ::tanh)
/// Check if all values of a field \p var are finite.
/// Loops over all points including the boundaries by
/// default (can be changed using the \p rgn argument
template <typename T, typename = bout::utils::EnableIfField<T>>
template <IsField T>
inline bool finite(const T& f, const std::string& rgn = "RGN_ALL") {

if (!f.isAllocated()) {
Expand All @@ -1068,7 +1071,7 @@ inline bool finite(const T& f, const std::string& rgn = "RGN_ALL") {

/// Makes a copy of a field \p f, ensuring that the underlying data is
/// not shared.
template <typename T, typename = bout::utils::EnableIfField<T>>
template <IsField T>
T copy(const T& f) {
T result = f;
result.allocate();
Expand All @@ -1083,7 +1086,7 @@ class Field3DParallel;
/// @param[in] var Variable to apply floor to
/// @param[in] f The floor value
/// @param[in] rgn The region to calculate the result over
template <typename T, typename = bout::utils::EnableIfField<T>>
template <IsField T>
inline auto floor(const T& var, BoutReal f, const std::string& rgn = "RGN_ALL") {
using ResT = bout::detail::UnaryFieldResult_t<T>;
return BinaryExpr<ResT, T, Constant<BoutReal>, bout::op::Floor>{
Expand Down
2 changes: 1 addition & 1 deletion include/bout/field3d.hxx
Original file line number Diff line number Diff line change
Expand Up @@ -700,7 +700,7 @@ protected:
_track(change, operation);
}
}
template <typename T, typename = bout::utils::EnableIfField<T>>
template <IsField T>
void _track(const T& change, std::string operation);
void _track(const BoutReal& change, std::string operation);

Expand Down
27 changes: 4 additions & 23 deletions include/bout/fieldgroup.hxx
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
#ifndef BOUT_FIELDGROUP_H
#define BOUT_FIELDGROUP_H

#include <bout/traits.hxx>
#include <bout/vector2d.hxx>
#include <bout/vector3d.hxx>

Expand Down Expand Up @@ -62,7 +61,7 @@ public:
/// to FieldGroup, leading to an infinite loop.
template <typename... Ts>
explicit FieldGroup(Ts&... ts) {
add(ts...);
(add(ts), ...);
}

/// Copy contents of another FieldGroup \p other into this group.
Expand Down Expand Up @@ -121,27 +120,9 @@ public:

/// Add multiple fields to this group
template <typename... Ts>
void add(Field& t, Ts&... ts) {
add(t); // Add the first using functions above
add(ts...); // Add the rest
}

template <typename... Ts>
void add(Field3D& t, Ts&... ts) {
add(t); // Add the first using functions above
add(ts...); // Add the rest
}

template <typename... Ts>
void add(Vector3D& t, Ts&... ts) {
add(t); // Add the first using functions above
add(ts...); // Add the rest
}

template <typename... Ts>
void add(Vector2D& t, Ts&... ts) {
add(t); // Add the first using functions above
add(ts...); // Add the rest
requires(sizeof...(Ts) > 1)
void add(Ts&... ts) {
(add(ts), ...);
}

/// Return number of fields
Expand Down
84 changes: 45 additions & 39 deletions include/bout/sys/type_name.hxx
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,10 @@
#include "bout/bout_types.hxx"

#include <string>
#include <type_traits>
#include <typeinfo>

// Forward declarations
class Field2D;
class Field3D;
class FieldPerp;
Expand All @@ -18,49 +20,53 @@ class Matrix;
template <class T>
class Tensor;

namespace bout {
namespace utils {
namespace bout::utils {

template <typename T>
std::string typeName() {
if constexpr (std::is_same_v<T, bool>) {
return "bool";
}
if constexpr (std::is_same_v<T, int>) {
return "int";
}
if constexpr (std::is_same_v<T, std::string>) {
return "string";
}
// Specialised for BOUT++ types to ensure that the result is human-readable
if constexpr (std::is_same_v<T, BoutReal>) {
return "BoutReal";
}
if constexpr (std::is_same_v<T, Field2D>) {
return "Field2D";
}
if constexpr (std::is_same_v<T, Field3D>) {
return "Field3D";
}
if constexpr (std::is_same_v<T, FieldPerp>) {
return "FieldPerp";
}
if constexpr (std::is_same_v<T, Array<int>>) {
return "Array<int>";
}
if constexpr (std::is_same_v<T, Array<BoutReal>>) {
return "Array<BoutReal>";
}
if constexpr (std::is_same_v<T, Matrix<int>>) {
return "Matrix<int>";
}
if constexpr (std::is_same_v<T, Matrix<BoutReal>>) {
return "Matrix<BoutReal>";
}
if constexpr (std::is_same_v<T, Tensor<int>>) {
return "Tensor<int>";
}
if constexpr (std::is_same_v<T, Tensor<BoutReal>>) {
return "Tensor<BoutReal>";
}
return typeid(T).name();
}

template <>
std::string typeName<bool>();
} // namespace bout::utils

template <>
std::string typeName<int>();

template <>
std::string typeName<std::string>();

// Specialised for BOUT++ types to ensure that the result is human-readable
template <>
std::string typeName<BoutReal>();

template <>
std::string typeName<Field2D>();

template <>
std::string typeName<Field3D>();

template <>
std::string typeName<FieldPerp>();

template <>
std::string typeName<Array<int>>();
template <>
std::string typeName<Array<BoutReal>>();
template <>
std::string typeName<Matrix<int>>();
template <>
std::string typeName<Matrix<BoutReal>>();
template <>
std::string typeName<Tensor<int>>();
template <>
std::string typeName<Tensor<BoutReal>>();
} // namespace utils
} // namespace bout

#endif //TYPE_NAME_HXX
#endif // TYPE_NAME_HXX
16 changes: 11 additions & 5 deletions include/bout/where.hxx
Original file line number Diff line number Diff line change
Expand Up @@ -31,14 +31,17 @@
#include "bout/field.hxx"
#include "bout/field2d.hxx"
#include "bout/field3d.hxx"
#include <type_traits>

/// For each point, choose between two inputs based on a third input
///
/// @param[in] test The value which determines which input to use
/// @param[in] gt0 Uses this value if test > 0.0
/// @param[in] le0 Uses this value if test <= 0.0
template <class T, class U, class V,
class ResultType = typename bout::utils::EnableIfField<T, U, V>>

// Overload 1: Three fields
template <IsField T, IsField U, IsField V,
typename ResultType = std::common_type_t<T, U, V>>
auto where(const T& test, const U& gt0, const V& le0) -> ResultType {
ASSERT1_FIELDS_COMPATIBLE(test, gt0);
ASSERT1_FIELDS_COMPATIBLE(test, le0);
Expand All @@ -51,7 +54,8 @@ auto where(const T& test, const U& gt0, const V& le0) -> ResultType {
return result;
}

template <class T, class U, class ResultType = typename bout::utils::EnableIfField<T, U>>
// Overload 2: Two fields, one BoutReal (le0)
template <IsField T, IsField U, typename ResultType = std::common_type_t<T, U>>
auto where(const T& test, const U& gt0, BoutReal le0) -> ResultType {
ASSERT1_FIELDS_COMPATIBLE(test, gt0);

Expand All @@ -63,7 +67,8 @@ auto where(const T& test, const U& gt0, BoutReal le0) -> ResultType {
return result;
}

template <class T, class V, class ResultType = typename bout::utils::EnableIfField<T, V>>
// Overload 3: Two fields, one BoutReal (gt0)
template <IsField T, IsField V, typename ResultType = std::common_type_t<T, V>>
auto where(const T& test, BoutReal gt0, const V& le0) -> ResultType {
ASSERT1_FIELDS_COMPATIBLE(test, le0);

Expand All @@ -75,7 +80,8 @@ auto where(const T& test, BoutReal gt0, const V& le0) -> ResultType {
return result;
}

template <class T, class ResultType = T>
// Overload 4: One field, two BoutReals
template <IsField T, typename ResultType = T>
auto where(const T& test, BoutReal gt0, BoutReal le0) -> ResultType {
ResultType result{emptyFrom(test)};

Expand Down
8 changes: 3 additions & 5 deletions src/field/field3d.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -972,7 +972,7 @@ Field3D& Field3D::enableTracking(const std::string& name,
return *this;
}

template <typename T, typename>
template <IsField T>
void Field3D::_track(const T& change, std::string operation) {
if (tracking_state == 0) {
return;
Expand Down Expand Up @@ -1000,12 +1000,10 @@ void Field3D::_track(const T& change, std::string operation) {
});
}

template void
Field3D::_track<Field3D, bout::utils::EnableIfField<Field3D>>(const Field3D&,
std::string);
template void Field3D::_track<Field3D>(const Field3D&, std::string);
template void Field3D::_track<Field3DParallel>(const Field3DParallel&, std::string);
template void Field3D::_track<Field2D>(const Field2D&, std::string);
template void Field3D::_track<>(const FieldPerp&, std::string);
template void Field3D::_track<FieldPerp>(const FieldPerp&, std::string);

void Field3D::_track(const BoutReal& change, std::string operation) {
if (tracking_state == 0) {
Expand Down
4 changes: 2 additions & 2 deletions src/mesh/coordinates.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ namespace {
// initializing yet, leading to an infinite recursion.
// Also, here we interpolate for the boundary points at xstart/ystart and
// (xend+1)/(yend+1) instead of extrapolating.
template <class T, typename = bout::utils::EnableIfField<T>>
template <IsField T>
void fillGuards_impl(T& result, CELL_LOC location, const T& f, bool extrapolate_x,
bool extrapolate_y, bool no_extra_interpolate = false) {
const auto* localmesh = result.getMesh();
Expand Down Expand Up @@ -175,7 +175,7 @@ void fillGuards_impl(T& result, CELL_LOC location, const T& f, bool extrapolate_
/// Boundary guard cells are set by extrapolating from the grid, like
/// 'free_o3' boundary conditions
/// Corner guard cells are set to BoutNaN
template <class T, typename = bout::utils::EnableIfField<T>>
template <IsField T>
auto interpolateAndExtrapolate(const T& f_, CELL_LOC location, bool extrapolate_x,
bool extrapolate_y, bool no_extra_interpolate,
ParallelTransform* pt_ = nullptr) -> T {
Expand Down
10 changes: 5 additions & 5 deletions src/solver/nvector.hxx
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ private:
public:
BoutNVector() = delete; // Enforce static access only

template <typename T, typename Ctx, typename = bout::utils::EnableIfField<T>>
template <IsField T, typename Ctx>
static N_Vector create(Ctx&& ctx, T& field, const bool evolve_bndry,
const bool own = false) {
N_Vector v = callWithSUNContext(N_VNewEmpty, std::forward<Ctx>(ctx));
Expand Down Expand Up @@ -186,12 +186,12 @@ public:
return v;
}

template <typename T, typename = bout::utils::EnableIfField<T>>
template <IsField T>
static void swap(const N_Vector v, T& field) {
field.swapData(get_field<T>(v));
}

template <typename T, typename = bout::utils::EnableIfField<T>>
template <IsField T>
static T& get(const N_Vector v) {
return get_field<T>(v);
}
Expand All @@ -205,12 +205,12 @@ public:
return v;
}

template <typename T, typename = bout::utils::EnableIfField<T>>
template <IsField T>
static void swap(const N_Vector v, T& field, std::size_t subvector) {
return BoutNVector::swap(N_VGetSubvector_ManyVector(v, subvector), field);
}

template <typename T, typename = bout::utils::EnableIfField<T>>
template <IsField T>
static T& get(const N_Vector v, std::size_t subvector) {
return BoutNVector::get<T>(N_VGetSubvector_ManyVector(v, subvector));
}
Expand Down
Loading
Loading