//======================================================================================================================
//
// This file is part of waLBerla. waLBerla 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 3 of
// the License, or (at your option) any later version.
//
// waLBerla 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 waLBerla (see COPYING.txt). If not, see .
//
//! \file BasicVoxelFileReader.impl.h
//! \ingroup geometry
//! \author Christian Godenschwager
//! \brief Defines class StructuredGeometryFileBasicReader that provides a low-level reader for waLBerla geometry files.
//
//======================================================================================================================
#include
#include
#include
#include
#include
namespace walberla {
namespace geometry {
/*******************************************************************************************************************//**
* \brief Constructs on empty geometry file
*
* \post isOpen() == false
**********************************************************************************************************************/
template
BasicVoxelFileReader::BasicVoxelFileReader() : xSize_(0), ySize_(0), zSize_(0)
{
assert( !isOpen() );
assert( filename_.empty() );
assert( dataBegin_ == std::streampos() );
assert( xSize_ == 0 );
assert( ySize_ == 0 );
assert( zSize_ == 0 );
}
/*******************************************************************************************************************//**
* \brief Opens an existing geometry file.
*
* \param filename Name (path) of the file.
*
* \throws std::runtime_error on I/O errors.
*
* \post isOpen() == true
**********************************************************************************************************************/
template
BasicVoxelFileReader::BasicVoxelFileReader( const std::string & _filename)
: xSize_(0), ySize_(0), zSize_(0)
{
open(_filename);
assert( dataBegin_ != std::streampos(-1) );
assert( dataBegin_ != std::streampos() );
assert( isOpen() );
assert( xSize() != 0 );
assert( ySize() != 0 );
assert( zSize() != 0 );
assert( filename() == _filename );
}
/*******************************************************************************************************************//**
* \brief Creates a new geometry file with extends xSize x ySize x zSize.
*
* \param filename Name (path) of the file.
* \param xSize Extend of the geometry file in x direction.
* \param ySize Extend of the geometry file in y direction.
* \param zSize Extend of the geometry file in z direction.
* \param value The value the cells are initialized with. Defaults to T().
*
* \throws std::runtime_error on I/O errors.
*
* \post isOpen() == true
**********************************************************************************************************************/
template
BasicVoxelFileReader::BasicVoxelFileReader( const std::string & _filename, std::size_t _xSize, std::size_t _ySize, std::size_t _zSize, T value /*= T()*/ )
: xSize_(0), ySize_(0), zSize_(0)
{
create(_filename, _xSize, _ySize, _zSize, value);
assert( dataBegin_ != std::streampos(-1) );
assert( dataBegin_ != std::streampos() );
assert( isOpen() );
assert( xSize_ == _xSize );
assert( ySize_ == _ySize );
assert( zSize_ == _zSize );
assert( filename_ == _filename );
}
/*******************************************************************************************************************//**
* \brief Creates a new geometry file with extends xSize x ySize x zSize.
*
* \param filename Name (path) of the file.
* \param xSize Extend of the geometry file in x direction.
* \param ySize Extend of the geometry file in y direction.
* \param zSize Extend of the geometry file in z direction.
* \param values An array of size xSize * ySize * zSize with the values to initialize the
* geometry file with.
*
* \throws std::runtime_error on I/O errors.
*
* \pre values != nullptr
*
* \post isOpen() == true
**********************************************************************************************************************/
template
BasicVoxelFileReader::BasicVoxelFileReader( const std::string & _filename, std::size_t _xSize, std::size_t _ySize, std::size_t _zSize, const T * values )
: xSize_(0), ySize_(0), zSize_(0)
{
assert(values != 0);
create(_filename, _xSize, _ySize, _zSize, values);
assert( dataBegin_ != std::streampos(-1) );
assert( dataBegin_ != std::streampos() );
assert( isOpen() );
assert( xSize_ == _xSize );
assert( ySize_ == _ySize );
assert( zSize_ == _zSize );
assert( filename_ == _filename );
}
/*******************************************************************************************************************//**
* \brief Destructor that closes the file if necessary.
**********************************************************************************************************************/
template
BasicVoxelFileReader::~BasicVoxelFileReader()
{
//filestream_.exceptions( std::ios_base::iostate(0) );
if(filestream_.is_open())
filestream_.close();
}
/*******************************************************************************************************************//**
* \brief Opens an existing geometry file.
*
* An already opened file gets closed beforehand.
*
* \param filename Name (path) of the file.
*
* \throws std::runtime_error on I/O errors.
* \throws std::runtime_error if the loaded geometry file's format is corrupt
*
* \post isOpen() == true
**********************************************************************************************************************/
template
void BasicVoxelFileReader::open( const std::string & _filename )
{
if( isOpen() )
close();
filename_ = _filename;
filestream_.open(_filename.c_str(), std::fstream::in | std::fstream::out | std::fstream::binary);
if( filestream_.fail() || filestream_.bad())
throw std::runtime_error("Error opening file \"" + _filename + "\"!");
std::string firstLine;
std::getline(filestream_, firstLine);
if( filestream_.fail() || filestream_.bad() )
throw std::runtime_error("Error reading header from file \"" + _filename + "\"!");
{
std::stringstream ss(firstLine);
ss >> xSize_;
ss >> ySize_;
ss >> zSize_;
}
dataBegin_ = filestream_.tellg();
if( filestream_.fail() || filestream_.bad() || dataBegin_ == std::streampos(-1) )
throw std::runtime_error("I/O Error while reading file \"" + _filename + "\"!");
filestream_.seekg(0, std::ios::end);
if( filestream_.fail() || filestream_.bad() )
throw std::runtime_error("I/O Error while reading file \"" + _filename + "\"!");
std::streampos dataEnd = filestream_.tellg();
if( filestream_.fail() || filestream_.bad() || dataEnd == std::streampos(-1) )
throw std::runtime_error("I/O Error while reading file \"" + _filename + "\"!");
assert(dataBegin_ <= dataEnd);
std::size_t rawDataLengthBytes = static_cast( dataEnd - dataBegin_ );
if( rawDataLengthBytes % sizeof(T) != 0 )
{
std::stringstream ss;
ss << "Raw data part of file " << _filename << " has size " << rawDataLengthBytes << " bytes. Data is of Type T = "
<< typeid(T).name() << " and sizeof(T) == " << sizeof(T) << "\nError: size % sizeof(T) != 0!";
throw std::runtime_error(ss.str());
}
assert(rawDataLengthBytes % sizeof(T) == 0);
std::size_t rawDataLength = rawDataLengthBytes / sizeof(T);
if( rawDataLength != numCells() )
{
std::stringstream ss;
ss << "Raw data part of file " << _filename << " has size " << rawDataLengthBytes << " bytes. Data is of Type T = "
<< typeid(T).name() << " and sizeof(T) == " << sizeof(T) << ". Error: Number of cells in data section of file = size / sizeof(T) = "
<< rawDataLength << " != Number of cells specified file header = " << numCells();
throw std::runtime_error(ss.str());
}
assert(dataBegin_ != std::streampos(-1));
assert(dataBegin_ != std::streampos());
assert(filename_ == _filename);
assert(xSize_ != 0);
assert(ySize_ != 0);
assert(zSize_ != 0);
}
/*******************************************************************************************************************//**
* \brief Creates a new geometry file with extends xSize x ySize x zSize.
*
* An already opened file gets closed beforehand.
*
* \param filename Name (path) of the file.
* \param xSize Extend of the geometry file in x direction.
* \param ySize Extend of the geometry file in y direction.
* \param zSize Extend of the geometry file in z direction.
* \param value The value the cells are initialized with. Defaults to T().
*
* \throws std::runtime_error on I/O errors.
*
* \post isOpen() == true
**********************************************************************************************************************/
template
void BasicVoxelFileReader::create( const std::string & _filename, std::size_t _xSize, std::size_t _ySize, std::size_t _zSize, T value /*= T()*/ )
{
if( isOpen() )
close();
filename_ = _filename;
xSize_ = _xSize;
ySize_ = _ySize;
zSize_ = _zSize;
filestream_.open(_filename.c_str(), std::fstream::out | std::fstream::binary);
if( filestream_.fail() || filestream_.bad())
throw std::runtime_error("Error opening file \"" + _filename + "\"!");
filestream_ << _xSize << " " << _ySize << " " << _zSize << "\n";
if( filestream_.fail() || filestream_.bad())
throw std::runtime_error("Error writing header to file \"" + _filename + "\"!");
dataBegin_ = filestream_.tellp();
if( filestream_.fail() || filestream_.bad() || dataBegin_ == std::streampos(-1) )
throw std::runtime_error("I/O Error while writing file \"" + _filename + "\"!");
const std::size_t maxChunkSizeBytes = 1024 * 1024; // 1 MegaByte
const std::size_t numCellsPerChunk = maxChunkSizeBytes / sizeof(T);
const std::streamsize bytesPerChunk = static_cast< std::streamsize >( numCellsPerChunk * sizeof(T) );
const std::vector chunkData(numCellsPerChunk, value);
assert(!chunkData.empty());
const char * rawData = reinterpret_cast(&chunkData[0]);
std::size_t cellsLeft = numCells();
while( cellsLeft >= numCellsPerChunk )
{
filestream_.write(rawData, bytesPerChunk);
if( filestream_.fail() || filestream_.bad() )
throw std::runtime_error("I/O Error while writing file \"" + _filename + "\"!");
cellsLeft -= numCellsPerChunk;
}
const std::streamsize bytesLastChunk = static_cast< std::streamsize >( cellsLeft * sizeof(T) );
assert(bytesLastChunk < bytesPerChunk);
filestream_.write(rawData, bytesLastChunk);
if( filestream_.fail() || filestream_.bad() )
throw std::runtime_error("I/O Error while writing file \"" + _filename + "\"!");
close();
open(_filename);
assert(dataBegin_ != std::streampos(-1));
assert(dataBegin_ != std::streampos());
assert(filename_ == _filename);
assert(xSize_ == _xSize);
assert(ySize_ == _ySize);
assert(zSize_ == _zSize);
}
/*******************************************************************************************************************//**
* \brief Creates a new geometry file with extends xSize x ySize x zSize.
*
* An already opened file gets closed beforehand.
*
* \param filename Name (path) of the file.
* \param xSize Extend of the geometry file in x direction.
* \param ySize Extend of the geometry file in y direction.
* \param zSize Extend of the geometry file in z direction.
* \param values An array of size xSize * ySize * zSize with the values to initialize the
* geometry file with.
*
* \throws std::runtime_error on I/O errors.
*
* \pre values != nullptr
*
* \post isOpen() == true
**********************************************************************************************************************/
template
void BasicVoxelFileReader::create( const std::string & _filename, std::size_t _xSize, std::size_t _ySize, std::size_t _zSize, const T * values )
{
if( isOpen() )
close();
filename_ = _filename;
xSize_ = _xSize;
ySize_ = _ySize;
zSize_ = _zSize;
filestream_.open(_filename.c_str(), std::fstream::out | std::fstream::binary);
if( filestream_.fail() || filestream_.bad())
throw std::runtime_error("Error opening file \"" + _filename + "\"!");
filestream_ << _xSize << " " << _ySize << " " << _zSize << "\n";
if( filestream_.fail() || filestream_.bad())
throw std::runtime_error("Error writing header to file \"" + _filename + "\"!");
dataBegin_ = filestream_.tellp();
if( filestream_.fail() || filestream_.bad() || dataBegin_ == std::streampos(-1) )
throw std::runtime_error("I/O Error while writing file \"" + _filename + "\"!");
const char * rawData = reinterpret_cast(values);
std::size_t dataSizeBytes = numCells() * sizeof(T);
filestream_.write(rawData, static_cast< std::streamsize >( dataSizeBytes ) );
if( filestream_.fail() || filestream_.bad() )
throw std::runtime_error("I/O Error while writing file \"" + _filename + "\"!");
close();
open(_filename);
assert(dataBegin_ != std::streampos(-1));
assert(dataBegin_ != std::streampos());
assert(filename_ == _filename);
assert(xSize_ == _xSize);
assert(ySize_ == _ySize);
assert(zSize_ == _zSize);
}
/*******************************************************************************************************************//**
* \brief Closes an opened geometry file.
*
* If no geometry file is open, this does nothing.
*
* \post isOpen() == false
**********************************************************************************************************************/
template
void BasicVoxelFileReader::close()
{
if( isOpen() )
{
filestream_.close();
dataBegin_ = std::streampos();
filename_.clear();
xSize_ = std::size_t(0);
ySize_ = std::size_t(0);
zSize_ = std::size_t(0);
}
assert(!filestream_.is_open());
assert(dataBegin_ == std::streampos());
assert(filename_.empty());
assert(xSize_ == 0);
assert(ySize_ == 0);
assert(zSize_ == 0);
assert( !isOpen() );
}
/*******************************************************************************************************************//**
* \brief Query if a geometry file is open.
*
* \return true if a file is opened, false if not.
**********************************************************************************************************************/
template
bool BasicVoxelFileReader::isOpen() const
{
return filestream_.is_open();
}
/*******************************************************************************************************************//**
* \brief Gets the filename of the opened geometry file.
*
* \pre isOpen() == true
*
* \return The filename of the opened geometry file.
**********************************************************************************************************************/
template
const std::string & BasicVoxelFileReader::filename() const
{
assert( isOpen() );
return filename_;
}
/*******************************************************************************************************************//**
* \brief Gets the extend of the geometry file in x direction.
*
* \pre isOpen() == true
*
* \return The extend of the geometry file in x direction.
**********************************************************************************************************************/
template
std::size_t BasicVoxelFileReader::xSize() const
{
assert( isOpen() );
return xSize_;
}
/*******************************************************************************************************************//**
* \brief Gets the extend of the geometry file in y direction.
*
* \pre isOpen() == true
*
* \return The extend of the geometry file in y direction.
**********************************************************************************************************************/
template
std::size_t BasicVoxelFileReader::ySize() const
{
assert( isOpen() );
return ySize_;
}
/*******************************************************************************************************************//**
* \brief Gets the extend of the geometry file in z direction.
*
* \pre isOpen() == true
*
* \return The extend of the geometry file in z direction.
**********************************************************************************************************************/
template
std::size_t BasicVoxelFileReader::zSize() const
{
assert( isOpen() );
return zSize_;
}
/*******************************************************************************************************************//**
* \brief Gets the number of cells of the currently loaded geometry file.
*
* \pre isOpen() == true
*
* \return xSize() * ySize() * zSize().
**********************************************************************************************************************/
template
std::size_t BasicVoxelFileReader::numCells() const
{
assert( isOpen() );
return xSize() * ySize() * zSize();
}
/*******************************************************************************************************************//**
* \brief Reads a block of data from the opened geometry file.
*
* \param cellAABB The axis-aligned bounding box of the block of data to be read.
* \param [out] data The vector the read data is stored to. The Storage order is zyx. (Meaning
* your innermost loop should iterate over x)
*
* \throws std::runtime_error on I/O errors.
*
* \pre isOpen() == true
* \pre cellAABB.xEnd < xSize()
* \pre cellAABB.yEnd < ySize()
* \pre cellAABB.zEnd < zSize()
*
* \post data.size() == cellAABB.numCells()
**********************************************************************************************************************/
template
void BasicVoxelFileReader::read( const CellAABB & cellAABB, std::vector & data ) const
{
assert( isOpen() );
assert( cellAABB.xEnd < xSize() );
assert( cellAABB.yEnd < ySize() );
assert( cellAABB.zEnd < zSize() );
data.clear();
data.resize( cellAABB.numCells() );
assert(!data.empty());
char * buffer = reinterpret_cast( &data[0] );
const std::size_t zFactor = xSize() * ySize();
const std::size_t yFactor = xSize();
std::streamsize lineLength = static_cast< std::streamsize >( cellAABB.xSize() * sizeof(T) );
for(std::size_t z = cellAABB.zBegin; z <= cellAABB.zEnd; ++z)
for(std::size_t y = cellAABB.yBegin; y <= cellAABB.yEnd; ++y)
{
assert( buffer < reinterpret_cast(&data[0] + data.size()) );
assert( buffer + lineLength - 1 < reinterpret_cast(&data[0] + data.size()) );
std::streamoff offset = static_cast< std::streamoff >( (z * zFactor + y * yFactor + cellAABB.xBegin) * sizeof(T) );
filestream_.seekg(dataBegin_ + offset);
if( filestream_.fail() || filestream_.bad() )
throw std::runtime_error("I/O Error while reading file \"" + filename() + "\"!");
filestream_.read(buffer, lineLength);
if( filestream_.fail() || filestream_.bad() )
throw std::runtime_error("I/O Error while reading file \"" + filename() + "\"!");
assert(filestream_.gcount() == lineLength);
buffer += lineLength;
}
assert( buffer == reinterpret_cast(&data[0] + data.size()) );
assert( data.size() == cellAABB.numCells() );
}
/*******************************************************************************************************************//**
* \brief Writes a block of data to the geometry file.
*
* \param cellAABB The axis-aligned bounding box of the block of data to be written.
* \param data The vector holding the data to bw written to the geometry file. The Storage
* order is zyx. (Meaning your innermost loop should iterate over x)
*
* \throws std::runtime_error on I/O errors.
*
* \pre isOpen() == true
* \pre cellAABB.xEnd < xSize()
* \pre cellAABB.yEnd < ySize()
* \pre cellAABB.zEnd < zSize()
* \pre data.size() >= cellAABB.numCells()
**********************************************************************************************************************/
template
void BasicVoxelFileReader::write( const CellAABB & cellAABB, const std::vector & data )
{
assert( isOpen() );
assert( cellAABB.xEnd < xSize_ );
assert( cellAABB.yEnd < ySize_ );
assert( cellAABB.zEnd < zSize_ );
assert( !data.empty() );
assert( data.size() >= cellAABB.numCells() );
const char * buffer = reinterpret_cast( &data[0] );
const std::size_t zFactor = xSize() * ySize();
const std::size_t yFactor = xSize();
std::streamsize lineLength = static_cast< std::streamsize >( cellAABB.xSize() * sizeof(T) );
for(std::size_t z = cellAABB.zBegin; z <= cellAABB.zEnd; ++z)
for(std::size_t y = cellAABB.yBegin; y <= cellAABB.yEnd; ++y)
{
assert( buffer < reinterpret_cast(&data[0] + data.size()) );
assert( buffer + lineLength - 1 < reinterpret_cast(&data[0] + data.size()) );
std::streamoff offset = static_cast< std::streamoff >( (z * zFactor + y * yFactor + cellAABB.xBegin) * sizeof(T) );
filestream_.seekp(dataBegin_ + offset);
if( filestream_.fail() || filestream_.bad() )
throw std::runtime_error("I/O Error while writing file \"" + filename() + "\"!");
filestream_.write(buffer, lineLength);
if( filestream_.fail() || filestream_.bad() )
throw std::runtime_error("I/O Error while writing file \"" + filename() + "\"!");
buffer += lineLength;
}
assert( buffer == reinterpret_cast(&data[0] + cellAABB.numCells()) );
}
/*******************************************************************************************************************//**
* \brief Constructor to initialize all members to 0.
*
* \post #xBegin = 0.
* \post #yBegin = 0.
* \post #zBegin = 0.
* \post #xEnd = 0.
* \post #yEnd = 0.
* \post #zEnd = 0.
* \post xSize() = 1
* \post ySize() = 1
* \post zSize() = 1
* \post numCells() = 1
**********************************************************************************************************************/
inline CellAABB::CellAABB()
: xBegin(0), yBegin(0), zBegin(0), xEnd(0), yEnd(0), zEnd(0)
{ }
/*******************************************************************************************************************//**
* \brief Constructor to initialize all members.
*
* \pre _xBegin <= _xEnd.
* \pre _yBegin <= _yEnd.
* \pre _zBegin <= _zEnd.
*
* \post #xBegin = _xBegin.
* \post #yBegin = _yBegin.
* \post #zBegin = _zBegin.
* \post #xEnd = _xEnd.
* \post #yEnd = _yEnd.
* \post #zEnd = _zEnd.
*
* \param _xBegin The minimal x coordinate of all cells included in the AABB.
* \param _yBegin The minimal y coordinate of all cells included in the AABB.
* \param _zBegin The minimal z coordinate of all cells included in the AABB.
* \param _xEnd The maximal x coordinate of all cells included in the AABB.
* \param _yEnd The maximal y coordinate of all cells included in the AABB.
* \param _zEnd The maximal z coordinate of all cells included in the AABB.
**********************************************************************************************************************/
CellAABB::CellAABB( std::size_t _xBegin, std::size_t _yBegin, std::size_t _zBegin,
std::size_t _xEnd, std::size_t _yEnd, std::size_t _zEnd )
: xBegin(_xBegin), yBegin(_yBegin), zBegin(_zBegin),
xEnd(_xEnd), yEnd(_yEnd), zEnd(_zEnd)
{
assert( xBegin <= xEnd );
assert( yBegin <= yEnd );
assert( zBegin <= zEnd );
}
/*******************************************************************************************************************//**
* \brief Gets the number cells included in the AABB.
*
* \pre #xBegin <= #xEnd.
* \pre #yBegin <= #yEnd.
* \pre #zBegin <= #zEnd.
*
* \return xSize() * ySize() * zSize().
**********************************************************************************************************************/
std::size_t CellAABB::numCells() const
{
assert( xBegin <= xEnd );
assert( yBegin <= yEnd );
assert( zBegin <= zEnd );
return xSize() * ySize() * zSize();
}
/*******************************************************************************************************************//**
* \brief Gets the extent of the AABB in z direction.
*
* \pre #xBegin <= #xEnd.
*
* \return #xEnd - #xBegin + 1.
**********************************************************************************************************************/
std::size_t CellAABB::xSize() const
{
assert( xBegin <= xEnd );
return xEnd - xBegin + 1;
}
/*******************************************************************************************************************//**
* \brief Gets the extent of the AABB in y direction.
*
* \pre #yBegin <= #yEnd.
*
* \return #yEnd - #yBegin + 1.
**********************************************************************************************************************/
std::size_t CellAABB::ySize() const
{
assert( yBegin <= yEnd );
return yEnd - yBegin + 1;
}
/*******************************************************************************************************************//**
* \brief Gets the extent of the AABB in z direction.
*
* \pre #zBegin <= #zEnd.
*
* \return #zEnd - #zBegin + 1.
**********************************************************************************************************************/
std::size_t CellAABB::zSize() const
{
assert( zBegin <= zEnd );
return zEnd - zBegin + 1;
}
} // namespace geometry
} // namespace walberla