Flow123d  release_2.2.0-33-g759111d
output_vtk.cc
Go to the documentation of this file.
1 /*!
2  *
3  * Copyright (C) 2015 Technical University of Liberec. All rights reserved.
4  *
5  * This program is free software; you can redistribute it and/or modify it under
6  * the terms of the GNU General Public License version 3 as published by the
7  * Free Software Foundation. (http://www.gnu.org/licenses/gpl-3.0.en.html)
8  *
9  * This program is distributed in the hope that it will be useful, but WITHOUT
10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11  * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
12  *
13  *
14  * @file output_vtk.cc
15  * @brief The functions for outputs to VTK files.
16  */
17 
18 #include "output_vtk.hh"
20 #include "output_mesh.hh"
21 
22 #include <limits.h>
23 #include "input/factory.hh"
25 #include "system/file_path.hh"
26 
27 #include "config.h"
28 #include <zlib.h>
29 
31 
32 
33 using namespace Input::Type;
34 
35 const Record & OutputVTK::get_input_type() {
36  return Record("vtk", "Parameters of vtk output format.")
37  // It is derived from abstract class
39  .declare_key("variant", OutputVTK::get_input_type_variant(), Default("\"ascii\""),
40  "Variant of output stream file format.")
41  // The parallel or serial variant
42  //.declare_key("parallel", Bool(), Default("false"),
43  // "Parallel or serial version of file format.")
44  .close();
45 }
46 
47 
49  return Selection("VTK variant (ascii or binary)")
51  "ASCII variant of VTK file format")
53  "Uncompressed appended binary XML VTK format without usage of base64 encoding of appended data.")
54 #ifdef FLOW123D_HAVE_ZLIB
56  "Appended binary XML VTK format without usage of base64 encoding of appended data. Compressed with ZLib.")
57 #endif // FLOW123D_HAVE_ZLIB
58  .close();
59 }
60 
61 
62 const int OutputVTK::registrar = Input::register_class< OutputVTK >("vtk") +
64 
65 
66 
68 {
69  this->enable_refinement_ = true;
70 }
71 
72 
73 
75 {
76  this->write_tail();
77 }
78 
79 
80 
81 void OutputVTK::init_from_input(const std::string &equation_name, Mesh &mesh, const Input::Record &in_rec)
82 {
83  OutputTime::init_from_input(equation_name, mesh, in_rec);
84 
85  if(this->rank == 0) {
86  auto format_rec = (Input::Record)(input_record_.val<Input::AbstractRecord>("format"));
87  variant_type_ = format_rec.val<VTKVariant>("variant");
88 
89  this->fix_main_file_extension(".pvd");
90  try {
91  this->_base_filename.open_stream( this->_base_file );
92  this->set_stream_precision(this->_base_file);
93  } INPUT_CATCH(FilePath::ExcFileOpen, FilePath::EI_Address_String, input_record_)
94 
95  LogOut() << "Writing flow output file: " << this->_base_filename << " ... ";
96 
97  this->make_subdirectory();
98  this->write_head();
99  }
100 
101 }
102 
103 
104 
105 
107 {
108  ASSERT_PTR(output_mesh_).error();
109 
110  /* It's possible now to do output to the file only in the first process */
111  if(this->rank != 0) {
112  /* TODO: do something, when support for Parallel VTK is added */
113  return 0;
114  }
115 
116  ASSERT(this->_base_file.is_open())(this->_base_filename).error();
117 
118  ostringstream ss;
119  ss << main_output_basename_ << "-"
120  << std::setw(6) << std::setfill('0') << this->current_step
121  << ".vtu";
122 
123 
124  std::string frame_file_name = ss.str();
125  FilePath frame_file_path({main_output_dir_, main_output_basename_, frame_file_name}, FilePath::output_file);
126 
127  /* Set up data file */
128  try {
129  frame_file_path.open_stream(_data_file);
131  } INPUT_CATCH(FilePath::ExcFileOpen, FilePath::EI_Address_String, input_record_)
132 
133 
134  LogOut() << __func__ << ": Writing output file " << this->_base_filename << " ... ";
135 
136  /* Set floating point precision to max */
137  //this->_base_file.precision(std::numeric_limits<double>::digits10);
138 
139  /* Strip out relative path and add "base/" string */
140  std::string relative_frame_file = main_output_basename_ + "/" + frame_file_name;
141  this->_base_file << "<DataSet timestep=\"" << (isfinite(this->time)?this->time:0)
142  << "\" group=\"\" part=\"0\" file=\"" << relative_frame_file <<"\"/>" << endl;
143 
144  LogOut() << "O.K.";
145 
146  LogOut() << __func__ << ": Writing output (frame " << this->current_step << ") file " << relative_frame_file << " ... ";
147 
148  this->write_vtk_vtu();
149 
150  /* Close stream for file of current frame */
151  _data_file.close();
152  //delete data_file;
153  //this->_data_file = NULL;
154 
155  LogOut() << "O.K.";
156 
157  return 1;
158 }
159 
160 
161 
162 
164 {
165  ASSERT_EQ(this->_base_filename.extension(), ".pvd").error();
168 
169  vector<string> sub_path = { main_output_dir_, main_output_basename_, "__tmp__" };
170  FilePath fp(sub_path, FilePath::output_file);
171  fp.create_output_dir();
172 }
173 
174 
175 
176 
178 {
179  ofstream &file = this->_data_file;
180 
181  file << "<?xml version=\"1.0\"?>" << endl;
182  // TODO: test endianess of platform (this would be important, when raw
183  // data will be saved to the VTK file)
184  file << "<VTKFile type=\"UnstructuredGrid\" version=\"0.1\" byte_order=\"LittleEndian\"";
185  if ( this->variant_type_ != VTKVariant::VARIANT_ASCII ) {
186  file << " header_type=\"UInt64\"";
187  }
188  if ( this->variant_type_ == VTKVariant::VARIANT_BINARY_ZLIB ) {
189  file << " compressor=\"vtkZLibDataCompressor\"";
190  }
191  file << ">" << endl;
192  file << "<UnstructuredGrid>" << endl;
193 }
194 
195 
196 
197 std::shared_ptr<ElementDataCache<unsigned int>> OutputVTK::fill_element_types_data()
198 {
199  auto &offsets = *( output_mesh_->offsets_->get_component_data(0).get() );
200  unsigned int n_elements = offsets.size();
201 
202  auto types = std::make_shared<ElementDataCache<unsigned int>>("types", ElementDataCacheBase::N_SCALAR, 1, n_elements);
203  std::vector< unsigned int >& data = *( types->get_component_data(0).get() );
204  int n_nodes;
205 
206  n_nodes = offsets[0];
207  switch(n_nodes) {
208  case 2:
209  data[0] = (unsigned int)VTK_LINE;
210  break;
211  case 3:
212  data[0] = (unsigned int)VTK_TRIANGLE;
213  break;
214  case 4:
215  data[0] = (unsigned int)VTK_TETRA;
216  break;
217  }
218 
219  for(unsigned int i=1; i < n_elements; i++)
220  {
221  n_nodes = offsets[i]-offsets[i-1];
222  switch(n_nodes) {
223  case 2:
224  data[i] = (unsigned int)VTK_LINE;
225  break;
226  case 3:
227  data[i] = (unsigned int)VTK_TRIANGLE;
228  break;
229  case 4:
230  data[i] = (unsigned int)VTK_TETRA;
231  break;
232  }
233  }
234 
235  return types;
236 }
237 
238 
239 
241 {
242  // names of types in DataArray section
243  static const std::vector<std::string> types = {
244  "Int8", "UInt8", "Int16", "UInt16", "Int32", "UInt32", "Float32", "Float64" };
245  // formats of DataArray section
246  static const std::vector<std::string> formats = { "ascii", "appended", "appended" };
247 
248  ofstream &file = this->_data_file;
249 
250  file << "<DataArray type=\"" << types[output_data->vtk_type()] << "\" ";
251  // possibly write name
252  if( ! output_data->field_input_name().empty())
253  file << "Name=\"" << output_data->field_input_name() <<"\" ";
254  // write number of components
255  if (output_data->n_elem() > 1)
256  {
257  file
258  << "NumberOfComponents=\"" << output_data->n_elem() << "\" ";
259  }
260  file << "format=\"" << formats[this->variant_type_] << "\"";
261 
262  if ( this->variant_type_ == VTKVariant::VARIANT_ASCII ) {
263  // ascii output
264  file << ">" << endl;
265  //file << std::fixed << std::setprecision(10); // Set precision to max
266  output_data->print_ascii_all(file);
267  file << "\n</DataArray>" << endl;
268  } else {
269  // binary output is stored to appended_data_ stream
270  double range_min, range_max;
271  output_data->get_min_max_range(range_min, range_max);
272  file << " offset=\"" << appended_data_.tellp() << "\" ";
273  file << "RangeMin=\"" << range_min << "\" RangeMax=\"" << range_max << "\"/>" << endl;
274  if ( this->variant_type_ == VTKVariant::VARIANT_BINARY_UNCOMPRESSED ) {
275  output_data->print_binary_all( appended_data_ );
276  } else { // ZLib compression
277  stringstream uncompressed_data, compressed_data;
278  output_data->print_binary_all( uncompressed_data, false );
279  this->compress_data(uncompressed_data, compressed_data);
280  appended_data_ << compressed_data.str();
281  }
282  }
283 
284 }
285 
286 
287 void OutputVTK::compress_data(stringstream &uncompressed_stream, stringstream &compressed_stream) {
288  // size of block of compressed data.
289  static const size_t BUF_SIZE = 32 * 1024;
290 
291  string uncompressed_string = uncompressed_stream.str(); // full uncompressed string
292  uLong uncompressed_size = uncompressed_string.size(); // size of uncompressed string
293  stringstream compressed_data; // helper stream stores blocks of compress data
294 
295  uLong count_of_blocks = (uncompressed_size + BUF_SIZE - 1) / BUF_SIZE;
296  uLong last_block_size = (uncompressed_size % BUF_SIZE);
297  compressed_stream.write(reinterpret_cast<const char*>(&count_of_blocks), sizeof(unsigned long long int));
298  compressed_stream.write(reinterpret_cast<const char*>(&BUF_SIZE), sizeof(unsigned long long int));
299  compressed_stream.write(reinterpret_cast<const char*>(&last_block_size), sizeof(unsigned long long int));
300 
301  for (uLong i=0; i<count_of_blocks; ++i) {
302  // get block of data for compression
303  std::string data_block = uncompressed_string.substr(i*BUF_SIZE, BUF_SIZE);
304  uLong data_block_size = data_block.size();
305 
306  std::vector<uint8_t> buffer;
307  uint8_t temp_buffer[BUF_SIZE];
308 
309  // set zlib object
310  z_stream strm;
311  strm.zalloc = 0;
312  strm.zfree = 0;
313  strm.next_in = reinterpret_cast<uint8_t *>(&data_block[0]);
314  strm.avail_in = data_block_size;
315  strm.next_out = temp_buffer;
316  strm.avail_out = BUF_SIZE;
317 
318  // compression of data
319  deflateInit(&strm, Z_BEST_COMPRESSION);
320  while (strm.avail_in != 0) {
321  int res = deflate(&strm, Z_NO_FLUSH);
322  ASSERT_EQ(res, Z_OK).error();
323  if (strm.avail_out == 0) {
324  buffer.insert(buffer.end(), temp_buffer, temp_buffer + BUF_SIZE);
325  strm.next_out = temp_buffer;
326  strm.avail_out = BUF_SIZE;
327  }
328  }
329  int deflate_res = Z_OK;
330  while (deflate_res == Z_OK) {
331  if (strm.avail_out == 0) {
332  buffer.insert(buffer.end(), temp_buffer, temp_buffer + BUF_SIZE);
333  strm.next_out = temp_buffer;
334  strm.avail_out = BUF_SIZE;
335  }
336  deflate_res = deflate(&strm, Z_FINISH);
337  }
338  ASSERT_EQ(deflate_res, Z_STREAM_END).error();
339  buffer.insert(buffer.end(), temp_buffer, temp_buffer + BUF_SIZE - strm.avail_out);
340  deflateEnd(&strm);
341 
342  // store compress data and its size to streams
343  std::string str(buffer.begin(), buffer.end());
344  uLong compressed_data_size = str.size();
345  compressed_stream.write(reinterpret_cast<const char*>(&compressed_data_size), sizeof(unsigned long long int));
346  compressed_data << str;
347  }
348  // push compress data to returned stream
349  compressed_stream << compressed_data.str();
350 }
351 
352 
354 {
355  for(OutputDataPtr data : output_data_vec)
356  write_vtk_data(data);
357 }
358 
359 
360 
361 
363  OutputDataFieldVec &output_data_vec)
364 {
365  if (output_data_vec.empty()) return;
366 
367  file << "Scalars=\"";
368  for(OutputDataPtr data : output_data_vec )
369  if (data->n_elem() == ElementDataCacheBase::N_SCALAR) file << data->field_input_name() << ",";
370  file << "\" ";
371 
372  file << "Vectors=\"";
373  for(OutputDataPtr data : output_data_vec )
374  if (data->n_elem() == ElementDataCacheBase::N_VECTOR) file << data->field_input_name() << ",";
375  file << "\" ";
376 
377  file << "Tensors=\"";
378  for(OutputDataPtr data : output_data_vec )
379  if (data->n_elem() == ElementDataCacheBase::N_TENSOR) file << data->field_input_name() << ",";
380  file << "\"";
381 }
382 
383 
385 {
386  ofstream &file = this->_data_file;
387 
388  // merge node and corner data
389  OutputDataFieldVec node_corner_data(output_data_vec_[NODE_DATA]);
390  node_corner_data.insert(node_corner_data.end(),
392 
393  if( ! node_corner_data.empty() ) {
394  /* Write <PointData begin */
395  file << "<PointData ";
396  write_vtk_data_names(file, node_corner_data);
397  file << ">" << endl;
398 
399  /* Write data on nodes */
400  this->write_vtk_field_data(output_data_vec_[NODE_DATA]);
401 
402  /* Write data in corners of elements */
404 
405  /* Write PointData end */
406  file << "</PointData>" << endl;
407  }
408 }
409 
410 
412 {
413  ofstream &file = this->_data_file;
414 
415  auto &data_map = this->output_data_vec_[ELEM_DATA];
416  if (data_map.empty()) return;
417 
418  /* Write CellData begin */
419  file << "<CellData ";
420  write_vtk_data_names(file, data_map);
421  file << ">" << endl;
422 
423  /* Write own data */
424  this->write_vtk_field_data(data_map);
425 
426  /* Write PointData end */
427  file << "</CellData>" << endl;
428 }
429 
430 
432 {
433  ofstream &file = this->_data_file;
434 
435  file << "</UnstructuredGrid>" << endl;
436  if ( this->variant_type_ != VTKVariant::VARIANT_ASCII ) {
437  // appended data of binary compressed output
438  file << "<AppendedData encoding=\"raw\">" << endl;
439  // appended data starts with '_' character
440  file << "_" << appended_data_.str() << endl;
441  file << "</AppendedData>" << endl;
442  }
443  file << "</VTKFile>" << endl;
444 }
445 
446 
448 {
449  ofstream &file = this->_data_file;
450 
451  /* Write header */
452  this->write_vtk_vtu_head();
453 
454  /* When there is no discontinuous data, then write classical vtu */
455  if ( this->output_data_vec_[CORNER_DATA].empty() )
456  {
457  /* Write Piece begin */
458  file << "<Piece NumberOfPoints=\"" << output_mesh_->n_nodes()
459  << "\" NumberOfCells=\"" << output_mesh_->n_elements() <<"\">" << endl;
460 
461  /* Write VTK Geometry */
462  file << "<Points>" << endl;
463  write_vtk_data(output_mesh_->nodes_);
464  file << "</Points>" << endl;
465 
466 
467  /* Write VTK Topology */
468  file << "<Cells>" << endl;
469  write_vtk_data(output_mesh_->connectivity_);
470  write_vtk_data(output_mesh_->offsets_);
471  auto types = fill_element_types_data();
472  write_vtk_data( types );
473  file << "</Cells>" << endl;
474 
475  /* Write VTK scalar and vector data on nodes to the file */
476  this->write_vtk_node_data();
477 
478  /* Write VTK data on elements */
479  this->write_vtk_element_data();
480 
481  /* Write Piece end */
482  file << "</Piece>" << endl;
483 
484  } else {
485  /* Write Piece begin */
486  file << "<Piece NumberOfPoints=\"" << output_mesh_discont_->n_nodes()
487  << "\" NumberOfCells=\"" << output_mesh_->n_elements() <<"\">" << endl;
488 
489  /* Write VTK Geometry */
490  file << "<Points>" << endl;
492  file << "</Points>" << endl;
493 
494  /* Write VTK Topology */
495  file << "<Cells>" << endl;
496  write_vtk_data(output_mesh_discont_->connectivity_);
498  auto types = fill_element_types_data();
499  write_vtk_data( types );
500  file << "</Cells>" << endl;
501 
502  /* Write VTK scalar and vector data on nodes to the file */
503  this->write_vtk_node_data();
504 
505  /* Write VTK data on elements */
506  this->write_vtk_element_data();
507 
508  /* Write Piece end */
509  file << "</Piece>" << endl;
510  }
511 
512  /* Write tail */
513  this->write_vtk_vtu_tail();
514 }
515 
516 
517 
519 {
520  /* It's possible now to do output to the file only in the first process */
521  if(this->rank != 0) {
522  /* TODO: do something, when support for Parallel VTK is added */
523  return 0;
524  }
525 
526  LogOut() << __func__ << ": Writing output file (head) " << this->_base_filename << " ... ";
527 
528  this->_base_file << "<?xml version=\"1.0\"?>" << endl;
529  this->_base_file << "<VTKFile type=\"Collection\" version=\"0.1\" byte_order=\"LittleEndian\">" << endl;
530  this->_base_file << "<Collection>" << endl;
531 
532  LogOut() << "O.K.";
533 
534  return 1;
535 }
536 
537 
539 {
540  /* It's possible now to do output to the file only in the first process */
541  if(this->rank != 0) {
542  /* TODO: do something, when support for Parallel VTK is added */
543  return 0;
544  }
545 
546  LogOut() << __func__ << ": Writing output file (tail) " << this->_base_filename << " ... ";
547 
548  this->_base_file << "</Collection>" << endl;
549  this->_base_file << "</VTKFile>" << endl;
550 
551  LogOut() << "O.K.";
552 
553  return 1;
554 }
555 
556 
557 
558 
559 
560 
Classes for auxiliary output mesh.
string stem() const
Definition: file_path.cc:193
double time
Definition: output_time.hh:228
std::shared_ptr< OutputMesh > output_mesh_
Output mesh.
Definition: output_time.hh:267
virtual void init_from_input(const std::string &equation_name, Mesh &mesh, const Input::Record &in_rec)
Constructor of OutputTime object. It opens base file for writing.
Definition: output_time.cc:78
Input::Record input_record_
Definition: output_time.hh:238
std::shared_ptr< OutputMeshDiscontinuous > output_mesh_discont_
Discontinuous (non-conforming) mesh. Used for CORNER_DATA.
Definition: output_time.hh:269
void fix_main_file_extension(std::string extension)
Definition: output_time.cc:162
unsigned int size() const
Returns number of keys in the Record.
Definition: type_record.hh:598
void make_subdirectory()
Definition: output_vtk.cc:163
static const Input::Type::Record & get_input_type()
The definition of input record for vtk file format.
Definition: output_vtk.cc:35
void create_output_dir()
Definition: file_path.cc:176
void write_vtk_field_data(OutputDataFieldVec &output_data_map)
Definition: output_vtk.cc:353
std::shared_ptr< ElementDataCache< unsigned int > > fill_element_types_data()
Fills the data cache with VTK element types indicators.
Definition: output_vtk.cc:197
void write_vtk_vtu(void)
This function write all scalar and vector data on nodes and elements to the VTK file (...
Definition: output_vtk.cc:447
Class Input::Type::Default specifies default value of keys of a Input::Type::Record.
Definition: type_record.hh:61
FilePath _base_filename
Definition: output_time.hh:248
void write_vtk_data(OutputDataPtr output_data)
Definition: output_vtk.cc:240
static const int registrar
Registrar of class to factory.
Definition: output_vtk.hh:124
#define INPUT_CATCH(ExceptionType, AddressEITag, input_accessor)
Definition: accessors.hh:64
static Input::Type::Abstract & get_input_format_type()
The specification of output file format.
Definition: output_time.cc:60
Definition: mesh.h:97
std::shared_ptr< ElementDataCacheBase > OutputDataPtr
Definition: output_time.hh:111
string main_output_basename_
Basename of main output file (without extension)
Definition: output_vtk.hh:204
#define ASSERT(expr)
Allow use shorter versions of macro names if these names is not used with external library...
Definition: asserts.hh:346
int write_head(void)
This function writes header of VTK (.pvd) file format.
Definition: output_vtk.cc:518
string main_output_dir_
Main output file directory.
Definition: output_vtk.hh:207
void write_vtk_element_data(void)
Write data on elements to the VTK file (.vtu)
Definition: output_vtk.cc:411
#define LogOut()
Macro defining &#39;log&#39; record of log.
Definition: logger.hh:239
Record & close() const
Close the Record for further declarations of keys.
Definition: type_record.cc:303
VTKVariant
The declaration enumeration used for variant of file VTK format.
Definition: output_vtk.hh:87
virtual Record & derive_from(Abstract &parent)
Method to derive new Record from an AbstractRecord parent.
Definition: type_record.cc:195
void open_stream(Stream &stream) const
Definition: file_path.cc:211
int write_data(void)
This function write data to VTK (.pvd) file format for curent time.
Definition: output_vtk.cc:106
ofstream _data_file
Definition: output_vtk.hh:191
int current_step
Definition: output_time.hh:223
ostringstream appended_data_
Definition: output_vtk.hh:196
Accessor to the data with type Type::Record.
Definition: accessors.hh:292
const Ret val(const string &key) const
void write_vtk_vtu_tail(void)
Write tail of VTK file (.vtu)
Definition: output_vtk.cc:431
This class is used for output data to VTK file format.
Definition: output_vtk.hh:34
Selection & add_value(const int value, const std::string &key, const std::string &description="", TypeBase::attribute_map attributes=TypeBase::attribute_map())
Adds one new value with name given by key to the Selection.
string parent_path() const
Definition: file_path.cc:183
Record & declare_key(const string &key, std::shared_ptr< TypeBase > type, const Default &default_value, const string &description, TypeBase::attribute_map key_attributes=TypeBase::attribute_map())
Declares a new key of the Record.
Definition: type_record.cc:490
int write_tail(void)
This function writes tail of VTK (.pvd) file format.
Definition: output_vtk.cc:538
void set_stream_precision(std::ofstream &stream)
Definition: output_time.cc:94
ofstream _base_file
Definition: output_time.hh:243
~OutputVTK()
The destructor of this class. It writes tail of the file too.
Definition: output_vtk.cc:74
string extension() const
Definition: file_path.cc:198
Accessor to the polymorphic input data of a type given by an AbstracRecord object.
Definition: accessors.hh:459
Dedicated class for storing path to input and output files.
Definition: file_path.hh:54
OutputVTK()
The constructor of this class. The head of file is written, when constructor is called.
Definition: output_vtk.cc:67
#define ASSERT_PTR(ptr)
Definition of assert macro checking non-null pointer (PTR)
Definition: asserts.hh:335
const Selection & close() const
Close the Selection, no more values can be added.
VTKVariant variant_type_
Output format (ascii, binary or binary compressed)
Definition: output_vtk.hh:210
void write_vtk_node_data(void)
Write data on nodes to the VTK file (.vtu)
Definition: output_vtk.cc:384
OutputDataFieldVec output_data_vec_[N_DISCRETE_SPACES]
Definition: output_time.hh:218
void compress_data(stringstream &uncompressed_stream, stringstream &compressed_stream)
Definition: output_vtk.cc:287
Record type proxy class.
Definition: type_record.hh:182
bool enable_refinement_
Auxiliary flag for refinement enabling, due to gmsh format.
Definition: output_time.hh:274
void write_vtk_vtu_head(void)
Write header of VTK file (.vtu)
Definition: output_vtk.cc:177
void init_from_input(const std::string &equation_name, Mesh &mesh, const Input::Record &in_rec) override
Override OutputTime::init_from_input.
Definition: output_vtk.cc:81
Template for classes storing finite set of named values.
#define FLOW123D_FORCE_LINK_IN_CHILD(x)
Definition: global_defs.h:180
#define ASSERT_EQ(a, b)
Definition of comparative assert macro (EQual)
Definition: asserts.hh:327
static const Input::Type::Selection & get_input_type_variant()
The definition of input record for selection of variant of file format.
Definition: output_vtk.cc:48
void write_vtk_data_names(ofstream &file, OutputDataFieldVec &output_data_map)
Write names of data sets in output_data vector that have value type equal to type. Output is done into stream file.
Definition: output_vtk.cc:362