Skip to content

Commit ae5e990

Browse files
committed
Merge branch 'next' of https://github.com/boutproject/BOUT-dev into normalise-metrics
2 parents bb4964e + b445c7e commit ae5e990

4 files changed

Lines changed: 128 additions & 19 deletions

File tree

include/bout/bout_enum_class.hxx

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@
6767
/// Create an enum class with toString and <enum name>FromString functions, and an
6868
/// Options::as<enum> overload to read the enum
6969
#define BOUT_ENUM_CLASS(enumname, ...) \
70-
enum class enumname : std::int8_t { __VA_ARGS__ }; \
70+
enum class enumname : std::uint8_t { __VA_ARGS__ }; \
7171
\
7272
inline std::string toString(enumname e) { \
7373
\
@@ -105,4 +105,48 @@
105105
return out << toString(e); \
106106
}
107107

108+
/// Create an enum class with toString and <enum name>FromString functions, and an
109+
/// Options::as<enum> overload to read the enum
110+
#define BOUT_ENUM_CLASS_NS(ns, enumname, ...) \
111+
namespace ns { \
112+
enum class enumname : std::uint8_t { __VA_ARGS__ }; \
113+
} \
114+
\
115+
inline std::string toString(ns::enumname e) { \
116+
\
117+
const static std::map<ns::enumname, std::string> toString_map = { \
118+
BOUT_ENUM_CLASS_MAP_ARGS(BOUT_ENUM_CLASS_STR, ns::enumname, __VA_ARGS__)}; \
119+
auto found = toString_map.find(e); \
120+
if (found == toString_map.end()) { \
121+
throw BoutException("Did not find enum {:d}", static_cast<int>(e)); \
122+
} \
123+
return found->second; \
124+
} \
125+
namespace ns { \
126+
inline enumname BOUT_MAKE_FROMSTRING_NAME(enumname)(const std::string& s) { \
127+
const static std::map<std::string, enumname> fromString_map = { \
128+
BOUT_ENUM_CLASS_MAP_ARGS(BOUT_STR_ENUM_CLASS, enumname, __VA_ARGS__)}; \
129+
auto found = fromString_map.find(s); \
130+
if (found == fromString_map.end()) { \
131+
std::string valid_values{}; \
132+
for (auto const& entry : fromString_map) { \
133+
valid_values += std::string(" ") + entry.first; \
134+
} \
135+
throw BoutException("Did not find enum {:s}. Valid values: {:s}", s, \
136+
valid_values); \
137+
} \
138+
return found->second; \
139+
} \
140+
} \
141+
\
142+
template <> \
143+
inline ns::enumname Options::as<ns::enumname>(const ns::enumname&) const { \
144+
return ns::BOUT_MAKE_FROMSTRING_NAME(enumname)(this->as<std::string>()); \
145+
} \
146+
namespace ns { \
147+
inline std::ostream& operator<<(std::ostream& out, const enumname& e) { \
148+
return out << toString(e); \
149+
} \
150+
}
151+
108152
#endif // BOUT_ENUM_CLASS_H

include/bout/difops.hxx

Lines changed: 21 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -36,14 +36,15 @@
3636
#ifndef BOUT_DIFOPS_H
3737
#define BOUT_DIFOPS_H
3838

39+
#include "bout/bout_enum_class.hxx"
3940
#include "bout/bout_types.hxx"
41+
#include "bout/coordinates.hxx"
4042
#include "bout/field2d.hxx"
4143
#include "bout/field3d.hxx"
4244
#include "bout/metric_tensor.hxx"
4345

44-
#include <string>
45-
4646
#include <cstdint>
47+
#include <string>
4748

4849
class Solver;
4950

