Line | Branch | Exec | Source |
---|---|---|---|
1 | #pragma once | ||
2 | |||
3 | #ifndef REAL_TYPE | ||
4 | #define REAL_TYPE double | ||
5 | #endif | ||
6 | |||
7 | #ifndef DIM | ||
8 | #define DIM 3 | ||
9 | #endif | ||
10 | |||
11 | #include <eigen3/Eigen/Dense> | ||
12 | #include <yaml-cpp/yaml.h> | ||
13 | |||
14 | using Real = REAL_TYPE; | ||
15 | using Vec = Eigen::Matrix<Real, DIM, 1>; | ||
16 | using VecVec = Eigen::Matrix<Real, DIM, Eigen::Dynamic>; | ||
17 | using ArrayI = Eigen::Array<int, DIM, 1>; | ||
18 | |||
19 | /** | ||
20 | * Get the minimum image vector from position r1 to r2 with respect to a box of size L. | ||
21 | */ | ||
22 | 695205415 | inline Vec r_ij(const Vec &L, const Vec &r1, const Vec &r2) { | |
23 | 695205415 | Vec result; | |
24 | 695205415 | result = r2 - r1; | |
25 | 695205415 | result.array() -= (result.array() / L.array()).round() * L.array(); | |
26 | 695205415 | return result; | |
27 | } | ||
28 | |||
29 | namespace YAML { | ||
30 | |||
31 | // The following enables yaml-cpp to natively encode and decode Eigen matrices and arrays. | ||
32 | // For example, one can now use node[key].as<Vec>() | ||
33 | template <template <typename, int...> class EigenClass, typename Scalar, int d> | ||
34 | struct convert<EigenClass<Scalar, d, 1>> { | ||
35 | 20 | static Node encode(const EigenClass<Scalar, d, 1> &rhs) { | |
36 | 20 | Node node; | |
37 |
2/2✓ Branch 0 taken 60 times.
✓ Branch 1 taken 20 times.
|
80 | for (int i = 0; i < d; ++i) { |
38 |
1/2✓ Branch 2 taken 60 times.
✗ Branch 3 not taken.
|
60 | node.push_back(rhs[i]); |
39 | } | ||
40 | 20 | return node; | |
41 | } | ||
42 | |||
43 | 110 | static bool decode(const Node &node, EigenClass<Scalar, d, 1> &rhs) { | |
44 |
2/4✓ Branch 0 taken 106 times.
✗ Branch 1 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 106 times.
|
110 | if (!node.IsSequence() || node.size() != d) { |
45 | ✗ | return false; | |
46 | } | ||
47 | |||
48 |
2/2✓ Branch 0 taken 318 times.
✓ Branch 1 taken 106 times.
|
440 | for (int i = 0; i < d; ++i) { |
49 |
1/2✓ Branch 2 taken 318 times.
✗ Branch 3 not taken.
|
330 | rhs[i] = node[i].as<Scalar>(); |
50 | } | ||
51 | 110 | return true; | |
52 | } | ||
53 | }; | ||
54 | |||
55 | // This helper class is needed because C++ forbids partial specialization of functions. | ||
56 | // In our case, we want to specialize the parse function to generic Eigen types. | ||
57 | template <typename ReturnT, typename DefaultT = ReturnT> struct ParseHelper { | ||
58 |
1/2✓ Branch 2 taken 484 times.
✗ Branch 3 not taken.
|
968 | ReturnT operator()(const Node &node, const std::string &key) { return node[key].as<ReturnT>(); } |
59 | 1468 | ReturnT operator()(const Node &node, const std::string &key, DefaultT defaultValue) { | |
60 |
4/6✓ Branch 1 taken 416 times.
✓ Branch 2 taken 318 times.
✓ Branch 4 taken 416 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 58 times.
✗ Branch 8 not taken.
|
1468 | return node[key] ? (*this)(node, key) : defaultValue; |
61 | } | ||
62 | }; | ||
63 | |||
64 | template <template <typename, int...> class EigenClass, typename Scalar1, int d, typename Scalar2> | ||
65 | struct ParseHelper<EigenClass<Scalar1, d, 1>, Scalar2> { | ||
66 | 144 | EigenClass<Scalar1, d, 1> operator()(const Node &node, const std::string &key) { | |
67 |
4/6✓ Branch 1 taken 31 times.
✓ Branch 2 taken 106 times.
✓ Branch 4 taken 31 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 31 times.
✗ Branch 8 not taken.
|
432 | return node[key].IsScalar() ? EigenClass<Scalar1, d, 1>::Constant(node[key].as<Scalar1>()) |
68 |
4/7✓ Branch 3 taken 106 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 106 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 31 times.
✓ Branch 10 taken 106 times.
✗ Branch 13 not taken.
|
288 | : node[key].as<EigenClass<Scalar1, d, 1>>(); |
69 | } | ||
70 | 84 | EigenClass<Scalar1, d, 1> operator()(const Node &node, const std::string &key, | |
71 | Scalar2 defaultValue) { | ||
72 |
3/4✓ Branch 1 taken 55 times.
✓ Branch 2 taken 29 times.
✓ Branch 4 taken 55 times.
✗ Branch 5 not taken.
|
113 | return node[key] ? (*this)(node, key) : EigenClass<Scalar1, d, 1>::Constant(defaultValue); |
73 | } | ||
74 | }; | ||
75 | |||
76 | template <template <typename, int...> class EigenClass, typename Scalar1, int d, | ||
77 | template <typename, int...> class EigenClass2, typename Scalar2> | ||
78 | struct ParseHelper<EigenClass<Scalar1, d, 1>, EigenClass2<Scalar2, d, 1>> { | ||
79 | 82 | EigenClass<Scalar1, d, 1> operator()(const Node &node, const std::string &key) { | |
80 | 164 | return ParseHelper<EigenClass<Scalar1, d, 1>, Scalar1>{}(node, key); | |
81 | } | ||
82 | EigenClass<Scalar1, d, 1> operator()(const Node &node, const std::string &key, | ||
83 | EigenClass2<Scalar2, d, 1> defaultValue) { | ||
84 | return node[key] ? (*this)(node, key) : EigenClass<Scalar1, d, 1>(defaultValue); | ||
85 | } | ||
86 | }; | ||
87 | |||
88 | // Two helper methods are provided for easy and consistent parsing of yaml nodes (with and without | ||
89 | // setting defaults) | ||
90 | 300 | template <typename ReturnT> auto parse(const Node &node, const std::string &key) { | |
91 | 300 | return ParseHelper<ReturnT>{}(node, key); | |
92 | } | ||
93 | |||
94 | template <typename ReturnT, typename DefaultT> | ||
95 | 818 | auto parse(const Node &node, const std::string &key, DefaultT defaultValue) { | |
96 | 818 | return ParseHelper<ReturnT, DefaultT>{}(node, key, defaultValue); | |
97 | } | ||
98 | |||
99 | } // namespace YAML | ||
100 |