vtkmultiwriter.hh
Go to the documentation of this file.
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  Copyright (C) 2008-2013 by Andreas Lauser
5  Copyright (C) 2009 by Anneli Schoeniger
6 
7  This file is part of the Open Porous Media project (OPM).
8 
9  OPM is free software: you can redistribute it and/or modify
10  it under the terms of the GNU General Public License as published by
11  the Free Software Foundation, either version 2 of the License, or
12  (at your option) any later version.
13 
14  OPM is distributed in the hope that it will be useful,
15  but WITHOUT ANY WARRANTY; without even the implied warranty of
16  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17  GNU General Public License for more details.
18 
19  You should have received a copy of the GNU General Public License
20  along with OPM. If not, see <http://www.gnu.org/licenses/>.
21 */
27 #ifndef EWOMS_VTK_MULTI_WRITER_HH
28 #define EWOMS_VTK_MULTI_WRITER_HH
29 
30 #include "vtkscalarfunction.hh"
31 #include "vtkvectorfunction.hh"
32 #include "vtktensorfunction.hh"
33 
35 
36 #include <opm/material/common/Valgrind.hpp>
37 
38 #include <dune/common/fvector.hh>
39 #include <dune/istl/bvector.hh>
40 #include <dune/grid/io/file/vtk/vtkwriter.hh>
41 
42 #if HAVE_MPI
43 #include <mpi.h>
44 #endif
45 
46 #include <list>
47 #include <string>
48 #include <limits>
49 #include <sstream>
50 #include <fstream>
51 
52 namespace Ewoms {
60 template <class GridView, int vtkFormat>
62 {
63  enum { dim = GridView::dimension };
64 
65  typedef Dune::MultipleCodimMultipleGeomTypeMapper<GridView, Dune::MCMGVertexLayout> VertexMapper;
66  typedef Dune::MultipleCodimMultipleGeomTypeMapper<GridView, Dune::MCMGElementLayout> ElementMapper;
67 
68 public:
75 
76  typedef Dune::VTKWriter<GridView> VtkWriter;
77 
78  VtkMultiWriter(const GridView &gridView,
79  const std::string &simName = "",
80  std::string multiFileName = "")
81  : gridView_(gridView)
82  , elementMapper_(gridView)
83  , vertexMapper_(gridView)
84  {
85  simName_ = (simName.empty()) ? "sim" : simName;
86  multiFileName_ = multiFileName;
87  if (multiFileName_.empty()) {
88  multiFileName_ = simName_;
89  multiFileName_ += ".pvd";
90  }
91 
92  curWriterNum_ = 0;
93 
94  commRank_ = gridView.comm().rank();
95  commSize_ = gridView.comm().size();
96  }
97 
99  {
100  finishMultiFile_();
101 
102  if (commRank_ == 0)
103  multiFile_.close();
104  }
105 
109  int curWriterNum() const
110  { return curWriterNum_; }
111 
119  void gridChanged()
120  {
121  elementMapper_.update();
122  vertexMapper_.update();
123  }
124 
128  void beginWrite(double t)
129  {
130  if (!multiFile_.is_open()) {
131  startMultiFile_(multiFileName_);
132  }
133 
134  curWriter_ = new VtkWriter(gridView_, Dune::VTK::conforming);
135  ++curWriterNum_;
136 
137  curTime_ = t;
138  curOutFileName_ = fileName_();
139  }
140 
147  ScalarBuffer *allocateManagedScalarBuffer(int numEntities)
148  {
149  ScalarBuffer *buf = new ScalarBuffer(numEntities);
150  managedScalarBuffers_.push_back(buf);
151  return buf;
152  }
153 
160  VectorBuffer *allocateManagedVectorBuffer(int numOuter, int numInner)
161  {
162  VectorBuffer *buf = new VectorBuffer(numOuter);
163  for (int i = 0; i < numOuter; ++ i)
164  (*buf)[i].resize(numInner);
165 
166  managedVectorBuffers_.push_back(buf);
167  return buf;
168  }
169 
186  void attachScalarVertexData(ScalarBuffer &buf, std::string name)
187  {
188  sanitizeScalarBuffer_(buf);
189 
190  typedef typename VtkWriter::VTKFunctionPtr FunctionPtr;
192  FunctionPtr fnPtr(new VtkFn(name,
193  gridView_,
194  vertexMapper_,
195  buf,
196  /*codim=*/dim));
197  curWriter_->addVertexData(fnPtr);
198  }
199 
215  void attachScalarElementData(ScalarBuffer &buf, std::string name)
216  {
217  sanitizeScalarBuffer_(buf);
218 
219  typedef typename VtkWriter::VTKFunctionPtr FunctionPtr;
221  FunctionPtr fnPtr(new VtkFn(name,
222  gridView_,
223  elementMapper_,
224  buf,
225  /*codim=*/0));
226  curWriter_->addCellData(fnPtr);
227  }
228 
245  void attachVectorVertexData(VectorBuffer &buf, std::string name)
246  {
247  sanitizeVectorBuffer_(buf);
248 
249  typedef typename VtkWriter::VTKFunctionPtr FunctionPtr;
251  FunctionPtr fnPtr(new VtkFn(name,
252  gridView_,
253  vertexMapper_,
254  buf,
255  /*codim=*/dim));
256  curWriter_->addVertexData(fnPtr);
257  }
258 
262  void attachTensorVertexData(TensorBuffer &buf, std::string name)
263  {
264  typedef typename VtkWriter::VTKFunctionPtr FunctionPtr;
266 
267  for (size_t colIdx = 0; colIdx < buf[0].N(); ++colIdx) {
268  std::ostringstream oss;
269  oss << name << "[" << colIdx << "]";
270 
271  FunctionPtr fnPtr(new VtkFn(oss.str(),
272  gridView_,
273  vertexMapper_,
274  buf,
275  /*codim=*/dim,
276  colIdx));
277  curWriter_->addVertexData(fnPtr);
278  }
279  }
280 
296  void attachVectorElementData(VectorBuffer &buf, std::string name)
297  {
298  sanitizeVectorBuffer_(buf);
299 
300  typedef typename VtkWriter::VTKFunctionPtr FunctionPtr;
302  FunctionPtr fnPtr(new VtkFn(name,
303  gridView_,
304  elementMapper_,
305  buf,
306  /*codim=*/0));
307  curWriter_->addCellData(fnPtr);
308  }
309 
313  void attachTensorElementData(TensorBuffer &buf, std::string name)
314  {
315  typedef typename VtkWriter::VTKFunctionPtr FunctionPtr;
317 
318  for (size_t colIdx = 0; colIdx < buf[0].N(); ++colIdx) {
319  std::ostringstream oss;
320  oss << name << "[" << colIdx << "]";
321 
322  FunctionPtr fnPtr(new VtkFn(oss.str(),
323  gridView_,
324  elementMapper_,
325  buf,
326  /*codim=*/0,
327  colIdx));
328  curWriter_->addCellData(fnPtr);
329  }
330  }
331 
339  void endWrite(bool onlyDiscard = false)
340  {
341  if (!onlyDiscard) {
342  std::string fileName;
343  // write the actual data as vtu or vtp (plus the pieces file in the parallel case)
344  fileName = curWriter_->write(/*name=*/curOutFileName_.c_str(),
345  static_cast<Dune::VTK::OutputType>(vtkFormat));
346 
347  // determine name to write into the multi-file for the
348  // current time step
349  multiFile_.precision(16);
350  multiFile_ << " <DataSet timestep=\"" << curTime_ << "\" file=\""
351  << fileName << "\"/>\n";
352  }
353  else
354  --curWriterNum_;
355 
356  // discard managed objects and the current VTK writer
357  delete curWriter_;
358  while (managedScalarBuffers_.begin() != managedScalarBuffers_.end()) {
359  delete managedScalarBuffers_.front();
360  managedScalarBuffers_.pop_front();
361  }
362  while (managedVectorBuffers_.begin() != managedVectorBuffers_.end()) {
363  delete managedVectorBuffers_.front();
364  managedVectorBuffers_.pop_front();
365  }
366 
367  // temporarily write the closing XML mumbo-jumbo to the mashup
368  // file so that the data set can be loaded even if the
369  // simulation is aborted (or not yet finished)
370  finishMultiFile_();
371  }
372 
376  template <class Restarter>
377  void serialize(Restarter &res)
378  {
379  res.serializeSectionBegin("VTKMultiWriter");
380  res.serializeStream() << curWriterNum_ << "\n";
381 
382  if (commRank_ == 0) {
383  size_t fileLen = 0;
384  size_t filePos = 0;
385  if (multiFile_.is_open()) {
386  // write the meta file into the restart file
387  filePos = multiFile_.tellp();
388  multiFile_.seekp(0, std::ios::end);
389  fileLen = multiFile_.tellp();
390  multiFile_.seekp(filePos);
391  }
392 
393  res.serializeStream() << fileLen << " " << filePos << "\n";
394 
395  if (fileLen > 0) {
396  std::ifstream multiFileIn(multiFileName_.c_str());
397  char *tmp = new char[fileLen];
398  multiFileIn.read(tmp, static_cast<long>(fileLen));
399  res.serializeStream().write(tmp, fileLen);
400  delete[] tmp;
401  }
402  }
403 
404  res.serializeSectionEnd();
405  }
406 
410  template <class Restarter>
411  void deserialize(Restarter &res)
412  {
413  res.deserializeSectionBegin("VTKMultiWriter");
414  res.deserializeStream() >> curWriterNum_;
415 
416  if (commRank_ == 0) {
417  std::string dummy;
418  std::getline(res.deserializeStream(), dummy);
419 
420  // recreate the meta file from the restart file
421  size_t filePos, fileLen;
422  res.deserializeStream() >> fileLen >> filePos;
423  std::getline(res.deserializeStream(), dummy);
424  if (multiFile_.is_open())
425  multiFile_.close();
426 
427  if (fileLen > 0) {
428  multiFile_.open(multiFileName_.c_str());
429 
430  char *tmp = new char[fileLen];
431  res.deserializeStream().read(tmp, fileLen);
432  multiFile_.write(tmp, fileLen);
433  delete[] tmp;
434  }
435 
436  multiFile_.seekp(filePos);
437  }
438  else {
439  std::string tmp;
440  std::getline(res.deserializeStream(), tmp);
441  }
442  res.deserializeSectionEnd();
443  }
444 
445 private:
446  std::string fileName_()
447  {
448  // use a new file name for each time step
449  std::ostringstream oss;
450  oss << simName_ << "-" << std::setw(5) << std::setfill('0')
451  << curWriterNum_;
452  return oss.str();
453  }
454 
455  std::string fileSuffix_()
456  { return (GridView::dimension == 1) ? "vtp" : "vtu"; }
457 
458  void startMultiFile_(const std::string &multiFileName)
459  {
460  // only the first process writes to the multi-file
461  if (commRank_ == 0) {
462  // generate one meta vtk-file holding the individual time steps
463  multiFile_.open(multiFileName.c_str());
464  multiFile_ << "<?xml version=\"1.0\"?>\n"
465  "<VTKFile type=\"Collection\"\n"
466  " version=\"0.1\"\n"
467  " byte_order=\"LittleEndian\"\n"
468  " compressor=\"vtkZLibDataCompressor\">\n"
469  " <Collection>\n";
470  }
471  }
472 
473  void finishMultiFile_()
474  {
475  // only the first process writes to the multi-file
476  if (commRank_ == 0) {
477  // make sure that we always have a working meta file
478  std::ofstream::pos_type pos = multiFile_.tellp();
479  multiFile_ << " </Collection>\n"
480  "</VTKFile>\n";
481  multiFile_.seekp(pos);
482  multiFile_.flush();
483  }
484  }
485 
486  // make sure the field is well defined if running under valgrind
487  // and make sure that all values can be displayed by paraview
488  void sanitizeScalarBuffer_(ScalarBuffer &b)
489  {
490  for (unsigned j = 0; j < b.size(); ++j) {
491  Valgrind::CheckDefined(b[j]);
492 
493  // set values which are too small to 0 to avoid
494  // problems with paraview
495  if (std::abs(b[j]) < std::numeric_limits<float>::min()) {
496  b[j] = 0.0;
497  }
498  }
499  }
500 
501  void sanitizeVectorBuffer_(VectorBuffer &b)
502  {
503  size_t nComps = b[0].size();
504  for (size_t i = 0; i < b.size(); ++i) {
505  for (size_t j = 0; j < nComps; ++j) {
506  Valgrind::CheckDefined(b[i][j]);
507 
508  // set values which are too small to 0 to avoid
509  // problems with paraview
510  if (std::abs(b[i][j]) < std::numeric_limits<float>::min()) {
511  b[i][j] = 0.0;
512  }
513  }
514  }
515  }
516 
517  const GridView gridView_;
518  ElementMapper elementMapper_;
519  VertexMapper vertexMapper_;
520 
521  std::string simName_;
522  std::ofstream multiFile_;
523  std::string multiFileName_;
524 
525  int commSize_; // number of processes in the communicator
526  int commRank_; // rank of the current process in the communicator
527 
528  VtkWriter *curWriter_;
529  double curTime_;
530  std::string curOutFileName_;
531  int curWriterNum_;
532 
533  std::list<ScalarBuffer *> managedScalarBuffers_;
534  std::list<VectorBuffer *> managedVectorBuffers_;
535 };
536 } // namespace Ewoms
537 
538 #endif
VectorBuffer * allocateManagedVectorBuffer(int numOuter, int numInner)
Allocate a managed buffer for a vector field.
Definition: vtkmultiwriter.hh:160
void attachVectorVertexData(VectorBuffer &buf, std::string name)
Add a finished vertex centered vector field to the output.
Definition: vtkmultiwriter.hh:245
BaseOutputWriter::ScalarBuffer ScalarBuffer
Definition: vtkmultiwriter.hh:72
std::vector< Vector > VectorBuffer
Definition: baseoutputwriter.hh:48
std::vector< Scalar > ScalarBuffer
Definition: baseoutputwriter.hh:47
BaseOutputWriter::VectorBuffer VectorBuffer
Definition: vtkmultiwriter.hh:73
std::vector< Tensor > TensorBuffer
Definition: baseoutputwriter.hh:49
void serialize(Restarter &res)
Write the multi-writer's state to a restart file.
Definition: vtkmultiwriter.hh:377
Dune::VTKWriter< GridView > VtkWriter
Definition: vtkmultiwriter.hh:76
void attachScalarVertexData(ScalarBuffer &buf, std::string name)
Add a finished vertex centered vector field to the output.
Definition: vtkmultiwriter.hh:186
void gridChanged()
Updates the internal data structures after mesh refinement.
Definition: vtkmultiwriter.hh:119
double Scalar
Definition: baseoutputwriter.hh:44
The base class for all output writers.
Definition: baseoutputwriter.hh:41
Provides a vector-valued function using Dune::FieldVectors as elements.
Definition: vtkscalarfunction.hh:49
Provides a tensor-valued function using Dune::FieldMatrix objects as elements.
BaseOutputWriter::Tensor Tensor
Definition: vtkmultiwriter.hh:71
void attachVectorElementData(VectorBuffer &buf, std::string name)
Add a element centered quantity to the output.
Definition: vtkmultiwriter.hh:296
Definition: baseauxiliarymodule.hh:35
ScalarBuffer * allocateManagedScalarBuffer(int numEntities)
Allocate a managed buffer for a scalar field.
Definition: vtkmultiwriter.hh:147
Provides a vector-valued function using Dune::FieldVectors as elements.
The base class for all output writers.
void beginWrite(double t)
Called whenever a new time step must be written.
Definition: vtkmultiwriter.hh:128
Provides a tensor-valued function using Dune::FieldMatrix objects as elements.
Definition: vtktensorfunction.hh:47
void attachScalarElementData(ScalarBuffer &buf, std::string name)
Add a element centered quantity to the output.
Definition: vtkmultiwriter.hh:215
void attachTensorVertexData(TensorBuffer &buf, std::string name)
Add a finished vertex-centered tensor field to the output.
Definition: vtkmultiwriter.hh:262
void attachTensorElementData(TensorBuffer &buf, std::string name)
Add a finished element-centered tensor field to the output.
Definition: vtkmultiwriter.hh:313
BaseOutputWriter::Scalar Scalar
Definition: vtkmultiwriter.hh:69
int curWriterNum() const
Returns the number of the current VTK file.
Definition: vtkmultiwriter.hh:109
~VtkMultiWriter()
Definition: vtkmultiwriter.hh:98
Dune::DynamicVector< double > Vector
Definition: baseoutputwriter.hh:45
Provides a vector-valued function using Dune::FieldVectors as elements.
Definition: vtkvectorfunction.hh:49
BaseOutputWriter::Vector Vector
Definition: vtkmultiwriter.hh:70
void deserialize(Restarter &res)
Read the multi-writer's state from a restart file.
Definition: vtkmultiwriter.hh:411
Dune::DynamicMatrix< double > Tensor
Definition: baseoutputwriter.hh:46
Provides a vector-valued function using Dune::FieldVectors as elements.
VtkMultiWriter(const GridView &gridView, const std::string &simName="", std::string multiFileName="")
Definition: vtkmultiwriter.hh:78
void endWrite(bool onlyDiscard=false)
Finalizes the current writer.
Definition: vtkmultiwriter.hh:339
Simplifies writing multi-file VTK datasets.
Definition: vtkmultiwriter.hh:61
BaseOutputWriter::TensorBuffer TensorBuffer
Definition: vtkmultiwriter.hh:74