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 | */ |
24 | template <typename Vps> |
25 | class ele_vps |
26 | { |
27 | public: |
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 | */ |
50 | template <typename Vpp> |
51 | class ele_vpp |
52 | { |
53 | public: |
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 | */ |
83 | template<typename ele_v, typename St> |
84 | struct 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 | */ |
183 | template <typename pair> |
184 | class 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 () |
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 | |
374 | public: |
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 ; |
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 ; |
431 | // edge properties header |
432 | std::string ; |
433 | // Data point header |
434 | std::string ; |
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 | |