@@ -200,21 +201,24 @@ Field3D Div_par_K_Grad_par(const Field3DParallel& kY, const Field2D& f,
200201
Field3D Div_par_K_Grad_par(const Field3DParallel& kY, const Field3DParallel& f,
201202
CELL_LOC outloc = CELL_DEFAULT);
202203

203-
namespace bout {
204-
enum class ConductionMethod : uint8_t {
205-
/// Separately averages :math:`K`, :math:`J`, :math:`g_{22}`, and
206-
/// :math:`dy` at the face and then multiplies them together.
207-
Original,
208-
/// Uses the same stencil as ``Original`` but averages :math:`J K`
209-
/// together before applying the face gradient.
210-
ProductJK,
211-
/// Uses a harmonic average of the half-cell conductances
212-
/// :math:`K J / (g_{22} dy)`. This better matches a series-resistance
213-
/// interpretation of two adjacent half-cells and can give noticeably
214-
/// different results when coefficients or cell sizes vary strongly.
215-
Harmonic
216-
};
217-
}
204+
/// enum class bout::ConductionMethod
205+
/// ---------------------------------
206+
///
207+
/// Original:
208+
/// Separately averages :math:`K`, :math:`J`, :math:`g_{22}`, and
209+
/// :math:`dy` at the face and then multiplies them together.
210+
///
211+
/// ProductJK:
212+
/// Uses the same stencil as ``Original`` but averages :math:`J K`
213+
/// together before applying the face gradient.
214+
///
215+
/// Harmonic:
216+
/// Uses a harmonic average of the half-cell conductances
217+
/// :math:`K J / (g_{22} dy)`. This better matches a series-resistance
218+
/// interpretation of two adjacent half-cells and can give noticeably
219+
/// different results when coefficients or cell sizes vary strongly.
220+
BOUT_ENUM_CLASS_NS(bout, ConductionMethod, Original, ProductJK, Harmonic);
221+
218222
/// Version with energy flow diagnostic
219223
/// For FCI fields, `flow_ylow` is currently returned as zero.
220224
Field3D

src/mesh/difops.cxx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -539,7 +539,7 @@ Field3D Div_par_K_Grad_par_mod(const Field3DParallel& Kin, const Field3DParallel
539539
}
540540
throw BoutException(
541541
"Unknown method `{}` - choose from `Original`, `ProductJK` or `Harmonic`.",
542-
static_cast<int>(method));
542+
toString(method));
543543
}
544544
/*******************************************************************************
545545
* Delp2

tests/unit/include/bout/test_bout_enum_class.cxx

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,25 @@
66
#include "bout/output.hxx"
77

88
BOUT_ENUM_CLASS(TestEnum, foo, bar);
9+
BOUT_ENUM_CLASS_NS(bout, TestEnum, foo, bar);
10+
BOUT_ENUM_CLASS_NS(bout::test, TestEnum, foo, bar);
11+
12+
TEST(BoutEnumClassNS, toString) {
13+
EXPECT_EQ(toString(bout::TestEnum::foo), "foo");
14+
EXPECT_EQ(toString(bout::TestEnum::bar), "bar");
15+
}
916

1017
TEST(BoutEnumClass, toString) {
1118
EXPECT_EQ(toString(TestEnum::foo), "foo");
1219
EXPECT_EQ(toString(TestEnum::bar), "bar");
1320
}
1421

22+
TEST(BoutEnumClassNS, fromString) {
23+
EXPECT_EQ(bout::TestEnumFromString("foo"), bout::TestEnum::foo);
24+
EXPECT_EQ(bout::TestEnumFromString("bar"), bout::TestEnum::bar);
25+
EXPECT_THROW(bout::TestEnumFromString("expect_fail"), BoutException);
26+
}
27+
1528
TEST(BoutEnumClass, fromString) {
1629
EXPECT_EQ(TestEnumFromString("foo"), TestEnum::foo);
1730
EXPECT_EQ(TestEnumFromString("bar"), TestEnum::bar);
@@ -38,10 +51,58 @@ TEST(BoutEnumClass, options) {
3851
EXPECT_THROW(options["optfail"].as<TestEnum>(), BoutException);
3952
}
4053

54+
TEST(BoutEnumClassNS, options) {
55+
WithQuietOutput quiet_info{output_info};
56+
57+
Options options;
58+
59+
auto opt1 = options["opt"].withDefault(bout::TestEnum::foo);
60+
EXPECT_EQ(opt1, bout::TestEnum::foo);
61+
EXPECT_NE(opt1, bout::TestEnum::bar);
62+
63+
options["opt"] = "bar";
64+
65+
auto opt2 = options["opt"].as<bout::TestEnum>();
66+
EXPECT_EQ(opt2, bout::TestEnum::bar);
67+
EXPECT_NE(opt2, bout::TestEnum::foo);
68+
69+
options["optfail"] = "expect_fail";
70+
71+
EXPECT_THROW(options["optfail"].as<bout::TestEnum>(), BoutException);
72+
}
73+
74+
TEST(BoutEnumClassNS2, options) {
75+
WithQuietOutput quiet_info{output_info};
76+
77+
Options options;
78+
79+
auto opt1 = options["opt"].withDefault(bout::test::TestEnum::foo);
80+
EXPECT_EQ(opt1, bout::test::TestEnum::foo);
81+
EXPECT_NE(opt1, bout::test::TestEnum::bar);
82+
83+
options["opt"] = "bar";
84+
85+
auto opt2 = options["opt"].as<bout::test::TestEnum>();
86+
EXPECT_EQ(opt2, bout::test::TestEnum::bar);
87+
EXPECT_NE(opt2, bout::test::TestEnum::foo);
88+
89+
options["optfail"] = "expect_fail";
90+
91+
EXPECT_THROW(options["optfail"].as<bout::test::TestEnum>(), BoutException);
92+
}
93+
4194
TEST(BoutEnumClass, ostream) {
4295
auto sstream = std::stringstream();
4396

4497
sstream << TestEnum::foo << TestEnum::bar;
4598

4699
EXPECT_EQ(sstream.str(), "foobar");
47100
}
101+
102+
TEST(BoutEnumClassNS, ostream) {
103+
auto sstream = std::stringstream();
104+
105+
sstream << bout::TestEnum::foo << bout::TestEnum::bar;
106+
107+
EXPECT_EQ(sstream.str(), "foobar");
108+
}

0 commit comments

Comments
 (0)