GCC Code Coverage Report


Directory: ../../../builds/dumux-repositories/
File: /builds/dumux-repositories/dumux/dumux/io/pointcloudvtkwriter.hh
Date: 2024-09-21 20:52:54
Exec Total Coverage
Lines: 87 111 78.4%
Functions: 10 20 50.0%
Branches: 99 266 37.2%

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 InputOutput
10 * \brief A VTK writer specialized for staggered grid implementations with dofs on the faces
11 */
12 #ifndef DUMUX_POINTCLOUD_VTK_WRITER_HH
13 #define DUMUX_POINTCLOUD_VTK_WRITER_HH
14
15 #include <string>
16 #include <vector>
17 #include <list>
18 #include <fstream>
19 #include <iomanip>
20
21 #include <dune/common/fvector.hh>
22 #include <dune/common/exceptions.hh>
23 #include <dune/common/path.hh>
24 #include <dune/grid/io/file/vtk/common.hh>
25
26 namespace Dumux {
27
28 /*!
29 * \ingroup InputOutput
30 * \brief A VTK output module to simplify writing dumux simulation data to VTK format
31 *
32 * Handles the output of scalar and vector fields to VTK formatted file for multiple
33 * variables and timesteps. Certain predefined fields can be registered on problem / model
34 * initialization and/or be turned on/off using the designated properties. Additionally
35 * non-standardized scalar and vector fields can be added to the writer manually.
36 */
37 template<class Scalar, class GlobalPosition>
38 51 class PointCloudVtkWriter
39 {
40 // GlobalPosition is used for the point coordinates, DimWorldVector for the actual data.
41 // GlobalPosition's ctype does not necessarily equal Scalar.
42 using DimWorldVector = Dune::FieldVector<Scalar, GlobalPosition::size()>;
43
44 static constexpr unsigned int precision = 6;
45 static constexpr unsigned int numBeforeLineBreak = 15;
46
47 /*!
48 * \brief A class holding a data container and additional information
49 */
50 template<class ContainerType>
51
3/24
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✓ Branch 15 taken 63 times.
✓ Branch 16 taken 1 times.
✗ Branch 17 not taken.
✓ Branch 18 taken 63 times.
✗ Branch 19 not taken.
✗ Branch 23 not taken.
✗ Branch 24 not taken.
✗ Branch 26 not taken.
✗ Branch 27 not taken.
127 class VTKFunction
52 {
53 public:
54 /*!
55 * \brief A class holding a data container and additional information
56 *
57 * \param data The data container
58 * \param name The name of the data set
59 * \param numComponents The number of components of the data set
60 */
61 254 VTKFunction(const ContainerType& data, const std::string& name, const int numComponents) : data_(data), name_(name), numComponents_(numComponents)
62 {}
63
64 /*!
65 * \brief Returns the name of the data set
66 */
67 const std::string& name() const
68 {
69 254 return name_;
70 }
71
72 /*!
73 * \brief Returns the number of components of the data set
74 */
75 int numComponents() const
76 {
77 return numComponents_;
78 }
79
80 /*!
81 * \brief Allows random access to data
82 *
83 * \param idx The index
84 */
85 auto& operator() (const int idx) const { return data_[idx]; }
86
87 decltype(auto) begin() const
88 {
89 127 return data_.begin();
90 }
91
92 decltype(auto) end() const
93 {
94 127 return data_.end();
95 }
96
97 /*!
98 * \brief Returns the size of the data container
99 */
100 int size() const
101 {
102 return data_.size();
103 }
104
105 private:
106 const ContainerType& data_;
107 const std::string name_;
108 const int numComponents_;
109 };
110
111
112 public:
113 using ScalarFunction = VTKFunction<std::vector<Scalar>>;
114 using VectorFunction = VTKFunction<std::vector<DimWorldVector>>;
115
116
117
3/6
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 1 times.
✗ Branch 8 not taken.
153 PointCloudVtkWriter(const std::vector<GlobalPosition>& coordinates) : coordinates_(coordinates)
118 {}
119
120 /*!
121 * \brief Create an output file
122 *
123 * \param name The base name
124 * \param type The output type
125 */
126 64 void write(const std::string& name, Dune::VTK::OutputType type = Dune::VTK::ascii)
127 {
128
4/10
✓ Branch 1 taken 64 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 64 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 64 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 64 times.
✗ Branch 11 not taken.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
192 auto filename = getSerialPieceName(name, "");
129
130
2/4
✓ Branch 1 taken 64 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 64 times.
✗ Branch 5 not taken.
128 std::ofstream file;
131
1/2
✓ Branch 1 taken 64 times.
✗ Branch 2 not taken.
64 file.open(filename);
132
1/2
✓ Branch 1 taken 64 times.
✗ Branch 2 not taken.
64 writeHeader_(file);
133
1/2
✓ Branch 1 taken 64 times.
✗ Branch 2 not taken.
64 writeCoordinates_(file, coordinates_);
134
1/2
✓ Branch 1 taken 64 times.
✗ Branch 2 not taken.
64 writeDataInfo_(file);
135
136
3/4
✓ Branch 0 taken 63 times.
✓ Branch 1 taken 64 times.
✓ Branch 3 taken 63 times.
✗ Branch 4 not taken.
255 for (auto&& data : scalarPointData_)
137
1/2
✓ Branch 1 taken 63 times.
✗ Branch 2 not taken.
63 writeData_(file, data);
138
139
3/4
✓ Branch 0 taken 64 times.
✓ Branch 1 taken 64 times.
✓ Branch 3 taken 64 times.
✗ Branch 4 not taken.
256 for (auto&& data :vectorPointData_)
140
1/2
✓ Branch 1 taken 64 times.
✗ Branch 2 not taken.
64 writeData_(file, data);
141
142
6/8
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 63 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 63 times.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 1 times.
✗ Branch 7 not taken.
128 if (!scalarPointData_.empty() || !vectorPointData_.empty())
143
1/2
✓ Branch 1 taken 64 times.
✗ Branch 2 not taken.
64 file << "</PointData>\n";
144
145
1/2
✓ Branch 1 taken 64 times.
✗ Branch 2 not taken.
64 file << "</Piece>\n";
146
1/2
✓ Branch 1 taken 64 times.
✗ Branch 2 not taken.
64 file << "</PolyData>\n";
147
1/2
✓ Branch 1 taken 64 times.
✗ Branch 2 not taken.
64 file << "</VTKFile>";
148
149 64 clear();
150
1/2
✓ Branch 1 taken 64 times.
✗ Branch 2 not taken.
64 file.close();
151 64 }
152
153 /*!
154 * \brief Create an output file in parallel
155 *
156 * \param name Base name of the output files. This should not
157 * contain any directory part and not filename
158 * extensions. It will be used both for each processes
159 * piece as well as the parallel collection file
160 * \param path Directory where to put the parallel collection
161 * (.pvtu/.pvtp) file. If it is relative, it is taken
162 * relative to the current directory
163 * \param extendpath Directory where to put the piece file (.vtu/.vtp) of
164 * this process. If it is relative, it is taken
165 * relative to the directory denoted by path
166 * \param type How to encode the data in the file
167 */
168 void pwrite(const std::string & name, const std::string & path, const std::string & extendpath,
169 Dune::VTK::OutputType type = Dune::VTK::ascii)
170 {
171 DUNE_THROW(Dune::NotImplemented, "parallel point cloud vtk output not supported yet");
172 }
173
174 /*!
175 * \brief Add a vector of scalar data that live on arbitrary points to the visualization.
176 *
177 * \param v The vector containing the data
178 * \param name The name of the data set
179 */
180 63 void addPointData(const std::vector<Scalar>& v, const std::string &name)
181 {
182
3/6
✗ Branch 0 not taken.
✓ Branch 1 taken 63 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 63 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 63 times.
189 assert(v.size() == coordinates_.size());
183
2/6
✓ Branch 2 taken 63 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 63 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
63 scalarPointData_.push_back(ScalarFunction(v, name, 1));
184 63 }
185
186 /*!
187 * \brief Add a vector of vector data that live on arbitrary points to the visualization.
188 *
189 * \param v The vector containing the data
190 * \param name The name of the data set
191 */
192 64 void addPointData(const std::vector<DimWorldVector>& v, const std::string &name)
193 {
194
3/6
✗ Branch 0 not taken.
✓ Branch 1 taken 64 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 64 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 64 times.
192 assert(v.size() == coordinates_.size());
195
2/6
✓ Branch 2 taken 64 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 64 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
64 vectorPointData_.push_back(VectorFunction(v, name, 3));
196 64 }
197
198 /*!
199 * \brief Clears the data lists
200 */
201 64 void clear()
202 {
203 64 scalarPointData_.clear();
204 64 vectorPointData_.clear();
205 64 }
206
207 /*!
208 * \brief Return name of a serial header file
209 *
210 * \param name Base name of the VTK output. This should be without
211 * any directory parts and without a filename extension.
212 * \param path Directory part of the resulting header name. May be
213 * empty, in which case the resulting name will not have a
214 * directory part. If non-empty, may or may not have a
215 * trailing '/'. If a trailing slash is missing, one is
216 * appended implicitly.
217 */
218 1100 std::string getSerialPieceName(const std::string& name,
219 const std::string& path) const
220 {
221
5/8
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 1097 times.
✓ Branch 3 taken 3 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 3 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 3 times.
✗ Branch 10 not taken.
1100 static const std::string extension = ".vtp";
222
223
2/6
✓ Branch 2 taken 1100 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1100 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
2200 return Dune::concatPaths(path, name+extension);
224 }
225
226 /*!
227 * \brief Return name of a parallel header file
228 *
229 * \param name Base name of the VTK output. This should be without
230 * any directory parts and without a filename extension.
231 * \param path Directory part of the resulting header name. May be
232 * empty, in which case the resulting name will not have a
233 * directory part. If non-empty, may or may not have a
234 * trailing '/'. If a trailing slash is missing, one is
235 * appended implicitly.
236 * \param commSize Number of processes writing a parallel vtk output.
237 */
238 std::string getParallelHeaderName(const std::string& name,
239 const std::string& path,
240 int commSize) const
241 {
242 std::ostringstream s;
243 if(path.size() > 0) {
244 s << path;
245 if(path[path.size()-1] != '/')
246 s << '/';
247 }
248 s << 's' << std::setw(4) << std::setfill('0') << commSize << '-';
249 s << name;
250 s << ".pvtp";
251 return s.str();
252 }
253
254
255 private:
256 /*!
257 * \brief Writes the header to the file
258 */
259 64 void writeHeader_(std::ostream& file)
260 {
261 128 std::string header = "<?xml version=\"1.0\"?>\n";
262
1/2
✓ Branch 1 taken 64 times.
✗ Branch 2 not taken.
64 header += "<VTKFile type=\"PolyData\" version=\"0.1\" byte_order=\"LittleEndian\">\n";
263
1/2
✓ Branch 1 taken 64 times.
✗ Branch 2 not taken.
64 header += "<PolyData>\n";
264
8/24
✓ Branch 1 taken 64 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 64 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 64 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 64 times.
✗ Branch 11 not taken.
✓ Branch 13 taken 64 times.
✗ Branch 14 not taken.
✓ Branch 15 taken 64 times.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
✓ Branch 18 taken 64 times.
✗ Branch 19 not taken.
✓ Branch 20 taken 64 times.
✗ Branch 21 not taken.
✗ Branch 22 not taken.
✗ Branch 23 not taken.
✗ Branch 24 not taken.
✗ Branch 25 not taken.
✗ Branch 26 not taken.
✗ Branch 27 not taken.
✗ Branch 28 not taken.
192 header += "<Piece NumberOfLines=\"0\" NumberOfPoints=\"" + std::to_string(coordinates_.size()) + "\">\n";
265
2/4
✓ Branch 1 taken 64 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 64 times.
✗ Branch 4 not taken.
64 file << header;
266 64 }
267
268 /*!
269 * \brief Writes information about the data to the file
270 */
271 64 void writeDataInfo_(std::ostream& file)
272 {
273
0/2
✗ Branch 0 not taken.
✗ Branch 1 not taken.
128 std::string scalarName;
274
2/6
✗ Branch 0 not taken.
✓ Branch 1 taken 64 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 64 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
128 std::string vectorName;
275 64 bool foundScalar = false;
276 64 bool foundVector = false;
277
278
3/4
✓ Branch 0 taken 63 times.
✓ Branch 1 taken 64 times.
✓ Branch 2 taken 63 times.
✗ Branch 3 not taken.
255 for(auto&& data : scalarPointData_)
279 {
280
2/4
✓ Branch 0 taken 63 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 63 times.
✗ Branch 3 not taken.
63 if(data.numComponents() == 1 && !foundScalar)
281 {
282
1/2
✓ Branch 1 taken 63 times.
✗ Branch 2 not taken.
63 scalarName = data.name();
283 foundScalar = true;
284 continue;
285 }
286
287 if(data.numComponents() > 1 && !foundVector)
288 {
289 vectorName = data.name();
290 foundVector = true;
291 }
292 }
293
294
3/4
✓ Branch 0 taken 64 times.
✓ Branch 1 taken 64 times.
✓ Branch 2 taken 64 times.
✗ Branch 3 not taken.
256 for(auto&& data : vectorPointData_)
295 {
296
2/4
✓ Branch 0 taken 64 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 64 times.
✗ Branch 3 not taken.
64 if(data.numComponents() > 1 && !foundVector)
297 {
298
1/2
✓ Branch 1 taken 64 times.
✗ Branch 2 not taken.
64 vectorName = data.name();
299 foundVector = true;
300 }
301 }
302
303
2/2
✓ Branch 0 taken 63 times.
✓ Branch 1 taken 1 times.
64 if(foundScalar)
304
1/2
✓ Branch 0 taken 63 times.
✗ Branch 1 not taken.
63 if(foundVector)
305
3/6
✓ Branch 2 taken 63 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 63 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 63 times.
✗ Branch 10 not taken.
189 file << "<PointData Scalars=\"" << scalarName << "\" Vectors=\"" << vectorName <<"\">\n";
306 else
307 file << "<PointData Scalars=\"" << scalarName << "\">\n";
308
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 else if(foundVector)
309
2/4
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 1 times.
✗ Branch 6 not taken.
2 file << "<PointData Vectors=\"" << vectorName << "\">\n";
310 else
311 return;
312 }
313
314 /*!
315 * \brief Writes the coordinates to the file
316 *
317 * \param file The output file
318 * \param positions Container to store the positions
319 */
320 64 void writeCoordinates_(std::ostream& file, const std::vector<GlobalPosition>& positions)
321 {
322 // write the positions to the file
323 64 file << "<Points>\n";
324 64 file << "<DataArray type=\"Float32\" Name=\"Coordinates\" NumberOfComponents=\"3\" format=\"ascii\">\n";
325 64 int counter = 0;
326
4/4
✓ Branch 0 taken 49015 times.
✓ Branch 1 taken 64 times.
✓ Branch 2 taken 49015 times.
✓ Branch 3 taken 64 times.
49207 for(auto&& x : positions)
327 {
328 49015 file << x ;
329
330 if(x.size() == 1)
331 file << " 0 0 ";
332 if(x.size() == 2)
333 49015 file << " 0 ";
334 if(x.size() == 3)
335 file << " ";
336
337 // introduce a line break after a certain time
338
2/2
✓ Branch 0 taken 3028 times.
✓ Branch 1 taken 45987 times.
49015 if((++counter) > numBeforeLineBreak)
339 {
340 3028 file << std::endl;
341 counter = 0;
342 }
343 }
344 64 file << "\n</DataArray>\n";
345 64 file << "</Points>\n";
346 64 }
347
348 /*!
349 * \brief Writes data to the file
350 *
351 * \param file The output file
352 * \param data The data container which hold the data itself, as well as the name of the data set and the number of its components
353 */
354 template<class T>
355 254 void writeData_(std::ostream& file, const T& data)
356 {
357 762 file << "<DataArray type=\"Float32\" Name=\"" << data.name() << "\" NumberOfComponents=\"" << data.numComponents() << "\" format=\"ascii\">\n";
358 254 int counter = 0;
359
4/4
✓ Branch 0 taken 97630 times.
✓ Branch 1 taken 127 times.
✓ Branch 2 taken 97630 times.
✓ Branch 3 taken 127 times.
196022 for(auto&& value : data)
360 {
361 // forward to specialized function
362 390520 writeToFile_(file, value);
363
364 // introduce a line break after a certain time
365
2/2
✓ Branch 0 taken 6031 times.
✓ Branch 1 taken 91599 times.
195260 if((++counter) > numBeforeLineBreak)
366 {
367 12062 file << std::endl;
368 counter = 0;
369 }
370 }
371 254 file << "\n</DataArray>\n";
372 254 }
373
374 /*!
375 * \brief Writes a scalar to the file
376 *
377 * \param file The output file
378 * \param s The scalar
379 */
380 void writeToFile_(std::ostream& file, const Scalar& s)
381 {
382 48615 file << s << " ";
383 }
384
385 /*!
386 * \brief Writes a vector to the file
387 *
388 * \param file The output file
389 * \param g The vector
390 */
391 void writeToFile_(std::ostream& file, const DimWorldVector& g)
392 {
393 assert(g.size() > 1 && g.size() < 4);
394 if(g.size() < 3)
395 49015 file << g << " 0 ";
396 else
397 file << g << " ";
398 }
399
400 const std::vector<GlobalPosition>& coordinates_;
401 std::list<ScalarFunction> scalarPointData_;
402 std::list<VectorFunction> vectorPointData_;
403 };
404 } // end namespace Dumux
405
406 #endif
407