OpenLB 1.7
Loading...
Searching...
No Matches
superVtmWriter3D.hh
Go to the documentation of this file.
1/* This file is part of the OpenLB library
2 *
3 * Copyright (C) 2016-2017 Albert Mink, Maximilian Gaedtke, Markus Morhard Mathias J. Krause
4 * E-mail contact: info@openlb.net
5 * The most recent release of OpenLB can be downloaded at
6 * <http://www.openlb.net/>
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * as published by the Free Software Foundation; either version 2
11 * of the License, or (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public
19 * License along with this program; if not, write to the Free
20 * Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
21 * Boston, MA 02110-1301, USA.
22*/
23
29#ifndef SUPER_VTM_WRITER_3D_HH
30#define SUPER_VTM_WRITER_3D_HH
31
32#include <fstream>
33#include <iostream>
34#include <iomanip>
35#include <string>
36#include "core/singleton.h"
40#include "io/fileName.h"
41#include "io/superVtmWriter3D.h"
42#include "io/base64.h"
43
44#include <stdio.h>
45#include <assert.h>
46#include <zlib.h>
47
48
49
50namespace olb {
51
52
53template<typename T, typename OUT_T, typename W>
54SuperVTMwriter3D<T,OUT_T,W>::SuperVTMwriter3D( const std::string& name, int overlap, bool binary, bool compress)
55 : clout( std::cout,"SuperVTMwriter3D" ), _createFile(false), _name(name), _overlap(overlap), _binary(binary), _compress(compress)
56{
57 static_assert(std::is_same_v<OUT_T, float> || std::is_same_v<OUT_T, double>,
58 "OUT_T must be either float or double");
59}
60
61template<typename T, typename OUT_T, typename W>
63 const std::string& name, int overlap, bool binary, bool compress)
64 : SuperVTMwriter3D(name, overlap, binary, compress)
65{
66 _cGeometry = &cGeometry;
67}
68
69template<typename T, typename OUT_T, typename W>
71{
72 // update to prevent gaps between vti files / cuboids
73 for (SuperF3D<T,W>* f : _pointerVec) {
74 f->getSuperStructure().communicate();
75 }
76
77 // to get first element _pointerVec
78 // problem if functors with different SuperStructure are stored
79 // since till now, there is only one origin
80 const auto it_begin = _pointerVec.cbegin();
81 if (!_cGeometry && it_begin == _pointerVec.end()) {
82 throw std::runtime_error("No functor to write");
83 }
84 CuboidGeometry3D<T> const& cGeometry = _cGeometry ? *_cGeometry : (**it_begin).getSuperStructure().getCuboidGeometry();
85
86 // PVD, owns all
87 writePVD(iT);
88 if (_cGeometry) {
89 // Write globally if cuboid geometry is provided
90 for (int iC = 0; iC < cGeometry.getNc(); ++iC) {
91 writeGlobalVTI(iT, iC);
92 }
93 } else {
94 LoadBalancer<T>& load = (**it_begin).getSuperStructure().getLoadBalancer();
95 // VTI, each process writes its cuboids
96 for (int iCloc = 0; iCloc < load.size(); iCloc++) {
97 writeVTI(iT, iCloc);
98 }
99 }
100}
101
102template<typename T, typename OUT_T, typename W>
104{
105 // to get first element _pointerVec
106 // problem if functors with different SuperStructure are stored
107 // since till now, there is only one origin
108 const auto it_begin = _pointerVec.cbegin();
109 CuboidGeometry3D<T> const& cGeometry = _cGeometry ? *_cGeometry : (**it_begin).getSuperStructure().getCuboidGeometry();
110
111 // PVD, owns all
112 if (singleton::mpi().isMainProcessor()) {
113 const std::string pathPVD = singleton::directories().getVtkOutDir()
114 + createFileName(_name) + ".pvd";
115 dataPVDmaster(iT, pathPVD, "data/" + createFileName(_name, iT) + ".vtm");
116
117 const std::string pathVTM = singleton::directories().getVtkOutDir()
118 + "data/" + createFileName(_name, iT) + ".vtm";
119 preambleVTM(pathVTM);
120 for (int iC = 0; iC < cGeometry.getNc(); iC++) {
121 dataVTM(iC, pathVTM, createFileName(_name, iT, iC) + ".vti" );
122 }
123 closeVTM(pathVTM);
124 }
125}
126
127template<typename T, typename OUT_T, typename W>
129{
130 const auto it_begin = _pointerVec.cbegin();
131 CuboidGeometry3D<T> const& cGeometry = _cGeometry ? *_cGeometry : (**it_begin).getSuperStructure().getCuboidGeometry();
132 const T delta = cGeometry.getMotherCuboid().getDeltaR();
133
134 // get piece/whole extent
135 const Vector<int,3> extent0(-_overlap,-_overlap,-_overlap);
136 const Vector<int,3> extent1(cGeometry.get(iC).getExtent());
137
138 const std::string fullNameVTI = singleton::directories().getVtkOutDir() + "data/"
139 + createFileName(_name, iT, iC) + ".vti";
140
141 // get dimension/extent for each cuboid
142 const int originLatticeR[4] = {iC,0,0,0};
143 T originPhysR[3] = {T()};
144 cGeometry.getPhysR(originPhysR,originLatticeR);
145
146 preambleVTI(fullNameVTI, extent0, (extent1+_overlap-1), originPhysR, delta);
147 for (auto it : _pointerVec) {
148 dataArray(fullNameVTI, *it, iC, extent1);
149 }
150 closePiece(fullNameVTI);
151 closeVTI(fullNameVTI);
152}
153
154template<typename T, typename OUT_T, typename W>
156{
157 const auto it_begin = _pointerVec.cbegin();
158 CuboidGeometry3D<T> const& cGeometry = (**it_begin).getSuperStructure().getCuboidGeometry();
159 LoadBalancer<T>& load = (**it_begin).getSuperStructure().getLoadBalancer();
160 const T delta = cGeometry.getMotherCuboid().getDeltaR();
161
162 // get piece/whole extent
163 const Vector<int,3> extent0(-_overlap,-_overlap,-_overlap);
164 const Vector<int,3> extent1(cGeometry.get(load.glob(iCloc)).getExtent());
165
166 const std::string fullNameVTI = singleton::directories().getVtkOutDir() + "data/"
167 + createFileName(_name, iT, load.glob(iCloc)) + ".vti";
168
169 // get dimension/extent for each cuboid
170 const int originLatticeR[4] = {load.glob(iCloc),0,0,0};
171 T originPhysR[3] = {T()};
172 cGeometry.getPhysR(originPhysR,originLatticeR);
173
174 preambleVTI(fullNameVTI, extent0, (extent1+_overlap-1), originPhysR, delta);
175 for (auto it : _pointerVec) {
176 dataArray(fullNameVTI, *it, load.glob(iCloc), extent1);
177 }
178 closePiece(fullNameVTI);
179 closeVTI(fullNameVTI);
180}
181
182template<typename T, typename OUT_T, typename W>
184{
187 // no gaps between vti files (cuboids)
189 const T delta = cGeometry.getMotherCuboid().getDeltaR();
190
191 int rank = 0;
192#ifdef PARALLEL_MODE_MPI
193 rank = singleton::mpi().getRank();
194#endif
195
196 // write a pvd file, which links all vti files
197 // each vti file is written by one thread, which may own severals cuboids
198 if ( rank == 0 ) {
199 // master only
200 const std::string pathVTM = singleton::directories().getVtkOutDir()
201 + createFileName( f.getName(), iT ) + ".vtm";
202
203 preambleVTM(pathVTM);
204 for (int iC = 0; iC < cGeometry.getNc(); iC++) {
205 const std::string nameVTI = "data/" + createFileName( f.getName(), iT, iC) + ".vti";
206 // puts name of .vti piece to a .pvd file [fullNamePVD]
207 dataVTM( iC, pathVTM, nameVTI );
208 }
209 closeVTM(pathVTM);
210 } // master only
211
212 for (int iCloc = 0; iCloc < load.size(); iCloc++) {
213 // get piece/whole extent
214 const Vector<int,3> extent0(-_overlap,-_overlap,-_overlap);
215 const Vector<int,3> extent1( cGeometry.get(load.glob(iCloc)).getExtent());
216
217 const std::string fullNameVTI = singleton::directories().getVtkOutDir() + "data/"
218 + createFileName( f.getName(), iT, load.glob(iCloc) ) + ".vti";
219
220 // get dimension/extent for each cuboid
221 const int originLatticeR[4] = {load.glob(iCloc),0,0,0};
222 T originPhysR[3] = {T()};
223 cGeometry.getPhysR(originPhysR,originLatticeR);
224
225 preambleVTI(fullNameVTI, extent0, (extent1+_overlap-1.), originPhysR, delta);
226
227 dataArray(fullNameVTI, f, load.glob(iCloc), extent1);
228 closePiece(fullNameVTI);
229 closeVTI(fullNameVTI);
230 } // cuboid
231}
232
233
234template<typename T, typename OUT_T, typename W>
235void SuperVTMwriter3D<T,OUT_T,W>::write(std::shared_ptr<SuperF3D<T,W>> ptr_f, int iT)
236{
237 write(*ptr_f, iT);
238}
239
240template<typename T, typename OUT_T, typename W>
242{
243 int rank = 0;
244#ifdef PARALLEL_MODE_MPI
245 rank = singleton::mpi().getRank();
246#endif
247 if ( rank == 0 ) {
248 const std::string fullNamePVDmaster = singleton::directories().getVtkOutDir()
249 + createFileName( _name ) + ".pvd";
250 preamblePVD(fullNamePVDmaster);
251 closePVD(fullNamePVDmaster);
252 _createFile = true;
253 }
254}
255
256template<typename T, typename OUT_T, typename W>
258{
259 _pointerVec.push_back(&f);
260}
261
262template<typename T, typename OUT_T, typename W>
263void SuperVTMwriter3D<T,OUT_T,W>::addFunctor(SuperF3D<T,W>& f, const std::string& functorName)
264{
265 f.getName() = functorName;
266 _pointerVec.push_back(&f);
267}
268
269template<typename T, typename OUT_T, typename W>
271{
272 _pointerVec.clear();
273}
274
275template<typename T, typename OUT_T, typename W>
277{
278 return _name;
279}
280
281
282
283
285template<typename T, typename OUT_T, typename W>
286void SuperVTMwriter3D<T,OUT_T,W>::preambleVTI (const std::string& fullName,
287 const Vector<int,3> extent0, const Vector<int,3> extent1, T origin[], T delta)
288{
289 const BaseType<T> d_delta = delta;
290 const BaseType<T> d_origin[3] = {origin[0], origin[1], origin[2]};
291
292 std::ofstream fout(fullName, std::ios::trunc);
293 if (!fout) {
294 clout << "Error: could not open " << fullName << std::endl;
295 }
296 fout << "<?xml version=\"1.0\"?>\n";
297 fout << "<VTKFile type=\"ImageData\" version=\"0.1\" ";
298 if (_compress) {
299 fout << "byte_order=\"LittleEndian\" compressor=\"vtkZLibDataCompressor\">\n";
300 }
301 else {
302 fout << "byte_order=\"LittleEndian\">\n";
303 }
304 fout << "<ImageData WholeExtent=\""
305 << extent0[0] <<" "<< extent1[0] <<" "
306 << extent0[1] <<" "<< extent1[1] <<" "
307 << extent0[2] <<" "<< extent1[2]
308 << "\" Origin=\"" << d_origin[0] << " " << d_origin[1] << " " << d_origin[2]
309 << "\" Spacing=\"" << d_delta << " " << d_delta << " " << d_delta << "\">\n";
310 fout << "<Piece Extent=\""
311 << extent0[0] <<" "<< extent1[0] <<" "
312 << extent0[1] <<" "<< extent1[1] <<" "
313 << extent0[2] <<" "<< extent1[2] <<"\">\n";
314 fout << "<PointData>\n";
315 fout.close();
316}
317
318template<typename T, typename OUT_T, typename W>
319void SuperVTMwriter3D<T,OUT_T,W>::closeVTI(const std::string& fullNamePiece)
320{
321 std::ofstream fout(fullNamePiece, std::ios::app );
322 if (!fout) {
323 clout << "Error: could not open " << fullNamePiece << std::endl;
324 }
325 fout << "</ImageData>\n";
326 fout << "</VTKFile>\n";
327 fout.close();
328}
329
330template<typename T, typename OUT_T, typename W>
331void SuperVTMwriter3D<T,OUT_T,W>::preamblePVD(const std::string& fullNamePVD)
332{
333 std::ofstream fout(fullNamePVD, std::ios::trunc);
334 if (!fout) {
335 clout << "Error: could not open " << fullNamePVD << std::endl;
336 }
337 fout << "<?xml version=\"1.0\"?>\n";
338 fout << "<VTKFile type=\"Collection\" version=\"0.1\" "
339 << "byte_order=\"LittleEndian\">\n"
340 << "<Collection>\n";
341 fout.close();
342}
343
344template<typename T, typename OUT_T, typename W>
345void SuperVTMwriter3D<T,OUT_T,W>::closePVD(const std::string& fullNamePVD)
346{
347 std::ofstream fout(fullNamePVD, std::ios::app );
348 if (!fout) {
349 clout << "Error: could not open " << fullNamePVD << std::endl;
350 }
351 fout << "</Collection>\n";
352 fout << "</VTKFile>\n";
353 fout.close();
354}
355
356template<typename T, typename OUT_T, typename W>
357void SuperVTMwriter3D<T,OUT_T,W>::preambleVTM(const std::string& fullNamePVD)
358{
359 std::ofstream fout(fullNamePVD, std::ios::trunc);
360 if (!fout) {
361 clout << "Error: could not open " << fullNamePVD << std::endl;
362 }
363 fout << "<?xml version=\"1.0\"?>\n";
364 fout << "<VTKFile type=\"vtkMultiBlockDataSet\" version=\"1.0\" "
365 << "byte_order=\"LittleEndian\">\n"
366 << "<vtkMultiBlockDataSet>\n" ;
367 fout.close();
368}
369
370template<typename T, typename OUT_T, typename W>
371void SuperVTMwriter3D<T,OUT_T,W>::closeVTM(const std::string& fullNamePVD)
372{
373 std::ofstream fout(fullNamePVD, std::ios::app );
374 if (!fout) {
375 clout << "Error: could not open " << fullNamePVD << std::endl;
376 }
377 fout << "</vtkMultiBlockDataSet>\n";
378 fout << "</VTKFile>\n";
379 fout.close();
380}
381
382template<typename T, typename OUT_T, typename W>
383void SuperVTMwriter3D<T,OUT_T,W>::dataVTM(int iC, const std::string& fullNamePVD,
384 const std::string& namePiece)
385{
386 std::ofstream fout(fullNamePVD, std::ios::app);
387 if (!fout) {
388 clout << "Error: could not open " << fullNamePVD << std::endl;
389 }
390 fout << "<Block index=\"" << iC << "\" >\n";
391 fout << "<DataSet index= \"0\" " << "file=\"" << namePiece << "\">\n"
392 << "</DataSet>\n";
393 fout << "</Block>\n";
394 fout.close();
395}
396
397template<typename T, typename OUT_T, typename W>
398void SuperVTMwriter3D<T,OUT_T,W>::dataPVDmaster(int iT,
399 const std::string& fullNamePVDMaster,
400 const std::string& namePiece)
401{
402 std::ofstream fout(fullNamePVDMaster, std::ios::in | std::ios::out | std::ios::ate);
403 if (fout) {
404 fout.seekp(-25,std::ios::end); // jump -25 form the end of file to overwrite closePVD
405
406 fout << "<DataSet timestep=\"" << iT << "\" "
407 << "group=\"\" part=\"\" "
408 << "file=\"" << namePiece << "\"/>\n";
409 fout.close();
410 closePVD(fullNamePVDMaster);
411 }
412 else {
413 clout << "Error: could not open " << fullNamePVDMaster << std::endl;
414 }
415}
416
417template<typename T, typename OUT_T, typename W>
418void SuperVTMwriter3D<T,OUT_T,W>::dataArray(const std::string& fullName,
419 SuperF3D<T,W>& f, int iC, const Vector<int,3> extent1)
420{
421 std::ofstream fout( fullName, std::ios::out | std::ios::app );
422 if (!fout) {
423 clout << "Error: could not open " << fullName << std::endl;
424 }
425
426 if constexpr (std::is_same_v<OUT_T, float>) {
427 fout << "<DataArray type=\"Float32\" Name=\"" << f.getName() << "\" NumberOfComponents=\"" << f.getTargetDim() << "\" ";
428 }
429 else if constexpr (std::is_same_v<OUT_T, double>) {
430 fout << "<DataArray type=\"Float64\" Name=\"" << f.getName() << "\" NumberOfComponents=\"" << f.getTargetDim() << "\" ";
431 }
432 if (_compress || _binary) {
433 fout << "format=\"binary\" encoding=\"base64\">\n";
434 }
435 else {
436 fout << ">\n";
437 }
438
439 int i[4] = {iC, 0, 0, 0};
440 W evaluated[f.getTargetDim()];
441 for (int iDim = 0; iDim < f.getTargetDim(); ++iDim) {
442 evaluated[iDim] = W();
443 }
444
445 size_t numberOfFloats = f.getTargetDim() * (extent1[0]+2*_overlap) * (extent1[1]+2*_overlap) * (extent1[2]+2*_overlap);
446 uint32_t binarySize = static_cast<uint32_t>( numberOfFloats*sizeof(float) );
447
448 std::unique_ptr<float[]> streamFloat(new float[numberOfFloats]); // stack may be too small
449 int itter = 0;
450 // fill buffer with functor data
451 for (i[3] = -_overlap; i[3] < extent1[2]+_overlap; ++i[3]) {
452 for (i[2] = -_overlap; i[2] < extent1[1]+_overlap; ++i[2]) {
453 for (i[1] = -_overlap; i[1] < extent1[0]+_overlap; ++i[1]) {
454 f(evaluated,i);
455 for (int iDim = 0; iDim < f.getTargetDim(); ++iDim) {
456 streamFloat[itter] = float( evaluated[iDim] );
457 ++itter;
458 }
459 }
460 }
461 }
462
463 if (_compress) {
464 // char buffer for functor data
465 const unsigned char* charData = reinterpret_cast<unsigned char*>(streamFloat.get());
466 // buffer for compression
467 std::unique_ptr<unsigned char[]> comprData(new unsigned char[ binarySize ]); // stack may be too small
468
469 // compress data (not yet decoded as base64) by zlib
470 uLongf sizeCompr = compressBound(binarySize);
471 compress2( comprData.get(), &sizeCompr, charData, binarySize, -1);
472
473 // encode prefix to base64 documented in http://www.earthmodels.org/software/vtk-and-paraview/vtk-file-formats
474 Base64Encoder<uint32_t> prefixEncoder(fout, 4);
475 uint32_t prefix[4] = {1,binarySize,binarySize,static_cast<uint32_t>(sizeCompr)};
476 prefixEncoder.encode(prefix, 4);
477
478 // encode compressed data to base64
479 Base64Encoder<unsigned char> dataEncoder( fout, sizeCompr );
480 dataEncoder.encode(comprData.get(), sizeCompr);
481 }
482 else if (_binary) {
483 // encode prefix to base64 documented in http://www.earthmodels.org/software/vtk-and-paraview/vtk-file-formats
484 Base64Encoder<uint32_t> prefixEncoder(fout, 1);
485 prefixEncoder.encode(&binarySize, 1);
486 // write numbers from functor
487 Base64Encoder<float> dataEncoder(fout, numberOfFloats);
488 dataEncoder.encode(streamFloat.get(),numberOfFloats);
489 }
490 else {
491 for ( size_t iOut = 0; iOut < numberOfFloats; ++iOut ) {
492 fout << streamFloat[iOut] << " ";
493 }
494 }
495 fout.close();
496
497 std::ofstream ffout( fullName, std::ios::out | std::ios::app );
498 if (!ffout) {
499 clout << "Error: could not open " << fullName << std::endl;
500 }
501 ffout << "\n</DataArray>\n";
502 ffout.close();
503}
504
505template<typename T, typename OUT_T, typename W>
506void SuperVTMwriter3D<T,OUT_T,W>::closePiece(const std::string& fullNamePiece)
507{
508 std::ofstream fout(fullNamePiece, std::ios::app );
509 if (!fout) {
510 clout << "Error: could not open " << fullNamePiece << std::endl;
511 }
512 fout << "</PointData>\n";
513 fout << "</Piece>\n";
514 fout.close();
515}
516
517
518} // namespace olb
519
520#endif
A cuboid geometry represents a voxel mesh.
Cuboid3D< T > & get(int iC)
Read and write access to a single cuboid.
int getNc() const
Returns the number of cuboids in the structure.
Cuboid3D< T > getMotherCuboid()
Returns the smallest cuboid that includes all cuboids of the structure.
void getPhysR(T physR[3], const int &iCglob, const int &iX, const int &iY, const int &iZ) const
Returns the physical position to the given lattice position respecting periodicity for the overlap no...
std::string & getName()
read and write access to name
Definition genericF.hh:51
Base class for all LoadBalancer.
int glob(int loc) const
represents all functors that operate on a SuperStructure<T,3> in general
SuperStructure< T, 3 > & getSuperStructure()
CuboidGeometry< T, D > & getCuboidGeometry()
Read and write access to cuboid geometry.
virtual void communicate()
LoadBalancer< T > & getLoadBalancer()
Read and write access to the load balancer.
SuperVTMwriter3D writes any SuperF3D to vtk-based output files.
std::string getName() const
getter for _name
void write(int iT=0)
writes functors stored in pointerVec every process writes a vti file with data for each of its cuboid...
void createMasterFile()
have to be called before calling write(int iT=0), since it creates
void writeGlobalVTI(int iT, int iC)
writes the vti file for cuboid iC at timestep iT
void clearAddedFunctors()
to clear stored functors, not yet used due to lack of necessity
SuperVTMwriter3D(const std::string &name, int overlap=1, bool binary=true, bool compress=true)
Construct writer for functor output.
void addFunctor(SuperF3D< T, W > &f)
put functor to _pointerVec to simplify writing process of several functors
void writeVTI(int iT, int iCloc)
writes the vti file for cuboid iCloc at timestep iT
void writePVD(int iT)
writes only the linking pvd file for timestep iT, blocks must be written separately (e....
Plain old scalar vector.
Definition vector.h:47
std::string getVtkOutDir() const
Definition singleton.h:97
int getRank() const
Returns the process ID.
The description of a vector of 3D cuboid – header file.
These functions help you to create file names.
Wrapper functions that simplify the use of MPI.
MpiManager & mpi()
Directories & directories()
Definition singleton.h:150
Top level namespace for all of OpenLB.
std::string createFileName(std::string name)
for .pvd masterFile
Definition fileName.hh:34
typename util::BaseTypeHelper< T >::type BaseType
Definition baseType.h:59
Definition of singletons: global, publicly available information.
A method to write vtk data for cuboid geometries (only for uniform grids) – header file.