Newer
Older

Oliver Sander
committed
#ifndef DUNE_GFE_VTKFILE_HH
#define DUNE_GFE_VTKFILE_HH
#include <vector>
#include <fstream>
#if HAVE_TINYXML2
// For VTK file reading
#include <tinyxml2.h>
#endif
#include <dune/common/fvector.hh>
// For parallel infrastructure stuff:
#include <dune/grid/io/file/vtk.hh>

Oliver Sander
committed
namespace Dune {
namespace GFE {
/** \brief A class representing a VTK file, but independent from the Dune grid interface
*
* This file is supposed to represent an abstraction layer in between the pure XML used for VTK files,
* and the VTKWriter from dune-grid, which knows about grids. In theory, the dune-grid VTKWriter
* could use this class to simplify its own code. More importantly, the VTKFile class allows to
* write files containing second-order geometries, which is currently not possible with the dune-grid
* VTKWriter.
*/
class VTKFile
{
public:
/** \brief Write the file to disk */
void write(const std::string& filename) const
{
int argc = 0;
char** argv;
Dune::MPIHelper& mpiHelper = Dune::MPIHelper::instance(argc,argv);

Oliver Sander
committed
std::string fullfilename = filename + ".vtu";
// Prepend rank and communicator size to the filename, if there are more than one process
if (mpiHelper.size() > 1)
fullfilename = getParallelPieceName(filename, "", mpiHelper.rank(), mpiHelper.size());

Oliver Sander
committed
// Write the pvtu file that ties together the different parts
if (mpiHelper.size() > 1 && mpiHelper.rank()==0)

Oliver Sander
committed
{
std::ofstream pvtuOutFile(getParallelName(filename, "", mpiHelper.size()));

Oliver Sander
committed
Dune::VTK::PVTUWriter writer(pvtuOutFile, Dune::VTK::unstructuredGrid);
writer.beginMain();
writer.beginPointData();
writer.addArray<float>("director0", 3);
writer.addArray<float>("director1", 3);
writer.addArray<float>("director2", 3);
writer.addArray<float>("zCoord", 1);
writer.endPointData();
writer.beginCellData();
writer.addArray<float>("mycelldata", 1);
writer.endCellData();

Oliver Sander
committed
// dump point coordinates
writer.beginPoints();
writer.addArray<float>("Coordinates", 3);
writer.endPoints();
for (int i=0; i<mpiHelper.size(); i++)
writer.addPiece(getParallelPieceName(filename, "", i, mpiHelper.size()));

Oliver Sander
committed
// finish main section
writer.endMain();
}
std::ofstream outFile(fullfilename);
// Write header
outFile << "<?xml version=\"1.0\"?>" << std::endl;
outFile << "<VTKFile type=\"UnstructuredGrid\" version=\"0.1\" byte_order=\"LittleEndian\">" << std::endl;
outFile << " <UnstructuredGrid>" << std::endl;
outFile << " <Piece NumberOfCells=\"" << cellOffsets_.size() << "\" NumberOfPoints=\"" << points_.size() << "\">" << std::endl;
// Write vertex coordinates
outFile << " <Points>" << std::endl;

Oliver Sander
committed
{ // extra parenthesis to control destruction of the pointsWriter object
Dune::VTK::AsciiDataArrayWriter<float> pointsWriter(outFile, "Coordinates", 3, Dune::Indent(4));
for (size_t i=0; i<points_.size(); i++)
for (int j=0; j<3; j++)
pointsWriter.write(points_[i][j]);
} // destructor of pointsWriter objects writes trailing </DataArray> to file

Oliver Sander
committed
outFile << " </Points>" << std::endl;
// Write elements
outFile << " <Cells>" << std::endl;

Oliver Sander
committed
{ // extra parenthesis to control destruction of the cellConnectivityWriter object
Dune::VTK::AsciiDataArrayWriter<int> cellConnectivityWriter(outFile, "connectivity", 1, Dune::Indent(4));
for (size_t i=0; i<cellConnectivity_.size(); i++)
cellConnectivityWriter.write(cellConnectivity_[i]);

Oliver Sander
committed
}

Oliver Sander
committed
{ // extra parenthesis to control destruction of the writer object
Dune::VTK::AsciiDataArrayWriter<int> cellOffsetsWriter(outFile, "offsets", 1, Dune::Indent(4));
for (size_t i=0; i<cellOffsets_.size(); i++)
cellOffsetsWriter.write(cellOffsets_[i]);
}

Oliver Sander
committed

Oliver Sander
committed
{ // extra parenthesis to control destruction of the writer object
Dune::VTK::AsciiDataArrayWriter<unsigned int> cellTypesWriter(outFile, "types", 1, Dune::Indent(4));
for (size_t i=0; i<cellTypes_.size(); i++)
cellTypesWriter.write(cellTypes_[i]);
}

Oliver Sander
committed
outFile << " </Cells>" << std::endl;
//////////////////////////////////////////////////
// Point data
//////////////////////////////////////////////////

Oliver Sander
committed
outFile << " <PointData Scalars=\"zCoord\" Vectors=\"director0\">" << std::endl;
// Z coordinate for better visualization of wrinkles

Oliver Sander
committed
{ // extra parenthesis to control destruction of the writer object
Dune::VTK::AsciiDataArrayWriter<float> zCoordWriter(outFile, "zCoord", 1, Dune::Indent(4));
for (size_t i=0; i<zCoord_.size(); i++)
zCoordWriter.write(zCoord_[i]);
}

Oliver Sander
committed
// The three director fields
for (size_t i=0; i<3; i++)
{

Oliver Sander
committed
Dune::VTK::AsciiDataArrayWriter<float> directorWriter(outFile, "director" + std::to_string(i), 3, Dune::Indent(4));

Oliver Sander
committed
for (size_t j=0; j<directors_[i].size(); j++)

Oliver Sander
committed
for (int k=0; k<3; k++)
directorWriter.write(directors_[i][j][k]);

Oliver Sander
committed
}
outFile << " </PointData>" << std::endl;
//////////////////////////////////////////////////
// Cell data
//////////////////////////////////////////////////
if (cellData_.size() > 0)
{
outFile << " <CellData>" << std::endl;

Oliver Sander
committed
{ // extra parenthesis to control destruction of the writer object
Dune::VTK::AsciiDataArrayWriter<float> cellDataWriter(outFile, "mycelldata", 1, Dune::Indent(4));
for (size_t i=0; i<cellData_.size(); i++)
cellDataWriter.write(cellData_[i]);
}
outFile << " </CellData>" << std::endl;
}
//////////////////////////////////////////////////
// Write footer
//////////////////////////////////////////////////

Oliver Sander
committed
outFile << " </Piece>" << std::endl;
outFile << " </UnstructuredGrid>" << std::endl;
outFile << "</VTKFile>" << std::endl;
}
/** \brief Read a VTKFile object from a file
*
* This method uses TinyXML2. If you do not have TinyXML2 installed the code will simply throw a NotImplemented exception.
*/
void read(const std::string& filename)
{
int argc = 0;
char** argv;
Dune::MPIHelper& mpiHelper = Dune::MPIHelper::instance(argc,argv);

Oliver Sander
committed
std::string fullfilename = filename + ".vtu";
// Prepend rank and communicator size to the filename, if there are more than one process
if (mpiHelper.size() > 1)
fullfilename = getParallelPieceName(filename, "", mpiHelper.rank(), mpiHelper.size());

Oliver Sander
committed
#if ! HAVE_TINYXML2
DUNE_THROW(Dune::NotImplemented, "You need TinyXML2 for vtk file reading!");
#else
tinyxml2::XMLDocument doc;
if (int error = doc.LoadFile(fullfilename.c_str()) != tinyxml2::XML_SUCCESS)
{
std::cout << "Error: " << error << std::endl;

Oliver Sander
committed
DUNE_THROW(Dune::IOError, "Couldn't open the file '" << fullfilename << "'");
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
// Get number of cells and number of points
tinyxml2::XMLElement* pieceElement = doc.FirstChildElement( "VTKFile" )->FirstChildElement( "UnstructuredGrid" )->FirstChildElement( "Piece" );
int numberOfCells;
int numberOfPoints;
pieceElement->QueryIntAttribute( "NumberOfCells", &numberOfCells );
pieceElement->QueryIntAttribute( "NumberOfPoints", &numberOfPoints );
//////////////////////////////////
// Read point coordinates
//////////////////////////////////
points_.resize(numberOfPoints);
tinyxml2::XMLElement* pointsElement = pieceElement->FirstChildElement( "Points" )->FirstChildElement( "DataArray" );
std::stringstream coordsStream(pointsElement->GetText());
double inDouble;
size_t i=0;
while (coordsStream >> inDouble)
{
points_[i/3][i%3] = inDouble;
i++;
}
///////////////////////////////////
// Read cells
///////////////////////////////////
tinyxml2::XMLElement* cellsElement = pieceElement->FirstChildElement( "Cells" )->FirstChildElement( "DataArray" );
for (int i=0; i<3; i++)
{
int inInt;
if (cellsElement->Attribute("Name", "connectivity"))
{
std::stringstream connectivityStream(cellsElement->GetText());
while (connectivityStream >> inInt)
cellConnectivity_.push_back(inInt);
}
if (cellsElement->Attribute("Name", "offsets"))
{
std::stringstream offsetsStream(cellsElement->GetText());
while (offsetsStream >> inInt)
cellOffsets_.push_back(inInt);
}
if (cellsElement->Attribute("Name", "types"))
{
std::stringstream typesStream(cellsElement->GetText());
while (typesStream >> inInt)
cellTypes_.push_back(inInt);
}
cellsElement = cellsElement->NextSiblingElement();
}
/////////////////////////////////////
// Read point data
/////////////////////////////////////
tinyxml2::XMLElement* pointDataElement = pieceElement->FirstChildElement( "PointData" )->FirstChildElement( "DataArray" );
for (int i=0; i<4; i++)
{
size_t j=0;
std::stringstream directorStream(pointDataElement->GetText());
if (pointDataElement->Attribute("Name", "director0"))
{
directors_[0].resize(numberOfPoints);
while (directorStream >> inDouble)
{
directors_[0][j/3][j%3] = inDouble;
j++;
}
}
if (pointDataElement->Attribute("Name", "director1"))
{
directors_[1].resize(numberOfPoints);
while (directorStream >> inDouble)
{
directors_[1][j/3][j%3] = inDouble;
j++;
}
}
if (pointDataElement->Attribute("Name", "director2"))
{
directors_[2].resize(numberOfPoints);
while (directorStream >> inDouble)
{
directors_[2][j/3][j%3] = inDouble;
j++;
}
}
pointDataElement = pointDataElement->NextSiblingElement();
}
#endif
}

Oliver Sander
committed
std::vector<Dune::FieldVector<double,3> > points_;
std::vector<int> cellConnectivity_;
std::vector<int> cellOffsets_;
std::vector<int> cellTypes_;
std::vector<double> zCoord_;
std::vector<double> cellData_;

Oliver Sander
committed
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
std::array<std::vector<Dune::FieldVector<double,3> >, 3 > directors_;
private:
/** \brief Extend filename to contain communicator rank and size
*
* Copied from dune-grid vtkwriter.hh
*/
static std::string getParallelPieceName(const std::string& name,
const std::string& path,
int commRank, int commSize)
{
std::ostringstream s;
if(path.size() > 0) {
s << path;
if(path[path.size()-1] != '/')
s << '/';
}
s << 's' << std::setw(4) << std::setfill('0') << commSize << '-';
s << 'p' << std::setw(4) << std::setfill('0') << commRank << '-';
s << name;
if (true) //(GridType::dimension > 1)
s << ".vtu";
else
s << ".vtp";
return s.str();
}
/** \brief Extend filename to contain communicator rank and size
*
* Copied from dune-grid vtkwriter.hh
*/
static std::string getParallelName(const std::string& name,
const std::string& path,
int commSize)
{
std::ostringstream s;
if(path.size() > 0) {
s << path;
if(path[path.size()-1] != '/')
s << '/';
}
s << 's' << std::setw(4) << std::setfill('0') << commSize << '-';
s << name;
if (true) //(GridType::dimension > 1)
s << ".pvtu";
else
s << ".pvtp";
return s.str();
}
};
}
}