1/*
2 * VTKWriter_point_set.hpp
3 *
4 * Created on: Feb 6, 2016
5 * Author: i-bird
6 */
7
8#ifndef OPENFPM_IO_SRC_VTKWRITER_POINT_SET_HPP_
9#define OPENFPM_IO_SRC_VTKWRITER_POINT_SET_HPP_
10
11#include <cstddef>
12#include <boost/mpl/pair.hpp>
13#include "VTKWriter_grids_util.hpp"
14#include "is_vtk_writable.hpp"
15#include <string>
16#include "byteswap_portable.hpp"
17#include "MetaParser/MetaParser.hpp"
18
19/*! \brief Store a reference to the vector position
20 *
21 * \tparam Vps Type of vector that store the position of the particles
22 *
23 */
24template <typename Vps>
25class ele_vps
26{
27public:
28
29 //! type of vector that store the particle position
30 typedef Vps value_type;
31
32 //! particle position vector
33 const Vps & g;
34
35 //! ghost marker
36 size_t mark;
37
38 //! constructor
39 ele_vps(const Vps & g, size_t mark)
40 :g(g),mark(mark)
41 {}
42
43};
44
45/*! \brief Store a reference to the vector properties
46 *
47 * \tparam Vpp Type of vector that store the property of the particles
48 *
49 */
50template <typename Vpp>
51class ele_vpp
52{
53public:
54
55 //! type of vector that store the particle properties
56 typedef Vpp value_type;
57
58
59 //! Reference to the particle properties
60 const Vpp & g;
61
62 //! ghost marker
63 size_t mark;
64
65 //! constructor
66 ele_vpp(const Vpp & vpp, size_t mark)
67 :g(vpp),mark(mark)
68 {}
69
70};
71
72
73/*! \brief this class is a functor for "for_each" algorithm
74 *
75 * This class is a functor for "for_each" algorithm. For each
76 * element of the boost::vector the operator() is called.
77 * Is mainly used to produce an output for each property
78 *
79 * \tparam ele_v It is the class ele_v that store the couple vector of position and property
80 *
81 *
82 */
83template<typename ele_v, typename St>
84struct prop_out_v
85{
86 //! Binary or ASCII
87 file_type ft;
88
89 //! property output string
90 std::string & v_out;
91
92 //! vector that we are processing
93 const openfpm::vector_std< ele_v > & vv;
94
95 //! properties names
96 const openfpm::vector<std::string> & prop_names;
97
98 /*! \brief constructor
99 *
100 * \param v_out string to fill with the vertex properties
101 * \param vv vector we are processing
102 * \param ft ASCII or BINARY format
103 *
104 */
105 prop_out_v(std::string & v_out,
106 const openfpm::vector_std< ele_v > & vv,
107 const openfpm::vector<std::string> & prop_names,
108 file_type ft)
109 :ft(ft),v_out(v_out),vv(vv),prop_names(prop_names)
110 {};
111
112 /*! \brief It produce an output for each property
113 *
114 * \param t property id
115 *
116 */
117 template<typename T>
118 void operator()(T& t) const
119 {
120 typedef typename boost::mpl::at<typename ele_v::value_type::value_type::type,boost::mpl::int_<T::value>>::type ptype;
121 typedef typename std::remove_all_extents<ptype>::type base_ptype;
122
123 meta_prop<boost::mpl::int_<T::value> ,ele_v,St, ptype, is_vtk_writable<base_ptype>::value > m(vv,v_out,prop_names,ft);
124 }
125
126 void lastProp()
127 {
128 // Create point data properties
129 v_out += "SCALARS domain float\n";
130
131 // Default lookup table
132 v_out += "LOOKUP_TABLE default\n";
133
134 // Produce point data
135 for (size_t k = 0 ; k < vv.size() ; k++)
136 {
137 //! Get a vertex iterator
138 auto it = vv.get(k).g.getIterator();
139
140 // if there is the next element
141 while (it.isNext())
142 {
143 if (ft == file_type::ASCII)
144 {
145 if (it.get() < vv.get(k).mark)
146 v_out += "1.0\n";
147 else
148 v_out += "0.0\n";
149 }
150 else
151 {
152 if (it.get() < vv.get(k).mark)
153 {
154 float one = 1;
155 one = swap_endian_lt(one);
156 v_out.append((const char *)&one,sizeof(int));
157 }
158 else
159 {
160 float zero = 0;
161 zero = swap_endian_lt(zero);
162 v_out.append((const char *)&zero,sizeof(int));
163 }
164 }
165
166 // increment the iterator and counter
167 ++it;
168 }
169 }
170 }
171};
172
173/*!
174 *
175 * It write a VTK format file for a list of grids defined on a space
176 *
177 * \tparam boost::mpl::pair<G,S>
178 *
179 * where G is the type of the vector containing the properties, S is the
180 * type of vector containing the particle positions
181 *
182 */
183template <typename pair>
184class VTKWriter<pair,VECTOR_POINTS>
185{
186 //! Vector of position
187 openfpm::vector< ele_vps<typename pair::first >> vps;
188 //! Vector of properties
189 openfpm::vector< ele_vpp<typename pair::second>> vpp;
190
191 /*! \brief Get the total number of points
192 *
193 * \return the total number
194 *
195 */
196 size_t get_total()
197 {
198 size_t tot = 0;
199
200 //! Calculate the full number of vertices
201 for (size_t i = 0 ; i < vps.size() ; i++)
202 {
203 tot += vps.get(i).g.size();
204 }
205 return tot;
206 }
207
208 /*! \brief It get the vertex properties list
209 *
210 * It get the vertex properties list of the vertex defined as VTK header
211 *
212 * \return a string that define the vertex properties in graphML format
213 *
214 */
215 std::string get_vertex_properties_list()
216 {
217 //! vertex property output string
218 std::string v_out;
219
220 // write the number of vertex
221 v_out += "VERTICES " + std::to_string(get_total()) + " " + std::to_string(get_total() * 2) + "\n";
222
223 // return the vertex properties string
224 return v_out;
225 }
226
227 /*! \brief It get the point position header string
228 *
229 * It get the vertex position header of the vertex defined as a VTK header
230 *
231 * \return a string that define the vertex position format
232 *
233 */
234 std::string get_point_properties_list(file_type ft)
235 {
236 //! vertex property output string
237 std::string v_out;
238
239 // write the number of vertex
240
241 v_out += "POINTS " + std::to_string(get_total()) + " " + getType<typename pair::first::value_type::coord_type>() + "\n";
242
243 // return the vertex properties string
244 return v_out;
245 }
246
247 /*! \brief Create the VTK point list
248 *
249 * \param ft file_type
250 *
251 * \return the list of points
252 *
253 */
254 std::string get_point_list(file_type ft)
255 {
256 //! vertex node output string
257 std::stringstream v_out;
258
259 //! For each defined grid
260
261 for (size_t i = 0 ; i < vps.size() ; i++)
262 {
263 //! write the particle position
264 auto it = vps.get(i).g.getIterator();
265
266 // if there is the next element
267 while (it.isNext())
268 {
269 Point<pair::first::value_type::dims,typename pair::first::value_type::coord_type> p;
270 p = vps.get(i).g.get(it.get());
271
272 output_point<pair::first::value_type::dims,typename pair::first::value_type::coord_type>(p,v_out,ft);
273
274 // increment the iterator and counter
275 ++it;
276 }
277 }
278
279 //! In case of binary we have to add a new line at the end of the list
280 if (ft == file_type::BINARY)
281 v_out << std::endl;
282
283 // return the vertex list
284 return v_out.str();
285 }
286
287 /*! \brief Create the VTK vertex list
288 *
289 * \param ft file_type
290 *
291 * \return the list of vertices
292 *
293 */
294 std::string get_vertex_list(file_type ft)
295 {
296 // vertex node output string
297 std::string v_out;
298
299 size_t k = 0;
300
301 for (size_t i = 0 ; i < vps.size() ; i++)
302 {
303 //! For each grid point create a vertex
304 auto it = vps.get(i).g.getIterator();
305
306 while (it.isNext())
307 {
308 output_vertex(k,v_out,ft);
309
310 ++k;
311 ++it;
312 }
313 }
314
315 //! In case of binary we have to add a new line at the end of the list
316 if (ft == file_type::BINARY)
317 {v_out += "\n";}
318
319 // return the vertex list
320 return v_out;
321 }
322
323 /*! \brief Get the point data header
324 *
325 * \return a string with the point data header for VTK format
326 *
327 */
328 std::string get_point_data_header()
329 {
330 std::string v_out;
331
332 v_out += "POINT_DATA " + std::to_string(get_total()) + "\n";
333
334 return v_out;
335 }
336
337 /*! \brief return the meta data string
338 *
339 * \param meta_data string with the meta-data to add
340 *
341 */
342 std::string add_meta_data(std::string & meta_data, file_type & opt)
343 {
344 std::string meta_string;
345
346 // check for time metadata
347 MetaParser_options opts;
348 opts.add_options()
349 ("time", MetaParser_def::value<double>());
350
351 MetaParser mp(opts);
352 mp.parse(meta_data);
353
354 double time = 0.0;
355 bool exist = mp.getOption("time",time);
356
357 if (exist == true)
358 {
359 meta_string += "FIELD FieldData 1\n";
360 meta_string += "TIME 1 1 double\n";
361 if (opt == file_type::ASCII)
362 {meta_string += std::to_string(time);}
363 else
364 {
365 time = swap_endian_lt(time);
366 meta_string.append((const char *)&time,sizeof(double));
367 }
368 meta_string += "\n";
369 }
370
371 return meta_string;
372 }
373
374public:
375
376 /*!
377 *
378 * VTKWriter constructor
379 *
380 */
381 VTKWriter()
382 {}
383
384 /*! \brief Add a vector dataset
385 *
386 * \param vps vector of positions
387 * \param vpp vector of properties
388 * \param mark additional information that divide the dataset into 2 (in general is used to mark real from ghost information)
389 * \param opt_names optional parameter that indicate the names of the properties
390 *
391 */
392 void add(const typename pair::first & vps,
393 const typename pair::second & vpp,
394 size_t mark)
395 {
396 ele_vps<typename pair::first> t1(vps,mark);
397 ele_vpp<typename pair::second> t2(vpp,mark);
398
399 this->vps.add(t1);
400 this->vpp.add(t2);
401 }
402
403 /*! \brief It write a VTK file from a vector of points
404 *
405 * \tparam prp_out which properties to output [default = -1 (all)]
406 *
407 * \param file path where to write
408 * \param f_name name of the dataset
409 * \param prop_names properties names
410 * \param ft specify if it is a VTK BINARY or ASCII file [default = ASCII]
411 *
412 * \return true if the write complete successfully
413 *
414 */
415 template<int prp = -1> bool write(std::string file,
416 const openfpm::vector<std::string> & prop_names,
417 std::string f_name = "points" ,
418 std::string meta_data = "",
419 file_type ft = file_type::ASCII)
420 {
421 // Header for the vtk
422 std::string vtk_header;
423 // Point list of the VTK
424 std::string point_list;
425 // Vertex list of the VTK
426 std::string vertex_list;
427 // Graph header
428 std::string vtk_binary_or_ascii;
429 // vertex properties header
430 std::string point_prop_header;
431 // edge properties header
432 std::string vertex_prop_header;
433 // Data point header
434 std::string point_data_header;
435 // Data point
436 std::string point_data;
437
438 // VTK header
439 vtk_header = "# vtk DataFile Version 3.0\n"
440 + f_name + "\n";
441
442 // Choose if binary or ASCII
443 if (ft == file_type::ASCII)
444 {vtk_header += "ASCII\n";}
445 else
446 {vtk_header += "BINARY\n";}
447
448 // Data type for graph is DATASET POLYDATA
449 vtk_header += "DATASET POLYDATA\n";
450
451 vtk_header += add_meta_data(meta_data,ft);
452
453 // point properties header
454 point_prop_header = get_point_properties_list(ft);
455
456 // Get point list
457 point_list = get_point_list(ft);
458
459 // vertex properties header
460 vertex_prop_header = get_vertex_properties_list();
461
462 // Get vertex list
463 vertex_list = get_vertex_list(ft);
464
465 // Get the point data header
466 point_data_header = get_point_data_header();
467
468 // For each property in the vertex type produce a point data
469
470 prop_out_v< ele_vpp<typename pair::second>, typename pair::first::value_type::coord_type> pp(point_data, vpp, prop_names,ft);
471
472 if (prp == -1)
473 {boost::mpl::for_each< boost::mpl::range_c<int,0, pair::second::value_type::max_prop> >(pp);}
474 else
475 {boost::mpl::for_each< boost::mpl::range_c<int,prp, prp> >(pp);}
476
477 // Add the last property
478 pp.lastProp();
479
480
481 // write the file
482 std::ofstream ofs(file);
483
484 // Check if the file is open
485 if (ofs.is_open() == false)
486 {std::cerr << "Error cannot create the VTK file: " + file + "\n";}
487
488 ofs << vtk_header << point_prop_header << point_list <<
489 vertex_prop_header << vertex_list << point_data_header << point_data;
490
491 // Close the file
492
493 ofs.close();
494
495 // Completed succefully
496 return true;
497 }
498};
499
500
501#endif /* OPENFPM_IO_SRC_VTKWRITER_POINT_SET_HPP_ */
502