diff --git a/vortexje/field-writers/vtk-field-writer.cpp b/vortexje/field-writers/vtk-field-writer.cpp index e18d2d3..e5dd687 100644 --- a/vortexje/field-writers/vtk-field-writer.cpp +++ b/vortexje/field-writers/vtk-field-writer.cpp @@ -11,6 +11,7 @@ #include #include +#include using namespace std; using namespace Eigen; @@ -27,6 +28,17 @@ VTKFieldWriter::file_extension() const return ".vtk"; } +const char * +VTKFieldWriter::float_str() const +{ + switch(float_type) { + case nstream::FLOAT: + return "FLOAT"; + default: + return "DOUBLE"; + } +} + /** Logs the velocity vector field into a VTK file. The grid is the smallest box encompassing all nodes of all surfaces, expanded in the X, Y, and Z @@ -81,17 +93,18 @@ VTKFieldWriter::write_velocity_field(const Solver &solver, const std::string &fi cout << "VTKFieldWriter: Saving velocity vector field to " << filename << "." << endl; ofstream f; - f.open(filename.c_str()); + f.open(filename.c_str(), ios::binary); + nstream::onstream nf(f, mode, float_type, nstream::BIGENDIAN); - write_preamble(f, x_min, y_min, z_min, dx, dy, dz, nx, ny, nz); + write_preamble(f, nf, x_min, y_min, z_min, dx, dy, dz, nx, ny, nz); // Velocity vector field; - f << "VECTORS Velocity double" << endl; + f << "VECTORS Velocity " << float_str() << endl; vector >::const_iterator it; for (it = velocities.begin(); it != velocities.end(); it++) { Vector3d v = *it; - f << v(0) << " " << v(1) << " " << v(2) << endl; + nf << v(0) << " " << v(1) << " " << v(2) << endl; } // Close file: @@ -155,9 +168,10 @@ VTKFieldWriter::write_velocity_potential_field(const Solver &solver, const std:: cout << "VTKFieldWriter: Saving velocity potential field to " << filename << "." << endl; ofstream f; - f.open(filename.c_str()); + f.open(filename.c_str(), ios::binary); + nstream::onstream nf(f, mode, float_type, nstream::BIGENDIAN); - write_preamble(f, x_min, y_min, z_min, dx, dy, dz, nx, ny, nz); + write_preamble(f, nf, x_min, y_min, z_min, dx, dy, dz, nx, ny, nz); // Velocity potential field: f << "SCALARS VelocityPotential double 1" << endl; @@ -166,8 +180,7 @@ VTKFieldWriter::write_velocity_potential_field(const Solver &solver, const std:: vector::const_iterator it; for (it = velocity_potentials.begin(); it != velocity_potentials.end(); it++) { double p = *it; - - f << p << endl; + nf << p << endl; } // Close file: @@ -181,35 +194,35 @@ VTKFieldWriter::write_velocity_potential_field(const Solver &solver, const std:: Write preamble for VTK output file. */ void -VTKFieldWriter::write_preamble(ofstream &f, +VTKFieldWriter::write_preamble(ofstream &f, nstream::onstream &nf, double x_min, double y_min, double z_min, double dx, double dy, double dz, int nx, int ny, int nz) const { f << "# vtk DataFile Version 2.0" << endl; f << "FieldData" << endl; - f << "ASCII" << endl; + f << (mode==nstream::BINARY? "BINARY" : "ASCII") << endl; f << "DATASET RECTILINEAR_GRID" << endl; f << "DIMENSIONS " << nx << " " << ny << " " << nz << endl; - f << "X_COORDINATES " << nx << " double" << endl; + f << "X_COORDINATES " << nx << " " << float_str() << endl; for (int i = 0; i < nx; i++) { if (i > 0) - f << ' '; - f << x_min + i * dx; + nf << ' '; + nf << x_min + i * dx; } f << endl; - f << "Y_COORDINATES " << ny << " double" << endl; + f << "Y_COORDINATES " << ny << " " << float_str() << endl; for (int i = 0; i < ny; i++) { if (i > 0) - f << ' '; - f << y_min + i * dy; + nf << ' '; + nf << y_min + i * dy; } f << endl; - f << "Z_COORDINATES " << nz << " double" << endl; + f << "Z_COORDINATES " << nz << " " << float_str() << endl; for (int i = 0; i < nz; i++) { if (i > 0) - f << ' '; - f << z_min + i * dz; + nf << ' '; + nf << z_min + i * dz; } f << endl; diff --git a/vortexje/field-writers/vtk-field-writer.hpp b/vortexje/field-writers/vtk-field-writer.hpp index a766ce1..1ea5467 100644 --- a/vortexje/field-writers/vtk-field-writer.hpp +++ b/vortexje/field-writers/vtk-field-writer.hpp @@ -13,6 +13,7 @@ #include #include +#include namespace Vortexje { @@ -24,7 +25,12 @@ namespace Vortexje */ class VTKFieldWriter : public FieldWriter { + nstream::serial_mode_e mode; + nstream::float_type_e float_type; public: + VTKFieldWriter(nstream::serial_mode_e m = nstream::ASCII, + nstream::float_type_e ft = nstream::DOUBLE) + : mode(m), float_type(ft) {} const char *file_extension() const; bool write_velocity_field(const Solver &solver, @@ -42,10 +48,12 @@ class VTKFieldWriter : public FieldWriter double dx, double dy, double dz); private: - void write_preamble(std::ofstream &f, + void write_preamble(std::ofstream &f, nstream::onstream &nf, double x_min, double y_min, double z_min, double dx, double dy, double dz, int nx, int ny, int nz) const; + + const char *float_str() const; }; }; diff --git a/vortexje/numeric-stream.hpp b/vortexje/numeric-stream.hpp new file mode 100644 index 0000000..f4e4ac0 --- /dev/null +++ b/vortexje/numeric-stream.hpp @@ -0,0 +1,138 @@ +// +// Vortexje -- Numeric stream supporting textual and binary streaming of numeric values +// +// Copyright (C) 2018 hrobeers +// +// Authors: Hans Robeers (hrobeers) +// This file is distributed under the MIT License. +// See notice at the end of this file. +// + +#ifndef __NUMERIC_STREAM_HPP__ +#define __NUMERIC_STREAM_HPP__ + +#include + +namespace nstream +{ + enum serial_mode_e { + ASCII, + BINARY + }; + enum float_type_e { + FLOAT, + DOUBLE + }; + enum byte_order_e { + BIGENDIAN, + LITTLEENDIAN + }; + + byte_order_e get_byte_order() + { + union { + uint32_t i; + char c[4]; + } bint = {0x01020304}; + return bint.c[0] == 1? BIGENDIAN : LITTLEENDIAN; + } + + template + T bswap(T val) { + T retVal; + char *pVal = (char*)&val; + char *pRetVal = (char*)&retVal; + int size = sizeof(T); + for(int i=0; i + std::ostream& write_bin(std::ostream &stream, T val, byte_order_e byte_order) + { + T ordered = (byte_order==get_byte_order())? val : bswap(val); + stream.write((char*)&ordered, sizeof(T)); + return stream; + } + + // output numeric stream + struct onstream + { + std::ostream &s; + serial_mode_e mode; + float_type_e float_type; + byte_order_e byte_order; + onstream(std::ostream &s, serial_mode_e m, float_type_e ft = DOUBLE, byte_order_e bo = BIGENDIAN) + : s(s), mode(m), float_type(ft), byte_order(bo) {} + }; + + + template + onstream& write_float(onstream &ns, T val) { + if (ns.mode != BINARY) { + ns.s << val; + return ns; + } + + switch (ns.float_type) { + case FLOAT: + write_bin(ns.s, val, ns.byte_order); + break; + case DOUBLE: + write_bin(ns.s, val, ns.byte_order); + break; + } + return ns; + } + inline onstream& operator<<(onstream &ns, float f) { + return write_float(ns, f); + } + inline onstream& operator<<(onstream &ns, double d) { + return write_float(ns, d); + } + inline onstream& operator<<(onstream &ns, char c) { + // ignore char in binary mode (typically whitespace) + if (ns.mode != BINARY) + ns.s << c; + return ns; + } + inline onstream& operator<<(onstream &ns, const char *cstr) { + // ignore cstr in binary mode (typically whitespace) + if (ns.mode != BINARY) + ns.s << cstr; + return ns; + } + inline onstream& operator<<(onstream &ns, std::ostream&(*f)(std::ostream&)) { + // ignore manipulators like std::endl in binary mode + if(ns.mode != BINARY) + ns.s << f; + return ns; + } +}; + +#endif // __NUMERIC_STREAM_HPP__ + +/* ---------------------------------------------------------------------- + * Copyright (C) 2018 Hans Robeers. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * ---------------------------------------------------------------------- */