GCC Code Coverage Report


Directory: ../../../builds/dumux-repositories/
File: /builds/dumux-repositories/dumux/dumux/io/pointcloudvtkwriter.hh
Date: 2024-05-04 19:09:25
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 76 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 87 times.
✓ Branch 16 taken 1 times.
✗ Branch 17 not taken.
✓ Branch 18 taken 87 times.
✗ Branch 19 not taken.
✗ Branch 23 not taken.
✗ Branch 24 not taken.
✗ Branch 26 not taken.
✗ Branch 27 not taken.
175 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 350 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 350 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 175 return data_.begin();
90 }
91
92 decltype(auto) end() const
93 {
94 175 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.
228 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 88 void write(const std::string& name, Dune::VTK::OutputType type = Dune::VTK::ascii)
127 {
128
4/10
✓ Branch 1 taken 88 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 88 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 88 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 88 times.
✗ Branch 11 not taken.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
264 auto filename = getSerialPieceName(name, "");
129
130
2/4
✓ Branch 1 taken 88 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 88 times.
✗ Branch 5 not taken.
176 std::ofstream file;
131
1/2
✓ Branch 1 taken 88 times.
✗ Branch 2 not taken.
88 file.open(filename);
132
1/2
✓ Branch 1 taken 88 times.
✗ Branch 2 not taken.
88 writeHeader_(file);
133
1/2
✓ Branch 1 taken 88 times.
✗ Branch 2 not taken.
88 writeCoordinates_(file, coordinates_);
134
1/2
✓ Branch 1 taken 88 times.
✗ Branch 2 not taken.
88 writeDataInfo_(file);
135
136
3/4
✓ Branch 0 taken 87 times.
✓ Branch 1 taken 88 times.
✓ Branch 3 taken 87 times.
✗ Branch 4 not taken.
351 for (auto&& data : scalarPointData_)
137
1/2
✓ Branch 1 taken 87 times.
✗ Branch 2 not taken.
87 writeData_(file, data);
138
139
3/4
✓ Branch 0 taken 88 times.
✓ Branch 1 taken 88 times.
✓ Branch 3 taken 88 times.
✗ Branch 4 not taken.
352 for (auto&& data :vectorPointData_)
140
1/2
✓ Branch 1 taken 88 times.
✗ Branch 2 not taken.
88 writeData_(file, data);
141
142
6/8
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 87 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 87 times.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 1 times.
✗ Branch 7 not taken.
176 if (!scalarPointData_.empty() || !vectorPointData_.empty())
143
1/2
✓ Branch 1 taken 88 times.
✗ Branch 2 not taken.
88 file << "</PointData>\n";
144
145
1/2
✓ Branch 1 taken 88 times.
✗ Branch 2 not taken.
88 file << "</Piece>\n";
146
1/2
✓ Branch 1 taken 88 times.
✗ Branch 2 not taken.
88 file << "</PolyData>\n";
147
1/2
✓ Branch 1 taken 88 times.
✗ Branch 2 not taken.
88 file << "</VTKFile>";
148
149 88 clear();
150
1/2
✓ Branch 1 taken 88 times.
✗ Branch 2 not taken.
88 file.close();
151 88 }
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 87 void addPointData(const std::vector<Scalar>& v, const std::string &name)
181 {
182
3/6
✗ Branch 0 not taken.
✓ Branch 1 taken 87 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 87 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 87 times.
261 assert(v.size() == coordinates_.size());
183
2/6
✓ Branch 2 taken 87 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 87 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
87 scalarPointData_.push_back(ScalarFunction(v, name, 1));
184 87 }
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 88 void addPointData(const std::vector<DimWorldVector>& v, const std::string &name)
193 {
194
3/6
✗ Branch 0 not taken.
✓ Branch 1 taken 88 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 88 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 88 times.
264 assert(v.size() == coordinates_.size());
195
2/6
✓ Branch 2 taken 88 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 88 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
88 vectorPointData_.push_back(VectorFunction(v, name, 3));
196 88 }
197
198 /*!
199 * \brief Clears the data lists
200 */
201 88 void clear()
202 {
203 88 scalarPointData_.clear();
204 88 vectorPointData_.clear();
205 88 }
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 1148 std::string getSerialPieceName(const std::string& name,
219 const std::string& path) const
220 {
221
5/8
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 1144 times.
✓ Branch 3 taken 4 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 4 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 4 times.
✗ Branch 10 not taken.
1148 static const std::string extension = ".vtp";
222
223
2/6
✓ Branch 2 taken 1148 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1148 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
2296 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 88 void writeHeader_(std::ostream& file)
260 {
261 176 std::string header = "<?xml version=\"1.0\"?>\n";
262
1/2
✓ Branch 1 taken 88 times.
✗ Branch 2 not taken.
88 header += "<VTKFile type=\"PolyData\" version=\"0.1\" byte_order=\"LittleEndian\">\n";
263
1/2
✓ Branch 1 taken 88 times.
✗ Branch 2 not taken.
88 header += "<PolyData>\n";
264
8/24
✓ Branch 1 taken 88 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 88 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 88 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 88 times.
✗ Branch 11 not taken.
✓ Branch 13 taken 88 times.
✗ Branch 14 not taken.
✓ Branch 15 taken 88 times.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
✓ Branch 18 taken 88 times.
✗ Branch 19 not taken.
✓ Branch 20 taken 88 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.
264 header += "<Piece NumberOfLines=\"0\" NumberOfPoints=\"" + std::to_string(coordinates_.size()) + "\">\n";
265
2/4
✓ Branch 1 taken 88 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 88 times.
✗ Branch 4 not taken.
88 file << header;
266 88 }
267
268 /*!
269 * \brief Writes information about the data to the file
270 */
271 88 void writeDataInfo_(std::ostream& file)
272 {
273
0/2
✗ Branch 0 not taken.
✗ Branch 1 not taken.
176 std::string scalarName;
274
2/6
✗ Branch 0 not taken.
✓ Branch 1 taken 88 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 88 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
176 std::string vectorName;
275 88 bool foundScalar = false;
276 88 bool foundVector = false;
277
278
3/4
✓ Branch 0 taken 87 times.
✓ Branch 1 taken 88 times.
✓ Branch 2 taken 87 times.
✗ Branch 3 not taken.
351 for(auto&& data : scalarPointData_)
279 {
280
2/4
✓ Branch 0 taken 87 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 87 times.
✗ Branch 3 not taken.
87 if(data.numComponents() == 1 && !foundScalar)
281 {
282
1/2
✓ Branch 1 taken 87 times.
✗ Branch 2 not taken.
87 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 88 times.
✓ Branch 1 taken 88 times.
✓ Branch 2 taken 88 times.
✗ Branch 3 not taken.
352 for(auto&& data : vectorPointData_)
295 {
296
2/4
✓ Branch 0 taken 88 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 88 times.
✗ Branch 3 not taken.
88 if(data.numComponents() > 1 && !foundVector)
297 {
298
1/2
✓ Branch 1 taken 88 times.
✗ Branch 2 not taken.
88 vectorName = data.name();
299 foundVector = true;
300 }
301 }
302
303
2/2
✓ Branch 0 taken 87 times.
✓ Branch 1 taken 1 times.
88 if(foundScalar)
304
1/2
✓ Branch 0 taken 87 times.
✗ Branch 1 not taken.
87 if(foundVector)
305
3/6
✓ Branch 2 taken 87 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 87 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 87 times.
✗ Branch 10 not taken.
261 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 88 void writeCoordinates_(std::ostream& file, const std::vector<GlobalPosition>& positions)
321 {
322 // write the positions to the file
323 88 file << "<Points>\n";
324 88 file << "<DataArray type=\"Float32\" Name=\"Coordinates\" NumberOfComponents=\"3\" format=\"ascii\">\n";
325 88 int counter = 0;
326
4/4
✓ Branch 0 taken 50455 times.
✓ Branch 1 taken 88 times.
✓ Branch 2 taken 50455 times.
✓ Branch 3 taken 88 times.
50719 for(auto&& x : positions)
327 {
328 50455 file << x ;
329
330 if(x.size() == 1)
331 file << " 0 0 ";
332 if(x.size() == 2)
333 50455 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 3100 times.
✓ Branch 1 taken 47355 times.
50455 if((++counter) > numBeforeLineBreak)
339 {
340 3100 file << std::endl;
341 counter = 0;
342 }
343 }
344 88 file << "\n</DataArray>\n";
345 88 file << "</Points>\n";
346 88 }
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 350 void writeData_(std::ostream& file, const T& data)
356 {
357 1050 file << "<DataArray type=\"Float32\" Name=\"" << data.name() << "\" NumberOfComponents=\"" << data.numComponents() << "\" format=\"ascii\">\n";
358 350 int counter = 0;
359
4/4
✓ Branch 0 taken 100510 times.
✓ Branch 1 taken 175 times.
✓ Branch 2 taken 100510 times.
✓ Branch 3 taken 175 times.
202070 for(auto&& value : data)
360 {
361 // forward to specialized function
362 402040 writeToFile_(file, value);
363
364 // introduce a line break after a certain time
365
2/2
✓ Branch 0 taken 6175 times.
✓ Branch 1 taken 94335 times.
201020 if((++counter) > numBeforeLineBreak)
366 {
367 12350 file << std::endl;
368 counter = 0;
369 }
370 }
371 350 file << "\n</DataArray>\n";
372 350 }
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 50055 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 50455 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