Line | Branch | Exec | Source |
---|---|---|---|
1 | // -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- | ||
2 | // vi: set et ts=4 sw=4 sts=4: | ||
3 | // | ||
4 | // SPDX-FileCopyrightInfo: Copyright © DuMux Project contributors, see AUTHORS.md in root folder | ||
5 | // SPDX-License-Identifier: GPL-3.0-or-later | ||
6 | // | ||
7 | /*! | ||
8 | * \file | ||
9 | * \ingroup Core | ||
10 | * \brief The infrastructure to retrieve metadata information. | ||
11 | */ | ||
12 | #ifndef DUMUX_COMMON_METADATA_HH | ||
13 | #define DUMUX_COMMON_METADATA_HH | ||
14 | |||
15 | #include <iostream> | ||
16 | #include <list> | ||
17 | #include <sstream> | ||
18 | #include <unordered_map> | ||
19 | #include <fstream> | ||
20 | #include <functional> | ||
21 | #include <string> | ||
22 | #include <tuple> | ||
23 | |||
24 | #include <dune/common/hybridutilities.hh> | ||
25 | #include <dune/common/indices.hh> | ||
26 | #include <dune/common/concept.hh> | ||
27 | #include <dune/common/classname.hh> | ||
28 | #include <dune/grid/common/gridview.hh> | ||
29 | |||
30 | #include <dumux/io/json.hh> | ||
31 | |||
32 | #include <dumux/common/properties.hh> | ||
33 | #include <dumux/common/typetraits/utility.hh> | ||
34 | #include <dumux/common/typetraits/isvalid.hh> | ||
35 | |||
36 | #include <dumux/assembly/fvassembler.hh> | ||
37 | #include <dumux/assembly/diffmethod.hh> | ||
38 | #include <dumux/discretization/basegridgeometry.hh> | ||
39 | #include <dumux/discretization/fvgridvariables.hh> | ||
40 | |||
41 | namespace Dumux::MetaData { | ||
42 | |||
43 | namespace Concept { | ||
44 | |||
45 | //! Concept of GridGeometry | ||
46 | struct GridGeometry | ||
47 | { | ||
48 | template<class GG> | ||
49 | auto require(const GG& gg) -> decltype( | ||
50 | gg.isPeriodic(), | ||
51 | gg.numScv(), | ||
52 | gg.numScvf(), | ||
53 | gg.numBoundaryScvf(), | ||
54 | gg.numDofs(), | ||
55 | GG::discMethod | ||
56 | ); | ||
57 | }; | ||
58 | |||
59 | //! Concept of GridVariables | ||
60 | struct GridVariables | ||
61 | { | ||
62 | template<class GV> | ||
63 | auto require(const GV& gv) -> decltype( | ||
64 | Dune::Concept::requireType<typename GV::GridVolumeVariables>(), | ||
65 | Dune::Concept::requireType<typename GV::VolumeVariables>(), | ||
66 | Dune::Concept::requireType<typename GV::GridFluxVariablesCache>() | ||
67 | ); | ||
68 | }; | ||
69 | |||
70 | //! Concept of GridView | ||
71 | struct GridView | ||
72 | { | ||
73 | template<class GV> | ||
74 | auto require(const GV& gv) -> decltype( | ||
75 | Dune::Concept::requireBaseOf<Dune::GridView<typename GV::Traits>, GV>() | ||
76 | ); | ||
77 | }; | ||
78 | |||
79 | } // end namespace Concept | ||
80 | |||
81 | namespace Detail { | ||
82 | |||
83 | ✗ | std::string removeNamespace(std::string&& s) | |
84 | { | ||
85 | ✗ | std::size_t last = s.find_last_of("::"); | |
86 | |||
87 | ✗ | if(last != std::string::npos) | |
88 | ✗ | s.erase(0, last+1); | |
89 | |||
90 | ✗ | return std::move(s); | |
91 | } | ||
92 | |||
93 | template<class TTagTuple, class Collector> | ||
94 | void collectTypeTagsFromTuple(Collector& collector, int depth=0, int parentBranch=-1) | ||
95 | { | ||
96 | using namespace Dune::Hybrid; | ||
97 | forEach(std::make_index_sequence<std::tuple_size_v<TTagTuple>>{}, [&](auto i) | ||
98 | { | ||
99 | using type = typename std::tuple_element<i, TTagTuple>::type; | ||
100 | collector.push_back(std::tuple<int, int, std::string>{depth, parentBranch, removeNamespace(Dune::className<type>())}); | ||
101 | if constexpr (Dumux::Properties::Detail::hasParentTypeTag<type>(int{})) | ||
102 | collectTypeTagsFromTuple<typename type::InheritsFrom>(collector, int{depth+1}, i); | ||
103 | }); | ||
104 | } | ||
105 | |||
106 | } // end namespace Detail | ||
107 | |||
108 | /*! | ||
109 | * \ingroup Core | ||
110 | * \brief Class to collect metadata | ||
111 | */ | ||
112 |
1/2✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
|
66 | class Collector |
113 | { | ||
114 | |||
115 | using JsonTree = Dumux::Json::JsonTree; | ||
116 | |||
117 | public: | ||
118 | /*! | ||
119 | * \brief Get the json tree | ||
120 | */ | ||
121 | JsonTree& getTree() | ||
122 | { | ||
123 | 59 | return tree_; | |
124 | } | ||
125 | |||
126 | const JsonTree& getTree() const | ||
127 | { | ||
128 | 21 | return tree_; | |
129 | } | ||
130 | |||
131 | /*! | ||
132 | * \brief Merges two trees by overwriting existing values | ||
133 | */ | ||
134 | void merge(const Collector& collector) | ||
135 | { | ||
136 | this->getTree().merge_patch(collector.getTree()); | ||
137 | } | ||
138 | |||
139 | /*! | ||
140 | * \brief Append data from another collector | ||
141 | * \param collector The json collector from which data is taken | ||
142 | * \param convertToArrays Convert non-array types to array which allows appending data | ||
143 | */ | ||
144 | void append(const Collector& collector, bool convertToArrays = false) | ||
145 | { | ||
146 | const auto& tree = collector.getTree(); | ||
147 | for (const auto& [key, values] : tree.items()) | ||
148 | { | ||
149 | auto& dataAtKey = this->getTree()[key]; | ||
150 | if(dataAtKey.is_array()) | ||
151 | { | ||
152 | if(values.is_array()) | ||
153 | dataAtKey.insert(dataAtKey.end(), values.begin(), values.end()); | ||
154 | else | ||
155 | dataAtKey.push_back(values); | ||
156 | } | ||
157 | else if(dataAtKey.is_null()) | ||
158 | { | ||
159 | dataAtKey = values; | ||
160 | } | ||
161 | else if(convertToArrays) | ||
162 | { | ||
163 | // convert to array and append data | ||
164 | auto val(dataAtKey); | ||
165 | dataAtKey = JsonTree::array({val}); | ||
166 | if(values.is_array()) | ||
167 | dataAtKey.insert(dataAtKey.end(), values.begin(), values.end()); | ||
168 | else | ||
169 | dataAtKey.push_back(values); | ||
170 | } | ||
171 | else | ||
172 | DUNE_THROW(Dune::InvalidStateException, "Unclear how to append data without conversion to array!"); | ||
173 | } | ||
174 | } | ||
175 | |||
176 | /*! | ||
177 | * \brief returns the object with id of the json tree | ||
178 | */ | ||
179 | auto& operator[] (const std::string& id) | ||
180 |
11/22✓ Branch 1 taken 21 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 21 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 1 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 1 times.
✗ Branch 11 not taken.
✓ Branch 13 taken 1 times.
✗ Branch 14 not taken.
✓ Branch 16 taken 1 times.
✗ Branch 17 not taken.
✓ Branch 19 taken 1 times.
✗ Branch 20 not taken.
✓ Branch 22 taken 1 times.
✗ Branch 23 not taken.
✓ Branch 25 taken 1 times.
✗ Branch 26 not taken.
✓ Branch 28 taken 1 times.
✗ Branch 29 not taken.
✓ Branch 31 taken 1 times.
✗ Branch 32 not taken.
|
51 | { return getTree()[id]; } |
181 | |||
182 | template <class T> | ||
183 | 1 | static std::string className(const T& c, bool hideTemplates) | |
184 | { | ||
185 |
4/12✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 1 times.
✗ Branch 7 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✓ Branch 12 taken 1 times.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
|
2 | return hideTemplates ? hideTemplateArguments(Dune::className(c)) : Dune::className(c); |
186 | } | ||
187 | |||
188 | template <class T> | ||
189 | static std::string className(bool hideTemplates) | ||
190 | { | ||
191 | return hideTemplates ? hideTemplateArguments(Dune::className<T>()) : Dune::className<T>(); | ||
192 | } | ||
193 | |||
194 | 1 | static std::string hideTemplateArguments(std::string&& s) | |
195 | { | ||
196 | 1 | std::size_t first = s.find("<"); | |
197 | 1 | std::size_t last = s.find_last_of(">"); | |
198 | |||
199 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if(first != std::string::npos && last != std::string::npos) |
200 | ✗ | s.replace(first, last-first+1, "<...>"); | |
201 | |||
202 | 1 | s.erase(std::unique(std::begin(s), std::end(s), | |
203 |
3/4✓ Branch 7 taken 1 times.
✓ Branch 8 taken 15 times.
✓ Branch 9 taken 1 times.
✗ Branch 10 not taken.
|
21 | [](unsigned char a, unsigned char b){return std::isspace(a) && std::isspace(b);}), std::end(s)); |
204 | |||
205 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | return std::move(s); |
206 | } | ||
207 | |||
208 | private: | ||
209 | JsonTree tree_; | ||
210 | }; | ||
211 | |||
212 | //! convenience function to check if file exists | ||
213 | 20 | bool jsonFileExists(const std::string& fileName) | |
214 | { | ||
215 |
1/2✓ Branch 2 taken 20 times.
✗ Branch 3 not taken.
|
20 | std::ifstream infile(fileName + ".json"); |
216 | 40 | return infile.good(); | |
217 | } | ||
218 | |||
219 | //! reads a json file into a tree | ||
220 | template<class Collector> | ||
221 | 16 | void readJsonFile(Collector& collector, const std::string& fileName) | |
222 | { | ||
223 |
1/2✓ Branch 2 taken 16 times.
✗ Branch 3 not taken.
|
32 | std::ifstream i(fileName + ".json"); |
224 |
1/2✓ Branch 1 taken 16 times.
✗ Branch 2 not taken.
|
16 | i >> collector.getTree(); |
225 | 16 | } | |
226 | |||
227 | //! writes a json tree to file | ||
228 | template<class Collector> | ||
229 | 21 | void writeJsonFile(const Collector& collector, const std::string& fileName) | |
230 | { | ||
231 |
1/2✓ Branch 2 taken 21 times.
✗ Branch 3 not taken.
|
21 | std::ofstream o(fileName + ".json"); |
232 |
4/8✓ Branch 1 taken 21 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 21 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 21 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 21 times.
✗ Branch 11 not taken.
|
63 | o << std::setw(4) << collector.getTree() << std::endl; |
233 | 21 | } | |
234 | |||
235 | //! prints json tree | ||
236 | template<class Collector> | ||
237 | void print(const Collector& collector) | ||
238 | { | ||
239 | std::cout << collector.getTree().dump(4) << std::endl; | ||
240 | } | ||
241 | |||
242 | template<class Collector, class TypeTag, DiffMethod diffmethod, bool isImplicit> | ||
243 | void collectMetaData(Collector& collector, const FVAssembler<TypeTag, diffmethod, isImplicit>& a, bool hideTemplates = true) | ||
244 | { | ||
245 | auto& obj = collector["Assembler"]; | ||
246 | obj["Type"] = Collector::className(a, hideTemplates); | ||
247 | obj["Stationary"] = a.isStationaryProblem(); | ||
248 | } | ||
249 | |||
250 | template<class Collector, class GridGeometry> | ||
251 | auto collectMetaData(Collector& collector, const GridGeometry& gg, bool hideTemplates = true) | ||
252 | -> typename std::enable_if_t<Dune::models<Concept::GridGeometry, GridGeometry>()> | ||
253 | { | ||
254 | auto& obj = collector["GridGeometry"]; | ||
255 | obj["Type"] = Collector::className(gg, hideTemplates); | ||
256 | obj["IsPeriodic"] = gg.isPeriodic(); | ||
257 | obj["DiscretizationMethod"] = GridGeometry::discMethod.name(); | ||
258 | obj["NumScvs"] = gg.numScv(); | ||
259 | obj["NumScvfs"] = gg.numScvf(); | ||
260 | obj["NumBoundaryScvfs"] = gg.numBoundaryScvf(); | ||
261 | obj["NumDofs"] = gg.numDofs(); | ||
262 | } | ||
263 | |||
264 | template<class Collector, class GridVariables> | ||
265 | auto collectMetaData(Collector& collector, const GridVariables& gv, bool hideTemplates = true) | ||
266 | -> typename std::enable_if_t<Dune::models<Concept::GridVariables, GridVariables>()> | ||
267 | { | ||
268 | auto& obj = collector["GridVariables"]; | ||
269 | obj["Type"] = Collector::className(gv, hideTemplates); | ||
270 | obj["GridVolumeVariables"]["Type"] = Collector::template className<typename GridVariables::GridVolumeVariables>(hideTemplates); | ||
271 | obj["VolumeVariables"]["Type"] = Collector::template className<typename GridVariables::VolumeVariables>(hideTemplates); | ||
272 | obj["GridFluxVariablesCache"]["Type"] = Collector::template className<typename GridVariables::GridFluxVariablesCache>(hideTemplates); | ||
273 | } | ||
274 | |||
275 | template<class Collector, class GridView> | ||
276 | auto collectMetaData(Collector& collector, const GridView& gridView, bool hideTemplates = true) | ||
277 | -> typename std::enable_if_t<Dune::models<Concept::GridView, GridView>()> | ||
278 | { | ||
279 | auto& obj = collector["GridView"]; | ||
280 | obj["Type"] = Collector::className(gridView, hideTemplates); | ||
281 | obj["dimension"] = GridView::dimension; | ||
282 | obj["dimensionWorld"] = GridView::dimensionworld; | ||
283 | obj["conforming"] = GridView::conforming; | ||
284 | //obj["Grid"]["Type"] = Collector::className(gridView.grid(), hideTemplates); | ||
285 | for(int codim = 0; codim < GridView::dimension; ++codim) | ||
286 | obj["numEntities"]["codim " + std::to_string(codim) ] = gridView.size(codim); | ||
287 | |||
288 | // TODO parallel runs, i.e. overlapSize() etc. | ||
289 | } | ||
290 | |||
291 | template<class TypeTag, class Collector> | ||
292 | auto collectTypeTags(Collector& collector) | ||
293 | { | ||
294 | auto& obj = collector["TTags"]; | ||
295 | obj = Dumux::Json::JsonTree::array(); | ||
296 | Detail::collectTypeTagsFromTuple<std::tuple<TypeTag>>(obj); | ||
297 | } | ||
298 | |||
299 | } // end namespace Dumux::MetaData | ||
300 | |||
301 | #endif | ||
302 |