/* This file is part of the OpenLB library
*
* Copyright (C) 2016-2017 Albert Mink, Maximilian Gaedtke, Markus Morhard Mathias J. Krause
* E-mail contact: info@openlb.net
* The most recent release of OpenLB can be downloaded at
*
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this program; if not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
/** \file
* A method to write vtk data for cuboid geometries
* (only for uniform grids) -- generic implementation.
*/
#ifndef SUPER_VTM_WRITER_3D_HH
#define SUPER_VTM_WRITER_3D_HH
#include
#include
#include
#include
#include "core/singleton.h"
#include "communication/loadBalancer.h"
#include "geometry/cuboidGeometry3D.h"
#include "communication/mpiManager.h"
#include "io/fileName.h"
#include "io/superVtmWriter3D.h"
#include "io/base64.h"
#include
#include
#include "zlib.h"
namespace olb {
template
SuperVTMwriter3D::SuperVTMwriter3D( const std::string& name, bool binary, bool compress)
: clout( std::cout,"SuperVTMwriter3D" ), _createFile(false), _name(name), _binary(binary), _compress(compress)
{}
template
void SuperVTMwriter3D::write(int iT)
{
int rank = 0;
#ifdef PARALLEL_MODE_MPI
rank = singleton::mpi().getRank();
#endif
// !!!!!!!!!!! check whether _pointerVec is empty
if ( _pointerVec.empty() ) {
clout << "Error: Did you add a Functor ?";
} else {
// to get first element _pointerVec
// problem if functors with different SuperStructure are stored
// since till now, there is only one origin
const auto it_begin = _pointerVec.cbegin();
CuboidGeometry3D const& cGeometry = (**it_begin).getSuperStructure().getCuboidGeometry();
// no gaps between vti files (cuboids)
(**it_begin).getSuperStructure().communicate();
LoadBalancer& load = (**it_begin).getSuperStructure().getLoadBalancer();
const T delta = cGeometry.getMotherCuboid().getDeltaR();
// PVD, owns all
if ( rank == 0 ) {
const std::string pathPVD = singleton::directories().getVtkOutDir()
+ createFileName( _name ) + ".pvd";
dataPVDmaster( iT, pathPVD, "data/" + createFileName( _name, iT ) + ".vtm" );
const std::string pathVTM = singleton::directories().getVtkOutDir()
+ "data/" + createFileName( _name, iT ) + ".vtm";
preambleVTM(pathVTM);
for (int iC = 0; iC < cGeometry.getNc(); iC++) {
dataVTM( iC, pathVTM, createFileName( _name, iT, iC) + ".vti" );
}
closeVTM(pathVTM);
}
// VTI, each process writes its cuboids
for (int iCloc = 0; iCloc < load.size(); iCloc++) {
// get piece/whole extent
const Vector extent0(-1,-1,-1);
const Vector extent1( cGeometry.get(load.glob(iCloc)).getExtend() );
const std::string fullNameVTI = singleton::directories().getVtkOutDir() + "data/"
+ createFileName( _name, iT, load.glob(iCloc) ) + ".vti";
// get dimension/extent for each cuboid
const int originLatticeR[4] = {load.glob(iCloc),0,0,0};
T originPhysR[3] = {T()};
cGeometry.getPhysR(originPhysR,originLatticeR);
preambleVTI(fullNameVTI, extent0, extent1, originPhysR, delta);
for (auto it : _pointerVec) {
dataArray(fullNameVTI, *it, load.glob(iCloc), extent1);
}
closePiece(fullNameVTI);
closeVTI(fullNameVTI);
}
}
}
template
void SuperVTMwriter3D::write(SuperF3D& f, int iT)
{
CuboidGeometry3D const& cGeometry = f.getSuperStructure().getCuboidGeometry();
LoadBalancer& load = f.getSuperStructure().getLoadBalancer();
// no gaps between vti files (cuboids)
f.getSuperStructure().communicate();
const T delta = cGeometry.getMotherCuboid().getDeltaR();
int rank = 0;
#ifdef PARALLEL_MODE_MPI
rank = singleton::mpi().getRank();
#endif
// write a pvd file, which links all vti files
// each vti file is written by one thread, which may own severals cuboids
if ( rank == 0 ) {
// master only
const std::string pathVTM = singleton::directories().getVtkOutDir()
+ createFileName( f.getName(), iT ) + ".vtm";
preambleVTM(pathVTM);
for (int iC = 0; iC < cGeometry.getNc(); iC++) {
const std::string nameVTI = "data/" + createFileName( f.getName(), iT, iC) + ".vti";
// puts name of .vti piece to a .pvd file [fullNamePVD]
dataVTM( iC, pathVTM, nameVTI );
}
closeVTM(pathVTM);
} // master only
for (int iCloc = 0; iCloc < load.size(); iCloc++) {
// get piece/whole extent
const Vector extent0(-1,-1,-1);
const Vector extent1( cGeometry.get(load.glob(iCloc)).getExtend() );
const std::string fullNameVTI = singleton::directories().getVtkOutDir() + "data/"
+ createFileName( f.getName(), iT, load.glob(iCloc) ) + ".vti";
// get dimension/extent for each cuboid
const int originLatticeR[4] = {load.glob(iCloc),0,0,0};
T originPhysR[3] = {T()};
cGeometry.getPhysR(originPhysR,originLatticeR);
preambleVTI(fullNameVTI, extent0, extent1, originPhysR, delta);
dataArray(fullNameVTI, f, load.glob(iCloc), extent1);
closePiece(fullNameVTI);
closeVTI(fullNameVTI);
} // cuboid
}
template
void SuperVTMwriter3D::write(std::shared_ptr> ptr_f, int iT)
{
write(*ptr_f, iT);
}
template
void SuperVTMwriter3D::createMasterFile()
{
int rank = 0;
#ifdef PARALLEL_MODE_MPI
rank = singleton::mpi().getRank();
#endif
if ( rank == 0 ) {
const std::string fullNamePVDmaster = singleton::directories().getVtkOutDir()
+ createFileName( _name ) + ".pvd";
preamblePVD(fullNamePVDmaster);
closePVD(fullNamePVDmaster);
_createFile = true;
}
}
template
void SuperVTMwriter3D::addFunctor(SuperF3D& f)
{
_pointerVec.push_back(&f);
}
template
void SuperVTMwriter3D::clearAddedFunctors()
{
_pointerVec.clear();
}
template
std::string SuperVTMwriter3D::getName() const
{
return _name;
}
////////////////////private member functions///////////////////////////////////
template
void SuperVTMwriter3D::preambleVTI (const std::string& fullName,
const Vector extent0, const Vector extent1, T origin[], T delta)
{
double d_delta = delta;
double d_origin[3] = {origin[0], origin[1], origin[2]};
std::ofstream fout(fullName, std::ios::trunc);
if (!fout) {
clout << "Error: could not open " << fullName << std::endl;
}
fout << "\n";
fout << "\n";
} else {
fout << "byte_order=\"LittleEndian\">\n";
}
fout << "\n";
fout << "\n";
fout << "\n";
fout.close();
}
template
void SuperVTMwriter3D::closeVTI(const std::string& fullNamePiece)
{
std::ofstream fout(fullNamePiece, std::ios::app );
if (!fout) {
clout << "Error: could not open " << fullNamePiece << std::endl;
}
fout << "\n";
fout << "\n";
fout.close();
}
template
void SuperVTMwriter3D::preamblePVD(const std::string& fullNamePVD)
{
std::ofstream fout(fullNamePVD, std::ios::trunc);
if (!fout) {
clout << "Error: could not open " << fullNamePVD << std::endl;
}
fout << "\n";
fout << "\n"
<< "\n";
fout.close();
}
template
void SuperVTMwriter3D::closePVD(const std::string& fullNamePVD)
{
std::ofstream fout(fullNamePVD, std::ios::app );
if (!fout) {
clout << "Error: could not open " << fullNamePVD << std::endl;
}
fout << "\n";
fout << "\n";
fout.close();
}
template
void SuperVTMwriter3D::preambleVTM(const std::string& fullNamePVD)
{
std::ofstream fout(fullNamePVD, std::ios::trunc);
if (!fout) {
clout << "Error: could not open " << fullNamePVD << std::endl;
}
fout << "\n";
fout << "\n"
<< "\n" ;
fout.close();
}
template
void SuperVTMwriter3D::closeVTM(const std::string& fullNamePVD)
{
std::ofstream fout(fullNamePVD, std::ios::app );
if (!fout) {
clout << "Error: could not open " << fullNamePVD << std::endl;
}
fout << "\n";
fout << "\n";
fout.close();
}
template
void SuperVTMwriter3D::dataVTM(int iC, const std::string& fullNamePVD,
const std::string& namePiece)
{
std::ofstream fout(fullNamePVD, std::ios::app);
if (!fout) {
clout << "Error: could not open " << fullNamePVD << std::endl;
}
fout << "\n";
fout << "\n"
<< "\n";
fout << "\n";
fout.close();
}
template
void SuperVTMwriter3D::dataPVDmaster(int iT,
const std::string& fullNamePVDMaster,
const std::string& namePiece)
{
std::ofstream fout(fullNamePVDMaster, std::ios::in | std::ios::out | std::ios::ate);
if (fout) {
fout.seekp(-25,std::ios::end); // jump -25 form the end of file to overwrite closePVD
fout << "\n";
fout.close();
closePVD(fullNamePVDMaster);
} else {
clout << "Error: could not open " << fullNamePVDMaster << std::endl;
}
}
template
void SuperVTMwriter3D::dataArray(const std::string& fullName,
SuperF3D& f, int iC, const Vector extent1)
{
std::ofstream fout( fullName, std::ios::out | std::ios::app );
if (!fout) {
clout << "Error: could not open " << fullName << std::endl;
}
fout << "\n";
} else {
fout << ">\n";
}
int i[4] = {iC, 0, 0, 0};
W evaluated[f.getTargetDim()];
for (int iDim = 0; iDim < f.getTargetDim(); ++iDim) {
evaluated[iDim] = W();
}
size_t numberOfFloats = f.getTargetDim() * (extent1[0]+2) * (extent1[1]+2) * (extent1[2]+2);
uint32_t binarySize = static_cast( numberOfFloats*sizeof(float) );
std::unique_ptr streamFloat(new float[numberOfFloats]); // stack may be too small
int itter = 0;
// fill buffer with functor data
for (i[3] = -1; i[3] < extent1[2]+1; ++i[3]) {
for (i[2] = -1; i[2] < extent1[1]+1; ++i[2]) {
for (i[1] = -1; i[1] < extent1[0]+1; ++i[1]) {
f(evaluated,i);
for (int iDim = 0; iDim < f.getTargetDim(); ++iDim) {
streamFloat[itter] = float( evaluated[iDim] );
++itter;
}
}
}
}
if (_compress) {
// char buffer for functor data
const unsigned char* charData = reinterpret_cast(streamFloat.get());
// buffer for compression
std::unique_ptr comprData(new unsigned char[ binarySize ]); // stack may be too small
// compress data (not yet decoded as base64) by zlib
uLongf sizeCompr = compressBound(binarySize);
compress2( comprData.get(), &sizeCompr, charData, binarySize, -1);
// encode prefix to base64 documented in http://www.earthmodels.org/software/vtk-and-paraview/vtk-file-formats
Base64Encoder prefixEncoder(fout, 4);
uint32_t prefix[4] = {1,binarySize,binarySize,static_cast(sizeCompr)};
prefixEncoder.encode(prefix, 4);
// encode compressed data to base64
Base64Encoder dataEncoder( fout, sizeCompr );
dataEncoder.encode(comprData.get(), sizeCompr);
} else if(_binary) {
// encode prefix to base64 documented in http://www.earthmodels.org/software/vtk-and-paraview/vtk-file-formats
Base64Encoder prefixEncoder(fout, 1);
prefixEncoder.encode(&binarySize, 1);
// write numbers from functor
Base64Encoder dataEncoder(fout, numberOfFloats);
dataEncoder.encode(streamFloat.get(),numberOfFloats);
} else {
for( size_t iOut = 0; iOut < numberOfFloats; ++iOut ) {
fout << streamFloat[iOut] << " ";
}
}
fout.close();
std::ofstream ffout( fullName, std::ios::out | std::ios::app );
if (!ffout) {
clout << "Error: could not open " << fullName << std::endl;
}
ffout << "\n\n";
ffout.close();
}
template
void SuperVTMwriter3D::closePiece(const std::string& fullNamePiece)
{
std::ofstream fout(fullNamePiece, std::ios::app );
if (!fout) {
clout << "Error: could not open " << fullNamePiece << std::endl;
}
fout << "\n";
fout << "\n";
fout.close();
}
} // namespace olb
#endif