1059 lines
42 KiB
C++
1059 lines
42 KiB
C++
// rights - 2006-, copyright benedikt, all rights reserved
|
|
// project - phidias3d
|
|
// file name - hdf5em.h
|
|
// file type - c++ header file
|
|
// objective - declare class for HDF5/ELECTROMAGNETIC file format access
|
|
// modified - 2006 jun 26, creation, benedikt oswald
|
|
// modified - 2006 aug 26, pl, integrate automatic index mapping.
|
|
// modified - 2006 sep 22, pl, add output functions for tets and coordinates.
|
|
// inheritance -
|
|
// feature - declares the base class for HDF5/ELECTROMAGNETIC file format access;
|
|
// feature - this class is completely self contained, i.e. it does not need anything
|
|
// feature - external, except the STL and the HDF5 header files and the corresponding
|
|
// feature - library.
|
|
// required software -
|
|
|
|
#ifndef HDF5FED_HH_
|
|
#define HDF5FED_HH_
|
|
|
|
#ifdef HAVE_HDF5
|
|
|
|
/* include standard header files */
|
|
#include <cmath>
|
|
#include <iostream>
|
|
#include <complex>
|
|
#include <string>
|
|
#include <vector>
|
|
|
|
// Include the files for rlog.
|
|
#ifdef HAVE_RLOG
|
|
#include <rlog/rlog.h>
|
|
#include <rlog/rloglocation.h>
|
|
#include <rlog/Error.h>
|
|
#include <rlog/RLogChannel.h>
|
|
#include <rlog/StdioNode.h>
|
|
#include <rlog/RLogTime.h>
|
|
#endif // HAVE_RLOG
|
|
|
|
// Include HDF5 headers.
|
|
#include <hdf5.h>
|
|
|
|
// Include h5fed specific constants.
|
|
#include "hdf5fedconst.hh"
|
|
|
|
/* include standard proprietary header files */
|
|
/*
|
|
#include "nonsciconst.h"
|
|
#include "physicomath.h"
|
|
*/
|
|
|
|
// Don't use this: doesn't working with dune.
|
|
//using namespace std;
|
|
//using namespace physicomath;
|
|
//using namespace nonsciconst;
|
|
|
|
namespace Hdf5fed
|
|
{
|
|
|
|
class Hdf5fed {
|
|
public:
|
|
|
|
/** \brief constructor and destructor */
|
|
Hdf5fed()
|
|
{
|
|
doIndexMapping_ = false;
|
|
indexMap_.clear();
|
|
positionMap_.clear();
|
|
|
|
// Deactivate the HDF5 error output.
|
|
H5Eset_auto (0, NULL );
|
|
};
|
|
|
|
// The Destructor.
|
|
~Hdf5fed(){};
|
|
|
|
//! Open an hdf5 finite element data file with appropriate access.
|
|
int open(std::string fileName, std::string fileAccess)
|
|
{
|
|
// Store filename and file access in private variable.
|
|
fileName_ = fileName;
|
|
fileAccess_ = fileAccess;
|
|
// Open file with respective rights via HDF5 API.
|
|
if (!fileAccess_.compare(FILE_READ))
|
|
{
|
|
hdf5FileIdent_ = H5Fopen(fileName_.c_str(), H5F_ACC_RDONLY, H5P_DEFAULT);
|
|
return OKCODE;
|
|
}
|
|
else if (!fileAccess_.compare(FILE_READ_WRITE))
|
|
{
|
|
hdf5FileIdent_ = H5Fopen(fileName_.c_str(), H5F_ACC_RDWR, H5P_DEFAULT);
|
|
return OKCODE;
|
|
}
|
|
else if (!fileAccess_.compare(FILE_CREATE))
|
|
{
|
|
hdf5FileIdent_ = H5Fcreate(fileName_.c_str(), H5F_ACC_EXCL,
|
|
H5P_DEFAULT, H5P_DEFAULT);
|
|
if (hdf5FileIdent_ < 0)
|
|
{
|
|
rError("The file %s already exist.",fileName_.c_str());
|
|
rError("To overwrite use the --force option.");
|
|
exit(ERRORCODE);
|
|
}
|
|
else
|
|
return OKCODE;
|
|
}
|
|
else if (!fileAccess_.compare(FILE_CREATE_FORCE))
|
|
{
|
|
hdf5FileIdent_ = H5Fcreate(fileName_.c_str(), H5F_ACC_TRUNC,
|
|
H5P_DEFAULT, H5P_DEFAULT);
|
|
return OKCODE;
|
|
}
|
|
else
|
|
{
|
|
rError("Unknown file-open-attribute for hdf5 file.");
|
|
exit(ERRORCODE);
|
|
}
|
|
};
|
|
|
|
// Close an open hdf5 file.
|
|
int close(void)
|
|
{
|
|
if (hdf5FileIdent_ >= 0)
|
|
{
|
|
hdf5Status_ = H5Fclose(hdf5FileIdent_);
|
|
return OKCODE;
|
|
}
|
|
else
|
|
{
|
|
rError("You cannot close a file that is not opened.");
|
|
return ERRORCODE;
|
|
}
|
|
};
|
|
|
|
// Create the empty HDF5 Finite Element Stardart group hierarchy.
|
|
int createGroupHierarchie()
|
|
{
|
|
// Hdf5 group identifier for group access, localy valid (this method).
|
|
hid_t hdf5GroupIdent_;
|
|
// Create the groups. All group-name strings are defined in
|
|
// hdf5fedconst.hh.
|
|
hdf5GroupIdent_ = H5Gcreate(hdf5FileIdent_,
|
|
HDF5FED_G_ROOT.c_str(),H5P_DEFAULT);
|
|
hdf5GroupIdent_ = H5Gcreate(hdf5FileIdent_,
|
|
HDF5FED_G_COORD.c_str(),H5P_DEFAULT);
|
|
hdf5GroupIdent_ = H5Gcreate(hdf5FileIdent_,
|
|
HDF5FED_G_VOLUME_MESH.c_str(),H5P_DEFAULT);
|
|
hdf5GroupIdent_ = H5Gcreate(hdf5FileIdent_,
|
|
HDF5FED_G_BOUNDARY_MESH.c_str(),H5P_DEFAULT);
|
|
hdf5GroupIdent_ = H5Gcreate(hdf5FileIdent_,
|
|
HDF5FED_G_MATERIAL.c_str(),H5P_DEFAULT);
|
|
hdf5GroupIdent_ = H5Gcreate(hdf5FileIdent_,
|
|
HDF5FED_G_ELECTROMAGNETIC.c_str(),H5P_DEFAULT);
|
|
hdf5GroupIdent_ = H5Gcreate(hdf5FileIdent_,
|
|
HDF5FED_G_DISCRETE.c_str(),H5P_DEFAULT);
|
|
hdf5GroupIdent_ = H5Gcreate(hdf5FileIdent_,
|
|
HDF5FED_G_PHYSICAL.c_str(),H5P_DEFAULT);
|
|
hdf5GroupIdent_ = H5Gcreate(hdf5FileIdent_,
|
|
HDF5FED_G_DEBYE.c_str(),H5P_DEFAULT);
|
|
hdf5GroupIdent_ = H5Gcreate(hdf5FileIdent_,
|
|
HDF5FED_G_LORENTZ.c_str(),H5P_DEFAULT);
|
|
hdf5GroupIdent_ = H5Gcreate(hdf5FileIdent_,
|
|
HDF5FED_G_DRUDE.c_str(),H5P_DEFAULT);
|
|
hdf5GroupIdent_ = H5Gcreate(hdf5FileIdent_,
|
|
HDF5FED_G_DOF.c_str(),H5P_DEFAULT);
|
|
hdf5GroupIdent_ = H5Gcreate(hdf5FileIdent_,
|
|
HDF5FED_G_FIELD.c_str(),H5P_DEFAULT);
|
|
return OKCODE;
|
|
};
|
|
|
|
// This function activate the automatic index mapping to create a gapfree
|
|
// and consecutive index set for the hdf5fed file.
|
|
// The indexVec holdes the numbers of the nodes in the same way, as the
|
|
// nodes are in the node vector.
|
|
int beginIndexMapping(std::vector<unsigned int>& indexVec)
|
|
{
|
|
rDebug("Begin automatic index mapping.");
|
|
doIndexMapping_ = true;
|
|
indexMap_.clear();
|
|
positionMap_.clear();
|
|
|
|
// Copy the old index to the map as map-key.
|
|
for(unsigned int varI = 0; varI < indexVec.size(); varI++)
|
|
{
|
|
indexMap_.insert(std::make_pair(indexVec[varI],0));
|
|
}
|
|
// Number all elements in the map consecutive, starting with zero, that
|
|
// is the new index set.
|
|
unsigned int tempUnInt = 0;
|
|
for(std::map<unsigned int, unsigned int>::iterator
|
|
iter = indexMap_.begin();
|
|
iter != indexMap_.end(); iter ++)
|
|
{
|
|
iter->second = tempUnInt;
|
|
tempUnInt++;
|
|
}
|
|
// The first column contains the new index, the second the old position
|
|
// of the coordinate in the vector.
|
|
for(unsigned int varI = 0; varI < indexVec.size(); varI++)
|
|
{
|
|
positionMap_.insert(std::make_pair(
|
|
(indexMap_.find(indexVec[varI]))->second,varI));
|
|
}
|
|
return OKCODE;
|
|
};
|
|
|
|
// This function deactivate the automatic index mapping.
|
|
// The uses index sets must be consecutive and gapfree.
|
|
int endIndexMapping()
|
|
{
|
|
rDebug("End automatic index mapping.");
|
|
doIndexMapping_ = false;
|
|
indexMap_.clear();
|
|
return OKCODE;
|
|
};
|
|
|
|
// Write 3dim coordinates to hdf5fed file.
|
|
int wCoord3d (std::vector<std::vector<double> >& coord)
|
|
{
|
|
// All these operations are only allowed, if there is a valid file
|
|
// identifier.
|
|
if (hdf5FileIdent_ >= 0)
|
|
{
|
|
// Define the rank of the different dataspaces.
|
|
const int rank = 2;
|
|
// Hdf5 error handling variable for Hdf5 actions.
|
|
herr_t hdf5Status;
|
|
// Hdf5 dataspace identifier.
|
|
hid_t hdf5DataspaceId;
|
|
// Hdf5 dataset identifier.
|
|
hid_t hdf5DatasetId;
|
|
// Define the dimension of the data array.
|
|
// Number of rows: as much as coordinates.
|
|
// Number of colums: 3, one for each dimension.
|
|
hsize_t dim[2];
|
|
dim[0] = coord.size();
|
|
dim[1] = 3;
|
|
|
|
// We copy the coordinates from coord in an standart array, so that
|
|
// hdf5 can handle it.
|
|
// We do this in portions, so we save memory.
|
|
|
|
// Subdimension of hyperslab in memory: 1 line, 3 columns.
|
|
hsize_t dim_sub_mem[2];
|
|
dim_sub_mem[0] = 1;
|
|
dim_sub_mem[1] = 3;
|
|
// Subdimension of hyperslab in file: 1 line, 3 columns.
|
|
hsize_t dim_sub_file[2];
|
|
dim_sub_file[0] = 1;
|
|
dim_sub_file[1] = 3;
|
|
// Define the offset for reading from the memory.
|
|
// Always fixed.
|
|
hsize_t offset_mem[2];
|
|
offset_mem[0] = 0;
|
|
offset_mem[1] = 0;
|
|
// Define the offset for writing into the file.
|
|
hsize_t offset_file[2];
|
|
offset_file[0] = 0; // Row only at the beginning. We iterate over it.
|
|
offset_file[1] = 0; // We have no offset respective to the column.
|
|
|
|
// Array for x, y and z component of one coordinate.
|
|
double coordinate[3];
|
|
|
|
// Dimesion and datatype of the file dataset, read out form file.
|
|
// This is not the fastest, but the most robust way.
|
|
hsize_t dim_out[2];
|
|
hid_t dataType;
|
|
|
|
|
|
// Create dataspace of full size.
|
|
hdf5DataspaceId = H5Screate_simple(rank, dim, H5P_DEFAULT);
|
|
|
|
// Create dataset of full size.
|
|
hdf5DatasetId = H5Dcreate(hdf5FileIdent_, HDF5FED_D_COORD3D.c_str(),
|
|
HDF5FED_COORD_DATATYPE,
|
|
hdf5DataspaceId, H5P_DEFAULT);
|
|
|
|
|
|
|
|
// Loop over all rows of the dataset (file) and copy the coord vector
|
|
// element wise.
|
|
hdf5Status = H5Sget_simple_extent_dims(hdf5DataspaceId, dim_out, H5P_DEFAULT);
|
|
dataType = H5Dget_type(hdf5DatasetId);
|
|
// If we use automatic mapping we need an interator to the map.
|
|
std::map<unsigned int, unsigned int>::iterator
|
|
iter = positionMap_.begin();
|
|
for (unsigned int varI = 0; varI < dim_out[0]; varI++)
|
|
{
|
|
// Iterate over the rows in file dataspace.
|
|
offset_file[0] = varI;
|
|
|
|
// Copy every element of a coordinate.
|
|
for (unsigned int varJ = 0; varJ < dim_out[1]; varJ++)
|
|
{
|
|
// Here is the only special case for automated mapping:
|
|
// Do not copy the next in the input vector, copy the coord
|
|
// with the next following number.
|
|
if (doIndexMapping_ == true)
|
|
coordinate[varJ] = coord[iter->second][varJ];
|
|
else
|
|
coordinate[varJ] = coord[varI][varJ];
|
|
}
|
|
|
|
// Select hyperslab ('region') in file dataspace.
|
|
hdf5Status = H5Sselect_hyperslab(hdf5DataspaceId, H5S_SELECT_SET,
|
|
offset_file, H5P_DEFAULT,
|
|
dim_sub_file, H5P_DEFAULT);
|
|
|
|
// Define memory Dataspace.
|
|
hid_t hdf5MemspaceId;
|
|
hdf5MemspaceId = H5Screate_simple(rank, dim_sub_mem, H5P_DEFAULT);
|
|
// Select hyperslab ('region') in memory.
|
|
hdf5Status = H5Sselect_hyperslab(hdf5MemspaceId, H5S_SELECT_SET,
|
|
offset_mem, H5P_DEFAULT,
|
|
dim_sub_mem, H5P_DEFAULT);
|
|
|
|
// Copy dataset to dataset from memory to file.
|
|
hdf5Status = H5Dwrite(hdf5DatasetId, H5T_NATIVE_DOUBLE,
|
|
hdf5MemspaceId, hdf5DataspaceId,
|
|
H5P_DEFAULT, coordinate);
|
|
|
|
H5Sclose(hdf5MemspaceId);
|
|
// Increment the map iterator if we make automatic mapping.
|
|
if (doIndexMapping_)
|
|
iter++;
|
|
}
|
|
|
|
// Close hdf5 identifier.
|
|
hdf5Status = H5Dclose(hdf5DatasetId);
|
|
hdf5Status = H5Sclose(hdf5DataspaceId);
|
|
|
|
return OKCODE;
|
|
}
|
|
else
|
|
{
|
|
rError("You cannot operate to dataset COORD3D.");
|
|
rError("There is no valid file identifier.");
|
|
return ERRORCODE;
|
|
}
|
|
};
|
|
|
|
// Read 3dim coordinates from hdf5fed file.
|
|
int rCoord3d (std::vector<std::vector<double> >& coord)
|
|
{
|
|
// All these operations are only allowed, if there is a valid file
|
|
// identifier.
|
|
if (hdf5FileIdent_ >= 0)
|
|
{
|
|
// The name of the dataset.
|
|
std::string datasetName = HDF5FED_D_COORD3D;
|
|
// Define the rank of the different dataspaces.
|
|
const int rank = 2;
|
|
// Hdf5 error handling variable for Hdf5 actions.
|
|
herr_t hdf5Status;
|
|
// Hdf5 dataspace identifier.
|
|
hid_t hdf5DataspaceId;
|
|
// Hdf5 dataset identifier.
|
|
hid_t hdf5DatasetId;
|
|
// Open the hdf5 dataset.
|
|
hdf5DatasetId = H5Dopen(hdf5FileIdent_, datasetName.c_str());
|
|
// Get the dataspace from the dataset.
|
|
hdf5DataspaceId = H5Dget_space(hdf5DatasetId);
|
|
// Read the dimension of the file dataspace.
|
|
hsize_t dim_out[rank];
|
|
hdf5Status = H5Sget_simple_extent_dims(hdf5DataspaceId, dim_out,
|
|
H5P_DEFAULT);
|
|
|
|
// Get the datatype of the datas we want to read.
|
|
hid_t dataType;
|
|
dataType = H5Dget_type(hdf5DatasetId);
|
|
|
|
// Resize the element and material index vector to dataspace size.
|
|
coord.clear();
|
|
coord.resize(dim_out[0]);
|
|
for (unsigned int varI = 0; varI < coord.size(); varI++)
|
|
{
|
|
coord[varI].resize(dim_out[1]);
|
|
}
|
|
|
|
rDebug("dim_out[0]: %d",dim_out[0]);
|
|
rDebug("dim_out[1]: %d",dim_out[1]);
|
|
|
|
// We copy the coordinates from coord in an standart array, so that
|
|
// hdf5 can handle it.
|
|
// We do this in portions, so we save memory.
|
|
|
|
// Subdimension of hyperslab in memory: 1 line, 3 columns.
|
|
hsize_t dim_sub_mem[2];
|
|
dim_sub_mem[0] = 1;
|
|
dim_sub_mem[1] = dim_out[1];
|
|
// Subdimension of hyperslab in file: 1 line, 3 columns.
|
|
hsize_t dim_sub_file[2];
|
|
dim_sub_file[0] = 1;
|
|
dim_sub_file[1] = dim_out[1];
|
|
// Define the offset for reading the file.
|
|
hsize_t offset_file[2];
|
|
offset_file[0] = 0; // Row only at the beginning. We iterate over it.
|
|
offset_file[1] = 0; // We have no offset respective to the column.
|
|
// Define the offset for writing into the memory.
|
|
// Always fixed.
|
|
hsize_t offset_mem[2];
|
|
offset_mem[0] = 0;
|
|
offset_mem[1] = 0;
|
|
|
|
// Array for x, y and z component of one coordinate.
|
|
double coordinate[dim_out[1]];
|
|
|
|
// Loop over all rows of the dataset (file) and copy the coord vector
|
|
// element wise.
|
|
for (unsigned int varI = 0; varI < dim_out[0]; varI++)
|
|
{
|
|
// Iterate over the rows in file dataspace.
|
|
offset_file[0] = varI;
|
|
|
|
// Select hyperslab ('region') in file dataspace.
|
|
hdf5Status = H5Sselect_hyperslab(hdf5DataspaceId, H5S_SELECT_SET,
|
|
offset_file, H5P_DEFAULT,
|
|
dim_sub_file, H5P_DEFAULT);
|
|
|
|
// Define memory Dataspace.
|
|
hid_t hdf5MemspaceId;
|
|
hdf5MemspaceId = H5Screate_simple(rank, dim_sub_mem, H5P_DEFAULT);
|
|
// Select hyperslab ('region') in memory.
|
|
hdf5Status = H5Sselect_hyperslab(hdf5MemspaceId, H5S_SELECT_SET,
|
|
offset_mem, H5P_DEFAULT,
|
|
dim_sub_mem, H5P_DEFAULT);
|
|
|
|
// Copy dataset to dataset from memory to file.
|
|
hdf5Status = H5Dread(hdf5DatasetId, dataType,
|
|
hdf5MemspaceId, hdf5DataspaceId,
|
|
H5P_DEFAULT, coordinate);
|
|
H5Sclose(hdf5MemspaceId);
|
|
|
|
// Copy every element of a coordinate.
|
|
for (unsigned int varJ = 0; varJ < dim_out[1]; varJ++)
|
|
{
|
|
coord[varI][varJ]=coordinate[varJ];
|
|
}
|
|
}
|
|
|
|
// Close hdf5 identifier.
|
|
hdf5Status = H5Dclose(hdf5DatasetId);
|
|
hdf5Status = H5Sclose(hdf5DataspaceId);
|
|
|
|
return OKCODE;
|
|
}
|
|
else
|
|
{
|
|
rError("You cannot operate to dataset %s.",HDF5FED_D_COORD3D.c_str());
|
|
rError("There is no valid file identifier.");
|
|
return ERRORCODE;
|
|
}
|
|
};
|
|
|
|
// Read and return tetrahedrons and respective material index of the
|
|
// given level.
|
|
int rTetrahedron(unsigned int level,
|
|
std::vector<std::vector<unsigned int> >& elem,
|
|
std::vector<unsigned int>& materialIndex)
|
|
{
|
|
// Set the name of the dataset, we want to read.
|
|
std::string datasetName = HDF5FED_D_TETMESH;
|
|
rElement_(datasetName, level, -1, elem, materialIndex);
|
|
return OKCODE;
|
|
};
|
|
|
|
// Copy the tetrahedon elements to the hdf5fed filse.
|
|
int wTetrahedron(unsigned int level,
|
|
std::vector< std::vector<unsigned int> >& elem,
|
|
std::vector<unsigned int>& materialIndex)
|
|
{
|
|
// Set dimension of an elements vector.
|
|
unsigned int elemDim = HDF5FED_TET_N_NODE;
|
|
// Set the name of the dataset, we want to operate.
|
|
std::string datasetName = HDF5FED_D_TETMESH;
|
|
// Select the data type in which the elements should be stored.
|
|
hid_t dataType = HDF5FED_MESH_ELEM_DATATYPE;
|
|
// This function does the real work for all elements.
|
|
wElement_(datasetName, level, -1, elemDim, elem, materialIndex, dataType);
|
|
return OKCODE;
|
|
}
|
|
|
|
int wTriangleB(unsigned int level,
|
|
unsigned int number,
|
|
std::vector< std::vector<unsigned int> >& elem,
|
|
std::vector<unsigned int>& boundaryIndex)
|
|
{
|
|
// Set dimension of an elements vector.
|
|
unsigned int elemDim = HDF5FED_TRIANGLE_N_NODE;
|
|
// Set the name of the dataset, we want to operate.
|
|
std::string datasetName = HDF5FED_D_TRIANGLEBOUNDARY;
|
|
// Select the data type in which the elements should be stored.
|
|
hid_t dataType = HDF5FED_MESH_ELEM_DATATYPE;
|
|
// This function does the real work for all elements.
|
|
wElement_(datasetName, level, (int)number, elemDim, elem, boundaryIndex, dataType);
|
|
return OKCODE;
|
|
}
|
|
|
|
// Read and return boundary triangles and respective boundary index of the
|
|
// given level and number.
|
|
int rTriangleB(unsigned int level,
|
|
unsigned int number,
|
|
std::vector<std::vector<unsigned int> >& elem,
|
|
std::vector<unsigned int>& boundaryIndex)
|
|
{
|
|
// Set the name of the dataset, we want to read.
|
|
std::string datasetName = HDF5FED_D_TRIANGLEBOUNDARY;
|
|
rElement_(datasetName, level, (int)number, elem, boundaryIndex);
|
|
return OKCODE;
|
|
};
|
|
|
|
|
|
// This function gets some attributes of the element, it should insert and
|
|
// insert it to the given dataset.
|
|
// Here we do the index mapping.
|
|
// datasetNameBlank: the name of the elements dataset without the level!
|
|
// (example: ../TETMESH_L)
|
|
// level: the hierarchy level of the elements.
|
|
// number: if there are different meshes on the same level (i.e. for
|
|
// boudaries, they are numbered. For no numbering choose
|
|
// number < 0.
|
|
// elemDim: the number of nodes a single element has (tet = 4, line = 2, ..)
|
|
// elem: the outer vector contains all elements,
|
|
// the inner vector contains the elements node numbers
|
|
// materialIndex: the material index to an element.
|
|
// elementType: this is the element type we use to store the elements and
|
|
// the material index in the file.
|
|
int wElement_(std::string datasetNameBlank,
|
|
unsigned int level,
|
|
int number,
|
|
unsigned int elemDim,
|
|
std::vector< std::vector<unsigned int> >& elem,
|
|
std::vector<unsigned int>& materialIndex,
|
|
hid_t dataType)
|
|
{
|
|
// All these operations are only allowed, if there is a valid file
|
|
// identifier.
|
|
if (hdf5FileIdent_ >= 0)
|
|
{
|
|
// Make datasetName with the datasetNameBlank and the level.
|
|
std::string datasetName = datasetNameBlank + stringify(level);
|
|
if (number >= 0)
|
|
{
|
|
datasetName = datasetName + "_K" + stringify(number);
|
|
}
|
|
|
|
// Check if the dataset with the given datasetName already exists:
|
|
// if it exists, abort;
|
|
// if not, check if the previouse level exists:
|
|
// if not, prompt warning
|
|
// if it exits, every thing is correct.
|
|
if (existsDataspace(datasetName))
|
|
{
|
|
rError("Dataspace %s already exists!", datasetName.c_str());
|
|
rError("You cannot insert it twice.");
|
|
rError("Exit.");
|
|
exit(ERRORCODE);
|
|
}
|
|
else
|
|
{
|
|
// We need no check for level 0.
|
|
// If the level is higher than zero, check if levle-1 exists.
|
|
if (level > 0)
|
|
{
|
|
if (!(existsDataspace(datasetNameBlank + stringify(level-1))))
|
|
{
|
|
rError("You insert level %d while level %d does not exists.",
|
|
level, level-1);
|
|
rError("So the %s levels will be not consective.",
|
|
datasetNameBlank.c_str());
|
|
rError("Exit.");
|
|
exit(ERRORCODE);
|
|
}
|
|
}
|
|
|
|
// Define the rank of the different dataspaces.
|
|
const int rank = 2;
|
|
// Hdf5 error handling variable for Hdf5 actions.
|
|
herr_t hdf5Status;
|
|
// Hdf5 dataspace identifier.
|
|
hid_t hdf5DataspaceId;
|
|
// Hdf5 dataset identifier.
|
|
hid_t hdf5DatasetId;
|
|
// Define the dimension of the data array.
|
|
hsize_t dim[2];
|
|
// Number of rows: as much as elements.
|
|
dim[0] = elem.size();
|
|
// Number of colums: dimenstion of an elements vector + 1.
|
|
// We need the extra column as index in the material list!
|
|
dim[1] = elemDim + 1;
|
|
|
|
// We copy the element nodes from a element in an standart array,
|
|
// so that hdf5 can handle it.
|
|
// We do this for every element separate, so we save memory.
|
|
|
|
// Subdimension of hyperslab in memory: 1 line, elemDim columns.
|
|
hsize_t dim_sub_mem[2];
|
|
dim_sub_mem[0] = 1;
|
|
dim_sub_mem[1] = dim[1];
|
|
// Subdimension of hyperslab in file: 1 line, elemDim columns.
|
|
hsize_t dim_sub_file[2];
|
|
dim_sub_file[0] = 1;
|
|
dim_sub_file[1] = dim[1];
|
|
// Define the offset for reading from the memory.
|
|
// Always fixed, because memory has exactly the same size.
|
|
hsize_t offset_mem[2];
|
|
offset_mem[0] = 0;
|
|
offset_mem[1] = 0;
|
|
// Define the offset for writing into the file.
|
|
hsize_t offset_file[2];
|
|
offset_file[0] = 0; // Row ofsett zero only at the beginning.
|
|
offset_file[1] = 0; // We have no offset respective to the column.
|
|
|
|
// Array for single elements of an element vector.
|
|
unsigned int element[dim[1]];
|
|
|
|
// Dimesion and datatype of the file dataset, read out form file.
|
|
// This is not the fastest, but the most robust way.
|
|
hsize_t dim_out[2];
|
|
|
|
// Create dataspace of full size.
|
|
hdf5DataspaceId = H5Screate_simple(rank, dim, H5P_DEFAULT);
|
|
|
|
// Create dataset of full size.
|
|
hdf5DatasetId = H5Dcreate(hdf5FileIdent_, datasetName.c_str(),
|
|
dataType, hdf5DataspaceId, H5P_DEFAULT);
|
|
|
|
// Loop over all rows of the dataset (file) and copy the elem vector
|
|
// row wise.
|
|
hdf5Status = H5Sget_simple_extent_dims(hdf5DataspaceId, dim_out,
|
|
H5P_DEFAULT);
|
|
// Get the datatype of the datas we want to write.
|
|
// dataType = H5Dget_type(hdf5DatasetId);
|
|
for (unsigned int varI = 0; varI < dim_out[0]; varI++)
|
|
{
|
|
// Iterate over the rows in file dataspace.
|
|
offset_file[0] = varI;
|
|
|
|
// Copy every element of a coordinate.
|
|
// Remember: the last column is an index in the material list!
|
|
for (unsigned int varJ = 0; varJ < dim_out[1] - 1; varJ++)
|
|
{
|
|
// Here is the only special case for automated mapping:
|
|
// Do not copy the next in the input vector, copy the coord
|
|
// with the next following number.
|
|
if (doIndexMapping_ == true)
|
|
{
|
|
std::map<unsigned int, unsigned int>::iterator iter;
|
|
iter = indexMap_.find((elem)[varI][varJ]);
|
|
element[varJ] = iter->second;
|
|
}
|
|
else
|
|
element[varJ] = (elem)[varI][varJ];
|
|
}
|
|
|
|
// Set the appropriate material list!
|
|
// element[dim_out[1]-1] = materialIndex[varI];
|
|
element[dim_out[1]-1] = 0;
|
|
|
|
// Select hyperslab ('region') in file dataspace.
|
|
hdf5Status = H5Sselect_hyperslab(hdf5DataspaceId, H5S_SELECT_SET,
|
|
offset_file, H5P_DEFAULT,
|
|
dim_sub_file, H5P_DEFAULT);
|
|
// Define memory Dataspace.
|
|
hid_t hdf5MemspaceId;
|
|
hdf5MemspaceId = H5Screate_simple(rank, dim_sub_mem, H5P_DEFAULT);
|
|
// Select hyperslab ('region') in memory.
|
|
hdf5Status = H5Sselect_hyperslab(hdf5MemspaceId, H5S_SELECT_SET,
|
|
offset_mem, H5P_DEFAULT,
|
|
dim_sub_mem, H5P_DEFAULT);
|
|
// Copy dataset to dataset from memory to file.
|
|
hdf5Status = H5Dwrite(hdf5DatasetId, dataType,
|
|
hdf5MemspaceId, hdf5DataspaceId,
|
|
H5P_DEFAULT, element);
|
|
// Close the memory space identifier.
|
|
H5Sclose(hdf5MemspaceId);
|
|
}
|
|
|
|
// Close hdf5 identifier.
|
|
hdf5Status = H5Dclose(hdf5DatasetId);
|
|
hdf5Status = H5Sclose(hdf5DataspaceId);
|
|
|
|
return OKCODE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
rError("You cannot operate to a dataset.");
|
|
rError("There is no valid file identifier.");
|
|
rError("Exit.");
|
|
exit(ERRORCODE);
|
|
}
|
|
};
|
|
|
|
// This function gets the level and name of an element in
|
|
// a Hdf5fed file and returns the element nodes and material tag as a
|
|
// vetor of vectors and a vector.
|
|
// datasetNameBlank: the name of the elements dataset without the level!
|
|
// (example: ../TETMESH_L)
|
|
// level: the hierarchy level of the elements
|
|
// number: if there are different meshes on the same level (i.e. for
|
|
// boudaries, they are numbered. For no numbering choose
|
|
// number < 0.
|
|
// elem: the outer vector gets all elements,
|
|
// the inner vectors get the elements node numbers.
|
|
// materialIndex: the material index to an elemen.
|
|
int rElement_(std::string datasetNameBlank,
|
|
unsigned int level,
|
|
int number,
|
|
std::vector< std::vector<unsigned int> >& elem,
|
|
std::vector<unsigned int>& materialIndex)
|
|
{
|
|
// All these operations are only allowed, if there is a valid file
|
|
// identifier.
|
|
if (hdf5FileIdent_ >= 0)
|
|
{
|
|
// Make datasetName with the datasetNameBlank and the level.
|
|
std::string datasetName = datasetNameBlank + stringify(level);
|
|
if (number >= 0)
|
|
{
|
|
datasetName = datasetName + "_K" + stringify(number);
|
|
}
|
|
|
|
// Check if the dataset with the given datasetName exists:
|
|
// if it does not return errorcode, else continue.
|
|
if (!(existsDataspace(datasetName)))
|
|
{
|
|
rDebug("Dataspace %s does not exists!", datasetName.c_str());
|
|
rDebug("So you cannot read.");
|
|
return ERRORCODE;
|
|
}
|
|
else
|
|
{
|
|
// Define the rank of the different dataspaces.
|
|
const int rank = 2;
|
|
// Hdf5 error handling variable for Hdf5 actions.
|
|
herr_t hdf5Status;
|
|
|
|
// Hdf5 dataspace identifier.
|
|
hid_t hdf5DataspaceId;
|
|
|
|
// Hdf5 dataset identifier.
|
|
hid_t hdf5DatasetId;
|
|
// Open the hdf5 dataset.
|
|
hdf5DatasetId = H5Dopen(hdf5FileIdent_, datasetName.c_str());
|
|
|
|
// Get the dataspace from the dataset.
|
|
hdf5DataspaceId = H5Dget_space(hdf5DatasetId);
|
|
|
|
// Read the dimension of the file dataspace.
|
|
hsize_t dim_out[2];
|
|
hdf5Status = H5Sget_simple_extent_dims(hdf5DataspaceId, dim_out,
|
|
H5P_DEFAULT);
|
|
|
|
// Get the datatype of the datas we want to read.
|
|
hid_t dataType;
|
|
dataType = H5Dget_type(hdf5DatasetId);
|
|
|
|
// Resize the element and material index vector to dataspace size.
|
|
elem.clear();
|
|
elem.resize(dim_out[0]);
|
|
for (unsigned int varI = 0; varI < elem.size(); varI++)
|
|
{
|
|
elem[varI].resize(dim_out[1]);
|
|
}
|
|
materialIndex.clear();
|
|
materialIndex.resize(dim_out[0]);
|
|
|
|
// We copy a line from file to a standart array, and the array to a
|
|
// stl::vector of vector so that hdf5 can handle it.
|
|
// We do this for every element separate, so we save memory.
|
|
|
|
// Subdimension of hyperslab in memory: 1 line, elemDim columns.
|
|
hsize_t dim_sub_mem[2];
|
|
dim_sub_mem[0] = 1;
|
|
dim_sub_mem[1] = dim_out[1];
|
|
// Subdimension of hyperslab in file: 1 line, elemDim columns.
|
|
hsize_t dim_sub_file[2];
|
|
dim_sub_file[0] = 1;
|
|
dim_sub_file[1] = dim_out[1];
|
|
// Define the offset for reading into the file.
|
|
hsize_t offset_file[2];
|
|
offset_file[0] = 0; // Row ofsett zero only at the beginning.
|
|
offset_file[1] = 0; // We have no offset respective to the column.
|
|
// Define the offset for writing to the memory.
|
|
// Always fixed, because memory has exactly the same size.
|
|
hsize_t offset_mem[2];
|
|
offset_mem[0] = 0;
|
|
offset_mem[1] = 0;
|
|
|
|
// Array for single elements in memory.
|
|
unsigned int element[dim_out[1]];
|
|
|
|
// Loop over all rows of the dataset (file) and copy the elem vector
|
|
// row wise.
|
|
for (unsigned int varI = 0; varI < dim_out[0]; varI++)
|
|
{
|
|
// Iterate over the rows in file dataspace.
|
|
offset_file[0] = varI;
|
|
|
|
// Select hyperslab ('region') in file dataspace.
|
|
hdf5Status = H5Sselect_hyperslab(hdf5DataspaceId, H5S_SELECT_SET,
|
|
offset_file, H5P_DEFAULT,
|
|
dim_sub_file, H5P_DEFAULT);
|
|
// Define memory Dataspace.
|
|
hid_t hdf5MemspaceId;
|
|
hdf5MemspaceId = H5Screate_simple(rank, dim_sub_mem, H5P_DEFAULT);
|
|
// Select hyperslab ('region') in memory.
|
|
hdf5Status = H5Sselect_hyperslab(hdf5MemspaceId, H5S_SELECT_SET,
|
|
offset_mem, H5P_DEFAULT,
|
|
dim_sub_mem, H5P_DEFAULT);
|
|
// Copy dataset to dataset from file to memory.
|
|
hdf5Status = H5Dread(hdf5DatasetId, dataType,
|
|
hdf5MemspaceId, hdf5DataspaceId,
|
|
H5P_DEFAULT, element);
|
|
// Close the memory space identifier.
|
|
H5Sclose(hdf5MemspaceId);
|
|
|
|
// Copy every element of a coordinate.
|
|
// Remember: the last column is an index in the material list!
|
|
for (unsigned int varJ = 0; varJ < dim_out[1]-1; varJ++)
|
|
{
|
|
elem[varI][varJ] = element[varJ];
|
|
}
|
|
// Copy the material index in the appropriate vector.
|
|
materialIndex[varI] = element[dim_out[1]-1];
|
|
}
|
|
|
|
// Close hdf5 identifier.
|
|
hdf5Status = H5Sclose(hdf5DataspaceId);
|
|
hdf5Status = H5Dclose(hdf5DatasetId);
|
|
|
|
return OKCODE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
rError("You cannot operate to a dataset.");
|
|
rError("There is no valid file identifier.");
|
|
rError("Exit.");
|
|
exit(ERRORCODE);
|
|
}
|
|
};
|
|
|
|
// Write 3dim coordinates to hdf5fed file.
|
|
bool existsDataspace (std::string dataspaceName)
|
|
{
|
|
// All these operations are only allowed, if there is a valid file
|
|
// identifier.
|
|
if (hdf5FileIdent_ >= 0)
|
|
{
|
|
// Hdf5 error handling variable for Hdf5 actions.
|
|
herr_t hdf5Status;
|
|
// Hdf5 dataspace identifier.
|
|
hid_t hdf5DataspaceId;
|
|
|
|
hdf5DataspaceId = H5Dopen(hdf5FileIdent_, dataspaceName.c_str());
|
|
if (hdf5DataspaceId < 0)
|
|
{
|
|
//rDebug("This dataspace exists NOT in this file: %s",
|
|
// dataspaceName.c_str());
|
|
return false;
|
|
}
|
|
else
|
|
{
|
|
//rDebug("This dataspace exists in this file: %s",
|
|
// dataspaceName.c_str());
|
|
return true;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
rError("You cannot check if the dataspace exists.");
|
|
rError("There is no valid file identifier.");
|
|
return false;
|
|
}
|
|
}
|
|
|
|
|
|
/** \brief Inquire existence of HDF5 groups */
|
|
// existsVolumeMesh()
|
|
// existsCoord()
|
|
// virtual bool existsMesh(){ return(false); }
|
|
// virtual bool existsVertices(){ return(false); }
|
|
// virtual bool existsEdges(){ return(false); }
|
|
// virtual bool existsTriangles(){ return(false); }
|
|
// virtual bool existsBoundaryTriangles(){ return(false); }
|
|
|
|
// /** \brief Data access both reading and writing */
|
|
// virtual unsigned int nDim(){ return(ndim_); } /* retrieve number of mesh dimension */
|
|
// virtual unsigned int nLevel(){ return(nlevel_); } /* retrieve number of mesh levels */
|
|
// virtual unsigned int nCoord(){ return(nvertex_); } /* retrieve total number of all vertices */
|
|
// virtual unsigned int nCoord(unsigned int level){ return(nvertex_); } /* retrieve total number of vertices used for defining the mesh */
|
|
// Überladen greifen auf nelem zu
|
|
// virtual std::vector<unsigned int> nTet(){ return(ntet_); } /* retrieve vector containing number of tetrahedra present in levels of the mesh */
|
|
// virtual std::vector<unsigned int> nBoundary(){ return(nboundary_); } /* retrieve vector containing number of boundary meshes present on a level of the mesh */
|
|
// Pism, ...
|
|
// nBoundaryTriangle
|
|
// Quad..
|
|
// Edge
|
|
|
|
|
|
/** \brief HDF5EM data access routines */
|
|
|
|
/** \brief Electromagnetic boundary conditions */
|
|
//_______________________________
|
|
// virtual int triangleBC(unsigned int level, unsigned int triangle, unsigned int bc){} /* set electromagnetic boundary condition for triangle on level */
|
|
// virtual unsigned int triangleBC(unsigned int level, unsigned int triangle){} /* retrieve electromagnetic boundary condition type */
|
|
//
|
|
// virtual int rhoSurfaceImpedance(unsigned int level, unsigned int triangle, double rho){} /* store resistance of surface impedance for triangle on level */
|
|
// virtual double rhoSurfaceImpedance(unsigned int level, unsigned int triangle){} /* retrieve resistance of surface impedance boundary condition */
|
|
//
|
|
// /** \brief Mesh */
|
|
// stl vectoren
|
|
// virtual unsigned int** tetrahedron(unsigned int level){} /* read tetrahedra on level l stored in hdf5 file and return them in simple form */
|
|
// virtual int tetrahedron(unsigned int level, unsigned int ntetrahedron, unsigned int** tetrahedron){}
|
|
// virtual unsigned int* vertexId(){} /* read identification tag of vertices */
|
|
//
|
|
// virtual double** vertex(unsigned int level){} /* read vertices */
|
|
// virtual int vertex(unsigned int nvertex, double** vertex){} /* write vertices */
|
|
//
|
|
// virtual unsigned int** boundary(unsigned int level, unsigned int wboundary){} /* read boundary meshes stored in the hdf5 file on level and return number of them */
|
|
// virtual int boundary(unsigned int level, unsigned int** boundary, unsigned int wboundary){} /* write whichboundary boundary mesh into file */
|
|
//
|
|
// virtual unsigned int** edge(unsigned int level, aqmedge* &edge){} /* read edges on level and return number of them */
|
|
// virtual int edge(unsigned int level, unsigned int* edge){} /* write edges on level and return number of them */
|
|
//
|
|
// virtual unsigned int** triangle(unsigned int level){} /* read Triangular faces on level */
|
|
// virtual int triangle(unsigned int level, unsigned int** triangle){} /* write Triangular faces on level */
|
|
//
|
|
// /** \brief Materials */
|
|
// bool existsMaterials() /* find out if there are materials parameters at discrete frequencies, energies or wavelength */
|
|
//
|
|
// vector<double> frequency(){} /* read a vector of discrete frequencies stored in the file */
|
|
// int frequency(vector<double> f){} /* store a vector of discrete frequencies into the file */
|
|
//
|
|
// vector<double> energy(){} /* read a vector of discrete energies stored in the file */
|
|
// int energy(vector<double> e){} /* store a vector of discrete wavelengths into the file */
|
|
//
|
|
// vector<double> wavelength(){} /* read a vector of discrete wavelengths stored in the file */
|
|
// int wavelength(vector<double> lambda){} /* store a vector of discrete wavelengths into the file */
|
|
//
|
|
// vector< complex<double> > permittivity(){} /* read a vector of complex valued relative permittivities from the file */
|
|
// int permittivity( vector< complex<double> > epsilonr){} /* store a vector of complex valued relative permittivities into the file */
|
|
//
|
|
// vector< complex<double> > permeability(){} /* read a vector of complex valued relative permittivities from the file */
|
|
// int permeability( vector< complex<double> > mur){} /* store a vector of complex valued relative permittivities into the file */
|
|
//
|
|
// vector< complex<double> > conductivity(){} /* read a vector of complex valued relative permittivities from the file */
|
|
// int conductivity( vector< complex<double> sigma>){} /* store a vector of complex valued relative permittivities into the file */
|
|
//
|
|
// /** \brief Materials */
|
|
// bool existsDebyeMaterial(){} /* are the Debye material model paramters */
|
|
// bool existsLorentz(){} /* are there Lorentz material model parameters */
|
|
// bool existsDrudeMaterial(){} /* are there Drude material model parameters */
|
|
//
|
|
// /* Debye dielectric material model parameters, cf. Taflove et al. pp. 354 */
|
|
// std<double> weightsDebye(){} /* retrieve vector of Debye material model weights */
|
|
// int weightsDebye(vector<double> weightsdebye){} /* store vector of Debye material model weights */
|
|
//
|
|
// std<double> relaxationFrequencyDebye(){} /* retrieve vector of Debye material model relaxation frequencies */
|
|
// int relaxationFrequencyDebye(vector<double> relaxfreq){} /* retrieve vector of Debye material model relaxation frequencies */
|
|
//
|
|
// double epsilonStaticDebye(){} /* retrieve static limit of relative permittivitiye */
|
|
// int epsilonStaticDebye(double epsilonstaticr){} /* store static limit of relative permittivitiye */
|
|
//
|
|
// double epsilonInfinityDebye(){} /* retrieve infinite limit of relative permittivity */
|
|
// int epsilonInfinityDebye(double epsiloninftyr){} /* store infinite limit of relative permittivity */
|
|
//
|
|
// /* Lorentz dielectric material model parameters, cf. Taflove et al. pp. 354 */
|
|
// std<double> weightsLorentz(){} /* retrieve vector of Debye material model weights */
|
|
// int weightsLorentz(vector<double> weightsdebye){} /* store vector of Debye material model weights */
|
|
//
|
|
// std<double> poleFrequencyLorentz(){} /* retrieve vector of Lorentz material model relaxation frequencies */
|
|
// int poleFrequencyDebye(vector<double> polefreq){} /* retrieve vector of Lorentz material model relaxation frequencies */
|
|
//
|
|
// std<double> dampingCoefficientLorentz(){} /* retrieve vector of Lorentz material model damping coefficients */
|
|
// int dampingCoefficientLorentz(vector<double> dampingcoeff){} /* retrieve vector of Lorentz material model damping coefficients */
|
|
//
|
|
// double epsilonStaticLorentz(){} /* retrieve static limit of relative permittivitiye */
|
|
// int epsilonStaticLorentz(double epsilonstaticr){} /* store static limit of relative permittivitiye */
|
|
//
|
|
// double epsilonInfinityLorentz(){} /* retrieve infinite limit of relative permittivity */
|
|
// int epsilonInfinityLorentz(double epsiloninftyr){} /* store infinite limit of relative permittivity */
|
|
//
|
|
// /* Drude dielectric material model parameters, cf. Taflove et al. pp. 354 */
|
|
// std<double> weightsDrude(){} /* retrieve vector of Drude material model weights */
|
|
// int weightsDrude(vector<double> weightsdebye){} /* store vector of Drude material model weights */
|
|
//
|
|
// std<double> poleFrequencyDrude(){} /* retrieve vector of Drude material model pole frequencies */
|
|
// int poleFrequencyDrude(vector<double> relaxfreq){} /* retrieve vector of Drude material model pole frequencies */
|
|
//
|
|
// std<double> inversePoleRelaxationTimeDrude(){} /* retrieve vector of Lorentz material model inverse pole relaxation time */
|
|
// int inversePoleRelaxationTimeDrude(vector<double> inversepolerelaxtime){} /* retrieve vector of Lorentz material model inverse pole relaxation time */
|
|
//
|
|
// double epsilonStaticDrude(){} /* retrieve static limit of relative permittivitiye */
|
|
// int epsilonStaticDrude(double epsilonstaticr){} /* store static limit of relative permittivitiye */
|
|
//
|
|
// double epsilonInfinityDrude(){} /* retrieve infinite limit of relative permittivity */
|
|
// int epsilonInfinityDRude(double epsiloninftyr){} /* store infinite limit of relative permittivity */
|
|
//________________________________________________________________
|
|
// protected:
|
|
//
|
|
private:
|
|
//-----------------------------------------------------------------------//
|
|
// Private data structure. //
|
|
//-----------------------------------------------------------------------//
|
|
// Store the filename of the Hdf5fed here.
|
|
std::string fileName_;
|
|
// Store the file access rights of the Hdf5fed here.
|
|
std::string fileAccess_;
|
|
|
|
// Hdf5 error variable stores the success of an Hdf5 action.
|
|
herr_t hdf5Status_;
|
|
// Hdf5 file identifier for file access. If a file access fails, the
|
|
// identifyer is negetive.
|
|
hid_t hdf5FileIdent_;
|
|
|
|
// If the elements we want to write to the hdf5fed file are not consecutive
|
|
// and with gaps numbered, this API shoud be able to map this to an gapfree
|
|
// and consecutive index set.
|
|
// To activate this function we have the following variable.
|
|
bool doIndexMapping_;
|
|
// The first entry in indexMap_ is the old index of a coordinate, the
|
|
// second is the new index usend in the hdf5fed file.
|
|
std::map<unsigned int, unsigned int> indexMap_;
|
|
// The first entry in positionMap_ is the new index usend in the hdf5fed
|
|
// file, the second is the old postion in the coordinate vector.
|
|
std::map<unsigned int, unsigned int> positionMap_;
|
|
|
|
//-----------------------------------------------------------------------//
|
|
// Private helper functions. //
|
|
//-----------------------------------------------------------------------//
|
|
// This function converts a number to a string.
|
|
template<typename type>
|
|
inline std::string stringify(type value)
|
|
{
|
|
std::ostringstream oStream;
|
|
try
|
|
{
|
|
oStream << value;
|
|
}
|
|
catch(std::exception& error)
|
|
{
|
|
rError("Cannot convert this variable to a string.");
|
|
rError("Error: %d",error.what());
|
|
exit(ERRORCODE);
|
|
}
|
|
return oStream.str();
|
|
}
|
|
|
|
|
|
};
|
|
|
|
} // End of namespace Hdf5fed
|
|
|
|
#elif
|
|
#warning "No HDF5 found. You cannot use hdf5fed."
|
|
#endif // HAVE_HDF5
|
|
#endif //HDF5FED_HH_
|