/* 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