changed: split HDF5 class in 3 parts
- HDF5Writer writes - HDF5Reader reads - HDF5Restart reads and writes restart data
This commit is contained in:
parent
7be71a9a73
commit
59ad507d3a
@ -22,6 +22,7 @@
|
||||
#include "MatVec.h"
|
||||
#include "Vec3.h"
|
||||
#include "DataExporter.h"
|
||||
#include "HDF5Restart.h"
|
||||
#include "HDF5Writer.h"
|
||||
#include "tinyxml.h"
|
||||
#include <fstream>
|
||||
@ -170,9 +171,9 @@ public:
|
||||
}
|
||||
|
||||
//! \brief Dummy method, no serialization support.
|
||||
bool serialize(DataExporter::SerializeData&) { return false; }
|
||||
bool serialize(HDF5Restart::SerializeData&) { return false; }
|
||||
//! \brief Dummy method, no deserialization support.
|
||||
bool deSerialize(const DataExporter::SerializeData&) { return false; }
|
||||
bool deSerialize(const HDF5Restart::SerializeData&) { return false; }
|
||||
|
||||
//! \brief Solves the nonlinear equations by Newton-Raphson iterations.
|
||||
bool solveStep(TimeStep& tp)
|
||||
|
@ -17,6 +17,7 @@
|
||||
#include "IFEM.h"
|
||||
#include "SIMadmin.h"
|
||||
#include "TimeStep.h"
|
||||
#include "HDF5Restart.h"
|
||||
#include "HDF5Writer.h"
|
||||
#include "tinyxml.h"
|
||||
|
||||
@ -45,16 +46,14 @@ public:
|
||||
//! \brief Handles application data output.
|
||||
//! \param[in] hdf5file The file to save to
|
||||
//! \param[in] saveInterval The stride in the output file
|
||||
//! \param[in] restartInterval The stride in the restart file
|
||||
void handleDataOutput(const std::string& hdf5file,
|
||||
int saveInterval = 1, int restartInterval = 0)
|
||||
void handleDataOutput(const std::string& hdf5file, int saveInterval = 1)
|
||||
{
|
||||
if (IFEM::getOptions().discretization < ASM::Spline && !hdf5file.empty())
|
||||
IFEM::cout <<"\n ** HDF5 output is available for spline discretization"
|
||||
<<" only. Deactivating...\n"<< std::endl;
|
||||
else
|
||||
{
|
||||
exporter = new DataExporter(true,saveInterval,restartInterval);
|
||||
exporter = new DataExporter(true,saveInterval);
|
||||
exporter->registerWriter(new HDF5Writer(hdf5file,adm));
|
||||
S1.registerFields(*exporter);
|
||||
IFEM::registerCallback(*exporter);
|
||||
@ -123,10 +122,11 @@ public:
|
||||
explicit SIMSolver(T1& s1) : SIMSolverStat<T1>(s1,"Time integration driver")
|
||||
{
|
||||
saveDivergedSol = false;
|
||||
restartAdm = nullptr;
|
||||
}
|
||||
|
||||
//! \brief Empty destructor.
|
||||
virtual ~SIMSolver() {}
|
||||
//! \brief The destructor deletes the restart data handler.
|
||||
virtual ~SIMSolver() { delete restartAdm; }
|
||||
|
||||
//! \brief Reads solver data from the specified input file.
|
||||
virtual bool read(const char* file) { return this->SIMadmin::read(file); }
|
||||
@ -161,16 +161,29 @@ public:
|
||||
return 0;
|
||||
}
|
||||
|
||||
//! \brief Handles application data output.
|
||||
//! \param[in] hdf5file The file to save to
|
||||
//! \param[in] saveInterval The stride in the output file
|
||||
//! \param[in] restartInterval The stride in the restart file
|
||||
void handleDataOutput(const std::string& hdf5file,
|
||||
int saveInterval = 1, int restartInterval = 0)
|
||||
{
|
||||
if (restartInterval > 0)
|
||||
restartAdm = new HDF5Restart(hdf5file+"_restart",this->adm,restartInterval);
|
||||
|
||||
this->SIMSolverStat<T1>::handleDataOutput(hdf5file, saveInterval);
|
||||
}
|
||||
|
||||
//! \brief Serialize internal state for restarting purposes.
|
||||
//! \param data Container for serialized data
|
||||
bool serialize(DataExporter::SerializeData& data)
|
||||
bool serialize(HDF5Restart::SerializeData& data)
|
||||
{
|
||||
return tp.serialize(data) && this->S1.serialize(data);
|
||||
}
|
||||
|
||||
//! \brief Set internal state from a serialized state.
|
||||
//! \param[in] data Container for serialized data
|
||||
bool deSerialize(const DataExporter::SerializeData& data)
|
||||
bool deSerialize(const HDF5Restart::SerializeData& data)
|
||||
{
|
||||
return tp.deSerialize(data) && this->S1.deSerialize(data);
|
||||
}
|
||||
@ -204,12 +217,12 @@ protected:
|
||||
return false;
|
||||
|
||||
if (saveRes && SIMSolverStat<T1>::exporter) {
|
||||
DataExporter::SerializeData data;
|
||||
if (SIMSolverStat<T1>::exporter->dumpForRestart(&tp) &&
|
||||
this->serialize(data))
|
||||
return SIMSolverStat<T1>::exporter->dumpTimeLevel(&tp,newMesh,&data);
|
||||
else // no restart dump, or serialization failure
|
||||
return SIMSolverStat<T1>::exporter->dumpTimeLevel(&tp,newMesh);
|
||||
HDF5Restart::SerializeData data;
|
||||
if (restartAdm && restartAdm->dumpStep(tp) && this->serialize(data))
|
||||
if (!restartAdm->writeData(tp,data))
|
||||
return false;
|
||||
|
||||
return SIMSolverStat<T1>::exporter->dumpTimeLevel(&tp,newMesh);
|
||||
}
|
||||
|
||||
return true;
|
||||
@ -225,9 +238,9 @@ public:
|
||||
{
|
||||
if (restartFile.empty()) return 0;
|
||||
|
||||
DataExporter::SerializeData data;
|
||||
HDF5Writer hdf(restartFile,SIMadmin::adm,true);
|
||||
if ((restartStep = hdf.readRestartData(data,restartStep)) >= 0)
|
||||
HDF5Restart::SerializeData data;
|
||||
HDF5Restart hdf(restartFile,SIMadmin::adm,1);
|
||||
if ((restartStep = hdf.readData(data,restartStep)) >= 0)
|
||||
{
|
||||
IFEM::cout <<"\n === Restarting from a serialized state ==="
|
||||
<<"\n file = "<< restartFile
|
||||
@ -247,6 +260,7 @@ private:
|
||||
|
||||
protected:
|
||||
TimeStep tp; //!< Time stepping information
|
||||
HDF5Restart* restartAdm; //!< Administrator for restart output
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -20,7 +20,7 @@
|
||||
#include "LinSolParams.h"
|
||||
#include "Functions.h"
|
||||
#include "Utilities.h"
|
||||
#include "HDF5Writer.h"
|
||||
#include "HDF5Reader.h"
|
||||
#include "IFEM.h"
|
||||
#include "tinyxml.h"
|
||||
#include <fstream>
|
||||
@ -73,16 +73,17 @@ bool SIMinput::parseGeometryTag (const TiXmlElement* elem)
|
||||
else if (strstr(file,".hdf5"))
|
||||
{
|
||||
IFEM::cout <<"\tReading global node numbers from "<< file << std::endl;
|
||||
HDF5Writer hdf5(file,ProcessAdm(),true,true);
|
||||
HDF5Reader hdf5(file,ProcessAdm());
|
||||
const char* field = elem->Attribute("field");
|
||||
for (int i = 1; i <= nGlPatches; i++)
|
||||
{
|
||||
IntVec nodes;
|
||||
ASMbase* pch = this->getPatch(i,true);
|
||||
if (pch && hdf5.readVector(0, field ? field : "node numbers", i, nodes))
|
||||
std::stringstream str;
|
||||
str << "/0/" << (field ? field : "node numbers") << "/" << i;
|
||||
if (pch && hdf5.readVector(str.str(),nodes))
|
||||
pch->setNodeNumbers(nodes);
|
||||
}
|
||||
hdf5.closeFile(0, true);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1210,8 +1211,7 @@ bool SIMinput::setInitialCondition (SIMdependency* fieldHolder,
|
||||
const std::string& fileName,
|
||||
const InitialCondVec& info)
|
||||
{
|
||||
HDF5Writer hdf5reader(fileName,adm,true,true);
|
||||
hdf5reader.openFile(0);
|
||||
HDF5Reader hdf5reader(fileName,adm);
|
||||
|
||||
std::map<std::string,PatchVec> basisMap;
|
||||
|
||||
@ -1225,7 +1225,9 @@ bool SIMinput::setInitialCondition (SIMdependency* fieldHolder,
|
||||
// Load basis
|
||||
CharVec nf(1,this->getNoFields(it.basis));
|
||||
PatchVec& basisVec = basisMap[it.file_basis];
|
||||
int nPatches = hdf5reader.getFieldSize(it.geo_level, it.file_basis+"/basis","");
|
||||
std::stringstream str;
|
||||
str << it.geo_level << "/" << it.file_basis << "/basis";
|
||||
int nPatches = hdf5reader.getFieldSize(str.str());
|
||||
if (basisVec.empty()) {
|
||||
for (int i = 0; i < nPatches; i++)
|
||||
if (this->getLocalPatchIndex(i+1) > 0)
|
||||
@ -1247,7 +1249,9 @@ bool SIMinput::setInitialCondition (SIMdependency* fieldHolder,
|
||||
if (!pch) continue;
|
||||
|
||||
Vector loc, newloc;
|
||||
hdf5reader.readVector(it.file_level, it.file_basis+"/fields/"+it.file_field, i+1, loc);
|
||||
std::stringstream str;
|
||||
str << it.file_level << "/" << it.file_basis << "/fields/" << it.file_field << "/" << i+1;
|
||||
hdf5reader.readVector(str.str(), loc);
|
||||
basisVec[p-1]->copyParameterDomain(pch);
|
||||
if (pch->evaluate(basisVec[p-1], loc, newloc, it.basis))
|
||||
pch->injectNodeVec(newloc, *field, newloc.size()/pch->getNoNodes(it.basis), it.basis);
|
||||
@ -1259,7 +1263,6 @@ bool SIMinput::setInitialCondition (SIMdependency* fieldHolder,
|
||||
for (ASMbase* pch : itb.second)
|
||||
delete pch;
|
||||
|
||||
hdf5reader.closeFile(0,true);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -97,24 +97,15 @@ bool DataExporter::setFieldValue (const std::string& name,
|
||||
}
|
||||
|
||||
|
||||
bool DataExporter::dumpForRestart (const TimeStep* tp) const
|
||||
{
|
||||
return m_nrestart > 0 && tp && tp->step % m_nrestart == 0;
|
||||
}
|
||||
|
||||
|
||||
bool DataExporter::dumpTimeLevel (const TimeStep* tp, bool geometryUpdated,
|
||||
SerializeData* serializeData)
|
||||
bool DataExporter::dumpTimeLevel (const TimeStep* tp, bool geometryUpdated)
|
||||
{
|
||||
// ignore multiple calls for the same time step
|
||||
if (tp && tp->step == m_last_step)
|
||||
return true;
|
||||
|
||||
bool writeData = !tp || tp->step % m_ndump == 0;
|
||||
bool writeRestart = serializeData && this->dumpForRestart(tp);
|
||||
int restartLevel = writeRestart ? tp->step / m_nrestart : 0;
|
||||
|
||||
if (!writeRestart && !writeData)
|
||||
if (!writeData)
|
||||
return true;
|
||||
|
||||
PROFILE1("DataExporter::dumpTimeLevel");
|
||||
@ -157,8 +148,6 @@ bool DataExporter::dumpTimeLevel (const TimeStep* tp, bool geometryUpdated,
|
||||
}
|
||||
if (tp && tp->multiSteps())
|
||||
writer->writeTimeInfo(m_level,m_ndump,*tp);
|
||||
if (writeRestart)
|
||||
writer->writeRestartData(restartLevel, *serializeData);
|
||||
|
||||
writer->closeFile(m_level);
|
||||
}
|
||||
|
@ -34,8 +34,6 @@ class TimeStep;
|
||||
class DataExporter : public ControlCallback
|
||||
{
|
||||
public:
|
||||
typedef std::map<std::string, std::string> SerializeData; //!< Convenience typedef
|
||||
|
||||
//! \brief Supported field types
|
||||
enum FieldType {
|
||||
VECTOR,
|
||||
@ -76,10 +74,9 @@ public:
|
||||
//! \brief Default constructor.
|
||||
//! \param[in] dynWriters If \e true, delete the writers on destruction
|
||||
//! \param[in] ndump Interval between dumps
|
||||
//! \param[in] nrestart Restart stride. 0 to disable
|
||||
DataExporter(bool dynWriters = false, int ndump=1, int nrestart=0) :
|
||||
DataExporter(bool dynWriters = false, int ndump=1) :
|
||||
m_delete(dynWriters), m_level(-1), m_ndump(ndump),
|
||||
m_last_step(-1), m_nrestart(nrestart), m_infoReader(0), m_dataReader(0) {}
|
||||
m_last_step(-1), m_infoReader(0), m_dataReader(0) {}
|
||||
|
||||
//! \brief The destructor deletes the writers if \a dynWriters was \e true.
|
||||
virtual ~DataExporter();
|
||||
@ -117,16 +114,7 @@ public:
|
||||
//! \brief Dumps all registered fields using the registered writers.
|
||||
//! \param[in] tp Current time stepping info
|
||||
//! \param[in] geometryUpdated Whether or not geometries are updated
|
||||
//! \param[in] serializeData Serialized data from simulators for restart files
|
||||
bool dumpTimeLevel(const TimeStep* tp=nullptr, bool geometryUpdated=false,
|
||||
SerializeData* serializeData = nullptr);
|
||||
|
||||
//! \brief Loads last time level with first registered writer by default.
|
||||
//! \param[in] level Time level to load, defaults to last time level
|
||||
//! \param[in] info DataWriter to read the info from (e.g. the XML writer)
|
||||
//! \param[in] input DataWriter to read the data from (e.g. the HDF5 writer)
|
||||
bool loadTimeLevel(int level=-1,
|
||||
DataWriter* info=nullptr, DataWriter* input=nullptr);
|
||||
bool dumpTimeLevel(const TimeStep* tp=nullptr, bool geometryUpdated=false);
|
||||
|
||||
//! \brief Returns the current time level of the exporter.
|
||||
int getTimeLevel();
|
||||
@ -148,9 +136,6 @@ public:
|
||||
//! \brief Returns visualization data stride
|
||||
int getStride() const { return m_ndump; }
|
||||
|
||||
//! \brief Returns whether current step should be saved for restart or not.
|
||||
bool dumpForRestart(const TimeStep* tp) const;
|
||||
|
||||
protected:
|
||||
//! \brief Internal helper function.
|
||||
int getWritersTimeLevel() const;
|
||||
@ -164,7 +149,6 @@ protected:
|
||||
int m_level; //!< Current time level
|
||||
int m_ndump; //!< Time level stride for dumping
|
||||
int m_last_step; //!< Last time step we dumped for
|
||||
int m_nrestart; //!< Stride for restart data dumping
|
||||
|
||||
DataWriter* m_infoReader; //!< DataWriter to read data information from
|
||||
DataWriter* m_dataReader; //!< DataWriter to read numerical data from
|
||||
@ -201,20 +185,13 @@ public:
|
||||
|
||||
//! \brief Closes the file.
|
||||
//! \param[in] level Level we just wrote to the file
|
||||
//! \param[in] force If true, we always close the actual file,
|
||||
//! otherwise it's up to the individual writers
|
||||
virtual void closeFile(int level, bool force = false) = 0;
|
||||
virtual void closeFile(int level) = 0;
|
||||
|
||||
//! \brief Writes a vector to file.
|
||||
//! \param[in] level The time level to write the vector at
|
||||
//! \param[in] entry The DataEntry describing the vector
|
||||
virtual void writeVector(int level, const DataEntry& entry) = 0;
|
||||
|
||||
//! \brief Reads a vector from file.
|
||||
//! \param[in] level The time level to read the vector at
|
||||
//! \param[in] entry The DataEntry describing the vector
|
||||
virtual bool readVector(int level, const DataEntry& entry) = 0;
|
||||
|
||||
//! \brief Writes data from a SIM object to file.
|
||||
//! \param[in] level The time level to write the data at
|
||||
//! \param[in] entry The DataEntry describing the vector
|
||||
@ -255,11 +232,6 @@ public:
|
||||
//! \brief Returns the name of the file
|
||||
const std::string& getName() const { return m_name; }
|
||||
|
||||
//! \brief Write restart data.
|
||||
//! \param[in] level Level to write restart data at
|
||||
//! \param[in] data Data to write
|
||||
virtual bool writeRestartData(int level, const DataExporter::SerializeData& data) = 0;
|
||||
|
||||
protected:
|
||||
std::string m_name; //!< File name
|
||||
std::vector<std::string> m_prefix; //!< The norm prefixes
|
||||
|
@ -20,7 +20,7 @@
|
||||
#include "Vec3.h"
|
||||
#include "StringUtils.h"
|
||||
#ifdef HAS_HDF5
|
||||
#include "HDF5Writer.h"
|
||||
#include "HDF5Reader.h"
|
||||
#include "ProcessAdm.h"
|
||||
#include <sstream>
|
||||
#endif
|
||||
@ -36,8 +36,7 @@ FieldFuncBase::FieldFuncBase (const std::string& fName) :
|
||||
lastTime = 0.0;
|
||||
#ifdef HAS_HDF5
|
||||
pAdm = new ProcessAdm();
|
||||
hdf5 = new HDF5Writer(fName,*pAdm,true,true);
|
||||
hdf5->readDouble(lastLevel,"timeinfo","SIMbase-1",lastTime);
|
||||
hdf5 = new HDF5Reader(fName,*pAdm);
|
||||
#else
|
||||
std::cerr <<"WARNING: Compiled without HDF5 support,"
|
||||
<<" field function is not instantiated."<< std::endl;
|
||||
@ -61,9 +60,13 @@ int FieldFuncBase::findClosestLevel (double time) const
|
||||
#ifdef HAS_HDF5
|
||||
double t;
|
||||
int incLev = time > lastTime ? 1 : -1;
|
||||
while (hdf5->readDouble(lastLevel+incLev,"timeinfo","SIMbase-1",t))
|
||||
bool ok = true;
|
||||
while (ok)
|
||||
{
|
||||
if (fabs(time-t) >= fabs(time-lastTime))
|
||||
std::stringstream str;
|
||||
str << lastLevel+incLev << "/timeinfo/SIMbase-1";
|
||||
ok = hdf5->readDouble(str.str(),t);
|
||||
if (ok && fabs(time-t) >= fabs(time-lastTime))
|
||||
{
|
||||
#ifdef SP_DEBUG
|
||||
std::cout <<"FieldFuncBase: New time level "<< lastLevel
|
||||
@ -87,7 +90,9 @@ bool FieldFuncBase::load (const std::vector<std::string>& fieldNames,
|
||||
size_t nOK = 0;
|
||||
size_t nPatches = 0;
|
||||
#ifdef HAS_HDF5
|
||||
nPatches = hdf5->getFieldSize(level, basisName, fieldNames.front());
|
||||
std::stringstream str;
|
||||
str << level << "/" << basisName << "/fields/" << fieldNames.front();
|
||||
nPatches = hdf5->getFieldSize(str.str());
|
||||
#endif
|
||||
if (nPatches == 0)
|
||||
nPatches = patch.size();
|
||||
@ -101,7 +106,9 @@ bool FieldFuncBase::load (const std::vector<std::string>& fieldNames,
|
||||
size_t nFldC3D = isScalar ? 1 : (nFldCmp < 3 ? 3 : nFldCmp);
|
||||
for (size_t ip = 0; ip < nPatches; ip++)
|
||||
{
|
||||
if (hdf5->hasGeometries(level,basisName))
|
||||
std::stringstream str;
|
||||
str << level << "/" << basisName << "/basis";
|
||||
if (hdf5->getFieldSize(str.str()))
|
||||
{
|
||||
if (patch[ip])
|
||||
{
|
||||
@ -140,7 +147,9 @@ bool FieldFuncBase::load (const std::vector<std::string>& fieldNames,
|
||||
RealArrays coefs(nFldCmp);
|
||||
for (size_t i = 0; i < nFldCmp; i++)
|
||||
{
|
||||
hdf5->readVector(level,basisName+"/fields/"+fieldNames[i],ip+1,coefs[i]);
|
||||
std::stringstream str;
|
||||
str << level << "/" << basisName << "/fields/" << fieldNames[i] << "/" << ip+1;
|
||||
hdf5->readVector(str.str(),coefs[i]);
|
||||
#if SP_DEBUG > 1
|
||||
std::cout <<"FieldFuncBase::load: Reading \""<< fieldNames[i]
|
||||
<<"\" ("<< coefs[i].size() <<") for patch "<< ip+1;
|
||||
|
@ -20,7 +20,7 @@
|
||||
class Field;
|
||||
class Fields;
|
||||
class ASMbase;
|
||||
class HDF5Writer;
|
||||
class HDF5Reader;
|
||||
class ProcessAdm;
|
||||
|
||||
|
||||
@ -63,7 +63,7 @@ protected:
|
||||
|
||||
private:
|
||||
#ifdef HAS_HDF5
|
||||
HDF5Writer* hdf5; //!< The HDF5-file containing the field data
|
||||
HDF5Reader* hdf5; //!< The HDF5-file containing the field data
|
||||
ProcessAdm* pAdm; //!< Process administrator for the HDF5-file reader
|
||||
#endif
|
||||
|
||||
|
102
src/Utility/HDF5Base.C
Normal file
102
src/Utility/HDF5Base.C
Normal file
@ -0,0 +1,102 @@
|
||||
// $Id$
|
||||
//==============================================================================
|
||||
//!
|
||||
//! \file HDF5Base.C
|
||||
//!
|
||||
//! \date Nov 1 2018
|
||||
//!
|
||||
//! \author Arne Morten Kvarving / SINTEF
|
||||
//!
|
||||
//! \brief Base class for interacting with HDF5 files.
|
||||
//!
|
||||
//==============================================================================
|
||||
|
||||
#include "HDF5Base.h"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#ifdef HAS_HDF5
|
||||
#include <numeric>
|
||||
#include <unistd.h>
|
||||
#ifdef HAVE_MPI
|
||||
#include "ProcessAdm.h"
|
||||
#include <mpi.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
HDF5Base::HDF5Base (const std::string& name, const ProcessAdm& adm)
|
||||
: m_file(-1), m_hdf5_name(name)
|
||||
#ifdef HAVE_MPI
|
||||
, m_adm(adm)
|
||||
#endif
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
HDF5Base::~HDF5Base ()
|
||||
{
|
||||
closeFile();
|
||||
}
|
||||
|
||||
|
||||
bool HDF5Base::openFile (unsigned flags)
|
||||
{
|
||||
if (m_file != -1)
|
||||
return true;
|
||||
|
||||
#ifdef HAS_HDF5
|
||||
#ifdef HAVE_MPI
|
||||
MPI_Info info = MPI_INFO_NULL;
|
||||
hid_t acc_tpl = H5Pcreate(H5P_FILE_ACCESS);
|
||||
H5Pset_fapl_mpio(acc_tpl, *m_adm.getCommunicator(), info);
|
||||
#else
|
||||
hid_t acc_tpl = H5P_DEFAULT;
|
||||
#endif
|
||||
|
||||
if (flags == H5F_ACC_TRUNC)
|
||||
m_file = H5Fcreate(m_hdf5_name.c_str(),flags,H5P_DEFAULT,acc_tpl);
|
||||
else
|
||||
m_file = H5Fopen(m_hdf5_name.c_str(),flags,acc_tpl);
|
||||
|
||||
if (m_file < 0)
|
||||
{
|
||||
std::cerr <<" *** HDF5Base: Failed to open "<< m_hdf5_name << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifdef HAVE_MPI
|
||||
H5Pclose(acc_tpl);
|
||||
#endif
|
||||
return true;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void HDF5Base::closeFile()
|
||||
{
|
||||
#ifdef HAS_HDF5
|
||||
if (m_file != -1)
|
||||
H5Fclose(m_file);
|
||||
#endif
|
||||
m_file = -1;
|
||||
}
|
||||
|
||||
|
||||
bool HDF5Base::checkGroupExistence (hid_t parent, const char* path)
|
||||
{
|
||||
bool result = false;
|
||||
#ifdef HAS_HDF5
|
||||
// turn off errors to avoid cout spew
|
||||
H5E_BEGIN_TRY {
|
||||
#if H5_VERS_MINOR > 8
|
||||
result = H5Lexists(parent, path, H5P_DEFAULT) == 1;
|
||||
#else
|
||||
result = H5Gget_objinfo((hid_t)parent,path,0,nullptr) == 0;
|
||||
#endif
|
||||
} H5E_END_TRY;
|
||||
#endif
|
||||
return result;
|
||||
}
|
68
src/Utility/HDF5Base.h
Normal file
68
src/Utility/HDF5Base.h
Normal file
@ -0,0 +1,68 @@
|
||||
// $Id$
|
||||
//==============================================================================
|
||||
//!
|
||||
//! \file HDF5Base.h
|
||||
//!
|
||||
//! \date Nov 1 2018
|
||||
//!
|
||||
//! \author Arne Morten Kvarving / SINTEF
|
||||
//!
|
||||
//! \brief Base class for interacting with HDF5 files.
|
||||
//!
|
||||
//==============================================================================
|
||||
|
||||
#ifndef _HDF5_BASE_H
|
||||
#define _HDF5_BASE_H
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#ifdef HAS_HDF5
|
||||
#include <hdf5.h>
|
||||
#endif
|
||||
|
||||
|
||||
class ProcessAdm;
|
||||
|
||||
|
||||
/*!
|
||||
\brief Base class for interacting with HDF5 files.
|
||||
*/
|
||||
|
||||
class HDF5Base
|
||||
{
|
||||
public:
|
||||
#ifndef HAS_HDF5
|
||||
using hid_t = int; //!< Type alias providing hid_t without the hdf5 library
|
||||
using herr_t = int; //!< Type alias providing herr_t without the hdf5 library
|
||||
#endif
|
||||
//! \brief The constructor opens a named HDF5-file.
|
||||
//! \param[in] name The name (without extension) of the data file
|
||||
//! \param[in] adm The process administrator
|
||||
HDF5Base(const std::string& name, const ProcessAdm& adm);
|
||||
|
||||
//! \brief The destructor closes the file.
|
||||
virtual ~HDF5Base();
|
||||
|
||||
protected:
|
||||
//! \brief Open the HDF5 file.
|
||||
//!\ param flag Mode to open file using
|
||||
bool openFile (unsigned flag);
|
||||
|
||||
//! \brief Close the HDF5 file.
|
||||
void closeFile();
|
||||
|
||||
//! \brief Internal helper function checking if a group exists in the file.
|
||||
//! \param[in] parent The HDF5 group of the parent
|
||||
//! \param[in] path Path of dataset
|
||||
//! \return \e true if group exists, otherwise \e false
|
||||
bool checkGroupExistence (hid_t parent, const char* path);
|
||||
|
||||
hid_t m_file; //!< The HDF5 handle for our file
|
||||
std::string m_hdf5_name; //!< The file name of the HDF5 file
|
||||
#ifdef HAVE_MPI
|
||||
const ProcessAdm& m_adm; //!< Pointer to process adm in use
|
||||
#endif
|
||||
};
|
||||
|
||||
#endif
|
143
src/Utility/HDF5Reader.C
Normal file
143
src/Utility/HDF5Reader.C
Normal file
@ -0,0 +1,143 @@
|
||||
// $Id$
|
||||
//==============================================================================
|
||||
//!
|
||||
//! \file HDF5Reader.C
|
||||
//!
|
||||
//! \date Nov 1 2018
|
||||
//!
|
||||
//! \author Arne Morten Kvarving / SINTEF
|
||||
//!
|
||||
//! \brief Read data from HDF5 file.
|
||||
//!
|
||||
//==============================================================================
|
||||
|
||||
#include "HDF5Reader.h"
|
||||
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
|
||||
#ifdef HAS_HDF5
|
||||
#include <numeric>
|
||||
#include <unistd.h>
|
||||
#ifdef HAVE_MPI
|
||||
#include <mpi.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
HDF5Reader::HDF5Reader (const std::string& name, const ProcessAdm& adm)
|
||||
: HDF5Base((name.find(".hdf5") == std::string::npos ? name+".hdf5": name), adm)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
/*!
|
||||
\brief Helper for reading data from HDF5 file
|
||||
*/
|
||||
|
||||
#ifdef HAS_HDF5
|
||||
template<class T>
|
||||
static bool hdf5Read(hid_t file, hid_t type,
|
||||
const std::string& path, std::vector<T>& vec)
|
||||
{
|
||||
hid_t set = H5Dopen2(file,path.c_str(),H5P_DEFAULT);
|
||||
hsize_t size = H5Dget_storage_size(set) / sizeof(T);
|
||||
if (size != 0) {
|
||||
vec.resize(size);
|
||||
H5Dread(set,type,H5S_ALL,H5S_ALL,H5P_DEFAULT,&vec[0]);
|
||||
H5Dclose(set);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
bool HDF5Reader::readVector (const std::string& path, std::vector<int>& vec)
|
||||
{
|
||||
#ifdef HAS_HDF5
|
||||
if (!this->openFile(H5F_ACC_RDONLY))
|
||||
return false;
|
||||
|
||||
return hdf5Read(m_file, H5T_NATIVE_INT, path, vec);
|
||||
#else
|
||||
std::cerr << "HDF5Reader: compiled without HDF5 support, no data read" << std::endl;
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
bool HDF5Reader::readVector (const std::string& path, std::vector<double>& vec)
|
||||
{
|
||||
#ifdef HAS_HDF5
|
||||
if (!this->openFile(H5F_ACC_RDONLY))
|
||||
return false;
|
||||
|
||||
return hdf5Read(m_file, H5T_NATIVE_DOUBLE, path, vec);
|
||||
#else
|
||||
std::cerr << "HDF5Reader: compiled without HDF5 support, no data read" << std::endl;
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
bool HDF5Reader::readDouble (const std::string& path, double& out)
|
||||
{
|
||||
#ifdef HAS_HDF5
|
||||
if (!this->openFile(H5F_ACC_RDONLY))
|
||||
return false;
|
||||
|
||||
std::vector<double> vec;
|
||||
if (!hdf5Read(m_file, H5T_NATIVE_DOUBLE, path, vec))
|
||||
return false;
|
||||
|
||||
out = vec.front();
|
||||
return true;
|
||||
#else
|
||||
std::cerr << "HDF5Reader: compiled without HDF5 support, no data read" << std::endl;
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
bool HDF5Reader::readString (const std::string& name, std::string& out)
|
||||
{
|
||||
#ifdef HAS_HDF5
|
||||
if (!this->openFile(H5F_ACC_RDONLY))
|
||||
return false;
|
||||
|
||||
hid_t set = H5Dopen2(m_file,name.c_str(),H5P_DEFAULT);
|
||||
hid_t space = H5Dget_space(set);
|
||||
hsize_t siz = H5Sget_simple_extent_npoints(space);
|
||||
out.resize(siz);
|
||||
H5Dread(set,H5T_NATIVE_CHAR,H5S_ALL,H5S_ALL,H5P_DEFAULT,&out[0]);
|
||||
H5Dclose(set);
|
||||
return true;
|
||||
#else
|
||||
std::cerr << "HDF5Reader: compiled without HDF5 support, no data read" << std::endl;
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
int HDF5Reader::getFieldSize (const std::string& fieldPath)
|
||||
{
|
||||
#ifdef HAS_HDF5
|
||||
if (!this->openFile(H5F_ACC_RDONLY))
|
||||
return 0;
|
||||
|
||||
int patches = 0;
|
||||
while (true) {
|
||||
++patches;
|
||||
std::stringstream str;
|
||||
str << fieldPath << "/" << patches;
|
||||
if (!checkGroupExistence(m_file, str.str().c_str()))
|
||||
break;
|
||||
}
|
||||
|
||||
return patches-1;
|
||||
#else
|
||||
std::cerr << "HDF5Reader: compiled without HDF5 support, no data read" << std::endl;
|
||||
return 0;
|
||||
#endif
|
||||
}
|
58
src/Utility/HDF5Reader.h
Normal file
58
src/Utility/HDF5Reader.h
Normal file
@ -0,0 +1,58 @@
|
||||
// $Id$
|
||||
//==============================================================================
|
||||
//!
|
||||
//! \file HDF5Reader.h
|
||||
//!
|
||||
//! \date Nov 1 2018
|
||||
//!
|
||||
//! \author Arne Morten Kvarving / SINTEF
|
||||
//!
|
||||
//! \brief Read data from HDF5 file.
|
||||
//!
|
||||
//==============================================================================
|
||||
|
||||
#ifndef _HDF5_READER_H
|
||||
#define _HDF5_READER_H
|
||||
|
||||
#include "HDF5Base.h"
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
/*!
|
||||
\brief Read data from a HDF5 file.
|
||||
*/
|
||||
|
||||
class HDF5Reader : public HDF5Base
|
||||
{
|
||||
public:
|
||||
//! \brief The constructor opens a named HDF5-file.
|
||||
//! \param[in] name The name (without extension) of the data file
|
||||
//! \param[in] adm The process administrator
|
||||
HDF5Reader(const std::string& name, const ProcessAdm& adm);
|
||||
|
||||
//! \brief Reads an integer vector.
|
||||
//! \param[in] path The path to the dataset to read
|
||||
//! \param[out] vec The vector to read data into
|
||||
bool readVector(const std::string& path, std::vector<int>& vec);
|
||||
|
||||
//! \brief Reads an double precision vector.
|
||||
//! \param[in] path The path to the dataset to read
|
||||
//! \param[out] vec The vector to read data into
|
||||
bool readVector(const std::string& path, std::vector<double>& vec);
|
||||
|
||||
//! \brief Reads a single double value.
|
||||
//! \param[in] name The name (path in HDF5 file) to the string
|
||||
//! \param[out] out The double to read data into
|
||||
bool readDouble(const std::string& name, double& out);
|
||||
|
||||
//! \brief Reads a text string.
|
||||
//! \param[in] name The name (path in HDF5 file) to the string
|
||||
//! \param[out] out The string to read data into
|
||||
bool readString(const std::string& name, std::string& out);
|
||||
|
||||
//! \brief Returns number of patches for a field.
|
||||
//! \param[in] fieldPath Path to field in hdf5 file
|
||||
int getFieldSize(const std::string& fieldPath);
|
||||
};
|
||||
|
||||
#endif
|
195
src/Utility/HDF5Restart.C
Normal file
195
src/Utility/HDF5Restart.C
Normal file
@ -0,0 +1,195 @@
|
||||
// $Id$
|
||||
//==============================================================================
|
||||
//!
|
||||
//! \file HDF5Restart.C
|
||||
//!
|
||||
//! \date Nov 1 2018
|
||||
//!
|
||||
//! \author Arne Morten Kvarving / SINTEF
|
||||
//!
|
||||
//! \brief Output of restart data to HDF5 file.
|
||||
//!
|
||||
//==============================================================================
|
||||
|
||||
#include "HDF5Restart.h"
|
||||
#include "TimeStep.h"
|
||||
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
|
||||
#ifdef HAS_HDF5
|
||||
#include <numeric>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
#ifdef HAVE_MPI
|
||||
#include <mpi.h>
|
||||
#include "ProcessAdm.h"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
HDF5Restart::HDF5Restart (const std::string& name, const ProcessAdm& adm,
|
||||
int stride)
|
||||
: HDF5Base(name, adm), m_stride(stride)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
bool HDF5Restart::dumpStep(const TimeStep& tp)
|
||||
{
|
||||
return (tp.step % m_stride) == 0;
|
||||
}
|
||||
|
||||
|
||||
void HDF5Restart::readArray(hid_t group, const std::string& name,
|
||||
int& len, char*& data)
|
||||
{
|
||||
#ifdef HAS_HDF5
|
||||
hid_t set = H5Dopen2(group,name.c_str(),H5P_DEFAULT);
|
||||
hsize_t siz = H5Dget_storage_size(set);
|
||||
len = siz;
|
||||
data = new char[siz];
|
||||
H5Dread(set,H5T_NATIVE_CHAR,H5S_ALL,H5S_ALL,H5P_DEFAULT,data);
|
||||
H5Dclose(set);
|
||||
#else
|
||||
len = 0;
|
||||
std::cout << "HDF5Restart: compiled without HDF5 support, no data read" << std::endl;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void HDF5Restart::writeArray(hid_t group, const std::string& name,
|
||||
int len, const void* data, hid_t type)
|
||||
{
|
||||
#ifdef HAS_HDF5
|
||||
#ifdef HAVE_MPI
|
||||
int lens[m_adm.getNoProcs()], lens2[m_adm.getNoProcs()];
|
||||
std::fill(lens,lens+m_adm.getNoProcs(),len);
|
||||
MPI_Alltoall(lens,1,MPI_INT,lens2,1,MPI_INT,*m_adm.getCommunicator());
|
||||
hsize_t siz = (hsize_t)std::accumulate(lens2,lens2+m_adm.getNoProcs(),0);
|
||||
hsize_t start = (hsize_t)std::accumulate(lens2,lens2+m_adm.getProcId(),0);
|
||||
#else
|
||||
hsize_t siz = (hsize_t)len;
|
||||
hsize_t start = 0;
|
||||
#endif
|
||||
hid_t space = H5Screate_simple(1,&siz,nullptr);
|
||||
hid_t set = H5Dcreate2(group,name.c_str(),
|
||||
type,space,H5P_DEFAULT,H5P_DEFAULT,H5P_DEFAULT);
|
||||
if (len > 0) {
|
||||
hid_t file_space = H5Dget_space(set);
|
||||
siz = len;
|
||||
hsize_t stride = 1;
|
||||
H5Sselect_hyperslab(file_space,H5S_SELECT_SET,&start,&stride,&siz,nullptr);
|
||||
hid_t mem_space = H5Screate_simple(1,&siz,nullptr);
|
||||
H5Dwrite(set,type,mem_space,file_space,H5P_DEFAULT,data);
|
||||
H5Sclose(mem_space);
|
||||
H5Sclose(file_space);
|
||||
}
|
||||
H5Dclose(set);
|
||||
H5Sclose(space);
|
||||
#else
|
||||
std::cout << "HDF5Restart: compiled without HDF5 support, no data written" << std::endl;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
bool HDF5Restart::writeData(const TimeStep& tp,
|
||||
const SerializeData& data)
|
||||
{
|
||||
int level = tp.step / m_stride;
|
||||
|
||||
#ifdef HAS_HDF5
|
||||
int flag = H5F_ACC_RDWR;
|
||||
struct stat buffer;
|
||||
if (stat(m_hdf5_name.c_str(),&buffer) != 0)
|
||||
flag = H5F_ACC_TRUNC;
|
||||
|
||||
if (!this->openFile(flag))
|
||||
return false;
|
||||
|
||||
std::stringstream str;
|
||||
str << '/' << level;
|
||||
if (!checkGroupExistence(m_file,str.str().c_str()))
|
||||
H5Gclose(H5Gcreate2(m_file,str.str().c_str(),0,H5P_DEFAULT,H5P_DEFAULT));
|
||||
|
||||
int pid = 0;
|
||||
#ifdef HAVE_MPI
|
||||
pid = m_adm.getProcId();
|
||||
int ptot = m_adm.getNoProcs();
|
||||
#else
|
||||
int ptot = 1;
|
||||
#endif
|
||||
for (int p = 0; p < ptot; p++)
|
||||
for (const std::pair<std::string,std::string>& it : data) {
|
||||
std::stringstream str;
|
||||
str << level << '/' << p;
|
||||
hid_t group;
|
||||
if (checkGroupExistence(m_file,str.str().c_str()))
|
||||
group = H5Gopen2(m_file,str.str().c_str(),H5P_DEFAULT);
|
||||
else
|
||||
group = H5Gcreate2(m_file,str.str().c_str(),0,H5P_DEFAULT,H5P_DEFAULT);
|
||||
if (!H5Lexists(group, it.first.c_str(), 0)) {
|
||||
int len = pid == p ? it.second.size() : 0;
|
||||
writeArray(group, it.first, len, it.second.data(), H5T_NATIVE_CHAR);
|
||||
}
|
||||
H5Gclose(group);
|
||||
}
|
||||
closeFile();
|
||||
#else
|
||||
std::cout << "HDF5Restart: compiled without HDF5 support, no data written" << std::endl;
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
//! \brief Convenience type for restart IO.
|
||||
typedef std::pair<HDF5Restart*,HDF5Restart::SerializeData*> read_restart_ctx;
|
||||
|
||||
|
||||
#ifdef HAS_HDF5
|
||||
herr_t HDF5Restart::read_restart_data(hid_t group_id, const char* member_name, void* data)
|
||||
{
|
||||
read_restart_ctx* ctx = static_cast<read_restart_ctx*>(data);
|
||||
|
||||
char* c;
|
||||
int len;
|
||||
ctx->first->readArray(group_id,member_name,len,c);
|
||||
ctx->second->insert(std::make_pair(std::string(member_name),std::string(c,len)));
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
int HDF5Restart::readData(SerializeData& data, int level)
|
||||
{
|
||||
#ifdef HAS_HDF5
|
||||
if (!openFile(H5F_ACC_RDONLY))
|
||||
return -1;
|
||||
|
||||
if (level == -1) {
|
||||
while (true) {
|
||||
std::stringstream str;
|
||||
str << '/' << level+1;
|
||||
if (!checkGroupExistence(m_file, str.str().c_str()))
|
||||
break;
|
||||
++level;
|
||||
}
|
||||
}
|
||||
|
||||
std::stringstream str;
|
||||
str << '/' << level << '/';
|
||||
#ifdef HAVE_MPI
|
||||
str << m_adm.getProcId();
|
||||
#else
|
||||
str << 0;
|
||||
#endif
|
||||
int idx = 0;
|
||||
read_restart_ctx ctx(this,&data);
|
||||
int it = H5Giterate(m_file, str.str().c_str(), &idx, read_restart_data, &ctx);
|
||||
return it < 0 ? it : level;
|
||||
#else
|
||||
std::cout << "HDF5Writer: compiled without HDF5 support, no data read" << std::endl;
|
||||
return -1;
|
||||
#endif
|
||||
}
|
85
src/Utility/HDF5Restart.h
Normal file
85
src/Utility/HDF5Restart.h
Normal file
@ -0,0 +1,85 @@
|
||||
// $Id$
|
||||
//==============================================================================
|
||||
//!
|
||||
//! \file HDF5Restart.h
|
||||
//!
|
||||
//! \date Nov 1 2018
|
||||
//!
|
||||
//! \author Arne Morten Kvarving / SINTEF
|
||||
//!
|
||||
//! \brief Output of restart data to HDF5.
|
||||
//!
|
||||
//==============================================================================
|
||||
|
||||
#ifndef _HDF5_RESTART_H
|
||||
#define _HDF5_RESTART_H
|
||||
|
||||
#include "HDF5Base.h"
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
|
||||
|
||||
class ProcessAdm;
|
||||
class TimeStep;
|
||||
|
||||
|
||||
/*!
|
||||
\brief Write and read restart data using a HDF5 file.
|
||||
|
||||
\details The HDF5 restart hanlder writes and reads data using a HDF5 file.
|
||||
It supports parallel I/O, and can be used to add restart capability
|
||||
to applications.
|
||||
*/
|
||||
|
||||
class HDF5Restart : public HDF5Base
|
||||
{
|
||||
public:
|
||||
typedef std::map<std::string, std::string> SerializeData; //!< Convenience typedef
|
||||
|
||||
//! \brief The constructor opens a named HDF5-file.
|
||||
//! \param[in] name The name (without extension) of the data file
|
||||
//! \param[in] adm The process administrator
|
||||
//! \param[in] stride Restart data output stride
|
||||
HDF5Restart(const std::string& name, const ProcessAdm& adm, int stride);
|
||||
|
||||
//! \brief Returns whether or not restart data should be output.
|
||||
//! \param tp Time stepping parameter
|
||||
bool dumpStep(const TimeStep& tp);
|
||||
|
||||
//! \brief Writes restart data to file.
|
||||
//! \param[in] tp Time stepping information
|
||||
//! \param[in] data Data to write
|
||||
bool writeData(const TimeStep& tp, const SerializeData& data);
|
||||
|
||||
//! \brief Reads restart data from file.
|
||||
//! \param[out] data The map to store data in
|
||||
//! \param[in] level Level to read (-1 to read last level in file)
|
||||
//! \returns Negative value on error, else restart level loaded
|
||||
int readData(SerializeData& data, int level = -1);
|
||||
|
||||
protected:
|
||||
//! \brief Internal helper function reading into an array of chars.
|
||||
//! \param[in] group The HDF5 dataset to read data from
|
||||
//! \param[in] name The name of the array
|
||||
//! \param[out] len The length of the data read
|
||||
//! \param[out] data The array to read data into
|
||||
void readArray(hid_t group, const std::string& name, int& len, char*& data);
|
||||
|
||||
//! \brief Internal helper function writing a data array to file.
|
||||
//! \param[in] group The HDF5 group to write data into
|
||||
//! \param[in] name The name of the array
|
||||
//! \param[in] len The length of the array
|
||||
//! \param[in] data The array to write
|
||||
//! \param[in] type The HDF5 type for the data (see H5T)
|
||||
void writeArray(hid_t group, const std::string& name,
|
||||
int len, const void* data, hid_t type);
|
||||
|
||||
//! \brief Static helper used for reading data.
|
||||
static herr_t read_restart_data(hid_t group_id, const char* member_name, void* data);
|
||||
|
||||
private:
|
||||
int m_stride; //!< Stride between outputs
|
||||
};
|
||||
|
||||
#endif
|
@ -36,27 +36,16 @@
|
||||
|
||||
|
||||
HDF5Writer::HDF5Writer (const std::string& name, const ProcessAdm& adm,
|
||||
bool append, bool keepOpen)
|
||||
: DataWriter(name,adm,".hdf5"), m_file(-1), m_restart_file(-1),
|
||||
m_keepOpen(keepOpen)
|
||||
#ifdef HAVE_MPI
|
||||
, m_adm(adm)
|
||||
#endif
|
||||
bool append)
|
||||
: DataWriter(name,adm,".hdf5"), HDF5Base(name+".hdf5", adm)
|
||||
{
|
||||
#ifdef HAS_HDF5
|
||||
struct stat temp;
|
||||
// file already exists - open and find the next group
|
||||
if (append && keepOpen)
|
||||
m_flag = H5F_ACC_RDONLY;
|
||||
else if (append && stat(m_name.c_str(),&temp) == 0)
|
||||
if (append && stat(m_name.c_str(),&temp) == 0)
|
||||
m_flag = H5F_ACC_RDWR;
|
||||
else
|
||||
m_flag = H5F_ACC_TRUNC;
|
||||
m_restart_name = name + "_restart.hdf5";
|
||||
if (stat(m_restart_name.c_str(),&temp) == 0)
|
||||
m_restart_flag = H5F_ACC_RDWR;
|
||||
else
|
||||
m_restart_flag = H5F_ACC_TRUNC;
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -95,33 +84,19 @@ int HDF5Writer::getLastTimeLevel ()
|
||||
}
|
||||
|
||||
|
||||
void HDF5Writer::openFile(int level, bool restart)
|
||||
void HDF5Writer::openFile(int level)
|
||||
{
|
||||
if ((m_file != -1 && !restart) || (m_restart_file != -1 && restart))
|
||||
if (m_file != -1)
|
||||
return;
|
||||
|
||||
#ifdef HAS_HDF5
|
||||
hid_t file;
|
||||
#ifdef HAVE_MPI
|
||||
MPI_Info info = MPI_INFO_NULL;
|
||||
hid_t acc_tpl = H5Pcreate(H5P_FILE_ACCESS);
|
||||
H5Pset_fapl_mpio(acc_tpl, *m_adm.getCommunicator(), info);
|
||||
#else
|
||||
hid_t acc_tpl = H5P_DEFAULT;
|
||||
#endif
|
||||
unsigned int flag = restart ? m_restart_flag : m_flag;
|
||||
std::string fname = restart ? m_restart_name : m_name;
|
||||
if (flag == H5F_ACC_RDWR) {
|
||||
if (m_flag == H5F_ACC_RDWR) {
|
||||
struct stat buffer;
|
||||
if (stat(fname.c_str(),&buffer) != 0)
|
||||
flag = H5F_ACC_TRUNC;
|
||||
if (stat(m_name.c_str(),&buffer) != 0)
|
||||
m_flag = H5F_ACC_TRUNC;
|
||||
}
|
||||
|
||||
if (flag == H5F_ACC_TRUNC)
|
||||
file = H5Fcreate(fname.c_str(),flag,H5P_DEFAULT,acc_tpl);
|
||||
else {
|
||||
// check free disk space - to protect against corrupting files
|
||||
// due to out of space condition
|
||||
if (flag == H5F_ACC_RDWR) {
|
||||
if (m_flag == H5F_ACC_RDWR) {
|
||||
#ifdef HAVE_GET_CURRENT_DIR_NAME
|
||||
char* cwd = get_current_dir_name();
|
||||
struct statvfs vfs;
|
||||
@ -132,34 +107,21 @@ void HDF5Writer::openFile(int level, bool restart)
|
||||
}
|
||||
free(cwd);
|
||||
#endif
|
||||
}
|
||||
file = H5Fopen(fname.c_str(),flag,acc_tpl);
|
||||
}
|
||||
if (file < 0)
|
||||
{
|
||||
std::cerr <<" *** HDF5Writer: Failed to open "<< m_name << std::endl;
|
||||
|
||||
if (!HDF5Base::openFile(m_flag))
|
||||
return;
|
||||
}
|
||||
|
||||
std::stringstream str;
|
||||
str << '/' << level;
|
||||
if (!checkGroupExistence(file,str.str().c_str()))
|
||||
H5Gclose(H5Gcreate2(file,str.str().c_str(),0,H5P_DEFAULT,H5P_DEFAULT));
|
||||
#ifdef HAVE_MPI
|
||||
H5Pclose(acc_tpl);
|
||||
#endif
|
||||
if (restart)
|
||||
m_restart_file = file;
|
||||
else
|
||||
m_file = file;
|
||||
if (!checkGroupExistence(m_file,str.str().c_str()))
|
||||
H5Gclose(H5Gcreate2(m_file,str.str().c_str(),0,H5P_DEFAULT,H5P_DEFAULT));
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void HDF5Writer::closeFile(int level, bool force)
|
||||
void HDF5Writer::closeFile(int level)
|
||||
{
|
||||
if (m_keepOpen && !force)
|
||||
return;
|
||||
#ifdef HAS_HDF5
|
||||
if (m_file) {
|
||||
H5Fflush(m_file,H5F_SCOPE_GLOBAL);
|
||||
@ -171,82 +133,6 @@ void HDF5Writer::closeFile(int level, bool force)
|
||||
}
|
||||
|
||||
|
||||
void HDF5Writer::readArray(hid_t group, const std::string& name,
|
||||
int& len, double*& data)
|
||||
{
|
||||
#ifdef HAS_HDF5
|
||||
if (!checkGroupExistence(group, name.c_str())) {
|
||||
len = 0;
|
||||
return;
|
||||
}
|
||||
hid_t set = H5Dopen2(group,name.c_str(),H5P_DEFAULT);
|
||||
hsize_t siz = H5Dget_storage_size(set) / 8;
|
||||
len = siz;
|
||||
data = new double[siz];
|
||||
H5Dread(set,H5T_NATIVE_DOUBLE,H5S_ALL,H5S_ALL,H5P_DEFAULT,data);
|
||||
H5Dclose(set);
|
||||
#else
|
||||
len = 0;
|
||||
std::cout << "HDF5Writer: compiled without HDF5 support, no data read" << std::endl;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void HDF5Writer::readArray(hid_t group, const std::string& name,
|
||||
int& len, int*& data)
|
||||
{
|
||||
#ifdef HAS_HDF5
|
||||
hid_t set = H5Dopen2(group,name.c_str(),H5P_DEFAULT);
|
||||
hsize_t siz = H5Dget_storage_size(set) / sizeof(int);
|
||||
len = siz;
|
||||
data = new int[siz];
|
||||
H5Dread(set,H5T_NATIVE_INT,H5S_ALL,H5S_ALL,H5P_DEFAULT,data);
|
||||
H5Dclose(set);
|
||||
#else
|
||||
len = 0;
|
||||
std::cout << "HDF5Writer: compiled without HDF5 support, no data read" << std::endl;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void HDF5Writer::readArray(hid_t group, const std::string& name,
|
||||
int& len, char*& data)
|
||||
{
|
||||
#ifdef HAS_HDF5
|
||||
hid_t set = H5Dopen2(group,name.c_str(),H5P_DEFAULT);
|
||||
hsize_t siz = H5Dget_storage_size(set);
|
||||
len = siz;
|
||||
data = new char[siz];
|
||||
H5Dread(set,H5T_NATIVE_CHAR,H5S_ALL,H5S_ALL,H5P_DEFAULT,data);
|
||||
H5Dclose(set);
|
||||
#else
|
||||
len = 0;
|
||||
std::cout << "HDF5Writer: compiled without HDF5 support, no data read" << std::endl;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void HDF5Writer::readString(const std::string& name, std::string& out, bool close)
|
||||
{
|
||||
#ifdef HAS_HDF5
|
||||
openFile(0);
|
||||
hid_t set = H5Dopen2(m_file,name.c_str(),H5P_DEFAULT);
|
||||
hid_t space = H5Dget_space(set);
|
||||
hsize_t siz = H5Sget_simple_extent_npoints(space);
|
||||
char* temp = new char[siz];
|
||||
out.resize(siz);
|
||||
H5Dread(set,H5T_NATIVE_CHAR,H5S_ALL,H5S_ALL,H5P_DEFAULT,temp);
|
||||
out.assign(temp, siz);
|
||||
delete[] temp;
|
||||
H5Dclose(set);
|
||||
if (close)
|
||||
closeFile(0);
|
||||
#else
|
||||
std::cout << "HDF5Writer: compiled without HDF5 support, no data read" << std::endl;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void HDF5Writer::writeArray(hid_t group, const std::string& name, int patch,
|
||||
int len, const void* data, hid_t type)
|
||||
{
|
||||
@ -298,13 +184,6 @@ void HDF5Writer::writeArray(hid_t group, const std::string& name, int patch,
|
||||
}
|
||||
|
||||
|
||||
bool HDF5Writer::readVector(int level, const DataEntry& entry)
|
||||
{
|
||||
// readArray(level,entry.first,entry.second.size,entry.second.data);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void HDF5Writer::writeVector(int level, const DataEntry& entry)
|
||||
{
|
||||
if (!entry.second.enabled)
|
||||
@ -334,29 +213,6 @@ void HDF5Writer::writeVector(int level, const DataEntry& entry)
|
||||
}
|
||||
|
||||
|
||||
bool HDF5Writer::readVector(int level, const std::string& name,
|
||||
int patch, std::vector<double>& vec)
|
||||
{
|
||||
bool ok=true;
|
||||
openFile(level);
|
||||
vec.clear();
|
||||
#ifdef HAS_HDF5
|
||||
std::stringstream str;
|
||||
str << level << "/" << name;
|
||||
hid_t group2 = H5Gopen2(m_file,str.str().c_str(),H5P_DEFAULT);
|
||||
double* tmp = nullptr; int siz = 0;
|
||||
std::stringstream str2;
|
||||
str2 << patch;
|
||||
readArray(group2,str2.str().c_str(),siz,tmp);
|
||||
vec.insert(vec.begin(),tmp,tmp+siz);
|
||||
delete[] tmp;
|
||||
H5Gclose(group2);
|
||||
#endif
|
||||
closeFile(level);
|
||||
return ok;
|
||||
}
|
||||
|
||||
|
||||
void HDF5Writer::writeBasis (int level, const DataEntry& entry,
|
||||
const std::string& prefix)
|
||||
{
|
||||
@ -702,23 +558,6 @@ void HDF5Writer::writeBasis (const SIMbase* sim, const std::string& name,
|
||||
}
|
||||
|
||||
|
||||
bool HDF5Writer::checkGroupExistence(hid_t parent, const char* path)
|
||||
{
|
||||
bool result = false;
|
||||
#ifdef HAS_HDF5
|
||||
// turn off errors to avoid cout spew
|
||||
H5E_BEGIN_TRY {
|
||||
#if H5_VERS_MINOR > 8
|
||||
result = H5Lexists(parent, path, H5P_DEFAULT) == 1;
|
||||
#else
|
||||
result = H5Gget_objinfo((hid_t)parent,path,0,nullptr) == 0;
|
||||
#endif
|
||||
} H5E_END_TRY;
|
||||
#endif
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
// TODO: implement for variable time steps.
|
||||
// (named time series to allow different timelevels for different fields)
|
||||
bool HDF5Writer::writeTimeInfo (int level, int interval, const TimeStep& tp)
|
||||
@ -788,174 +627,3 @@ void HDF5Writer::writeNodalForces(int level, const DataEntry& entry)
|
||||
std::cout << "HDF5Writer: compiled without HDF5 support, no data written" << std::endl;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
bool HDF5Writer::hasGeometries(int level, const std::string& basisName)
|
||||
{
|
||||
std::stringstream str;
|
||||
str << level << "/" << basisName << "/basis";
|
||||
|
||||
bool notOpen = m_file == -1;
|
||||
if (notOpen) this->openFile(level);
|
||||
bool result = this->checkGroupExistence(m_file,str.str().c_str());
|
||||
if (notOpen) this->closeFile(level);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
bool HDF5Writer::readDouble(int level, const std::string& group,
|
||||
const std::string& name, double& data)
|
||||
{
|
||||
#ifdef HAS_HDF5
|
||||
std::stringstream str;
|
||||
str << "/" << level << "/" << group;
|
||||
if (!checkGroupExistence(m_file,str.str().c_str()))
|
||||
return false;
|
||||
|
||||
hid_t group2 = H5Gopen2(m_file,str.str().c_str(),H5P_DEFAULT);
|
||||
double* data2; int len=1;
|
||||
readArray(group2,name,len,data2);
|
||||
H5Gclose(group2);
|
||||
if (len > 0) {
|
||||
data = data2[0];
|
||||
delete[] data2;
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool HDF5Writer::readVector(int level, const std::string& name,
|
||||
int patch, std::vector<int>& vec)
|
||||
{
|
||||
bool ok=true;
|
||||
openFile(level);
|
||||
#ifdef HAS_HDF5
|
||||
std::stringstream str;
|
||||
str << level << "/" << name;
|
||||
hid_t group2 = H5Gopen2(m_file,str.str().c_str(),H5P_DEFAULT);
|
||||
int* tmp = nullptr; int siz = 0;
|
||||
std::stringstream str2;
|
||||
str2 << patch;
|
||||
readArray(group2,str2.str().c_str(),siz,tmp);
|
||||
vec.assign(tmp, tmp + siz);
|
||||
delete[] tmp;
|
||||
H5Gclose(group2);
|
||||
#endif
|
||||
closeFile(level);
|
||||
return ok;
|
||||
}
|
||||
|
||||
|
||||
bool HDF5Writer::writeRestartData(int level, const DataExporter::SerializeData& data)
|
||||
{
|
||||
#ifdef HAS_HDF5
|
||||
if (level > 0)
|
||||
m_restart_flag = H5F_ACC_RDWR;
|
||||
openFile(level, true);
|
||||
int pid = 0;
|
||||
#ifdef HAVE_MPI
|
||||
pid = m_adm.getProcId();
|
||||
int ptot = m_adm.getNoProcs();
|
||||
#else
|
||||
int ptot = 1;
|
||||
#endif
|
||||
for (int p = 0; p < ptot; p++)
|
||||
for (const std::pair<std::string,std::string>& it : data) {
|
||||
std::stringstream str;
|
||||
str << level << '/' << p;
|
||||
hid_t group;
|
||||
if (checkGroupExistence(m_restart_file,str.str().c_str()))
|
||||
group = H5Gopen2(m_restart_file,str.str().c_str(),H5P_DEFAULT);
|
||||
else
|
||||
group = H5Gcreate2(m_restart_file,str.str().c_str(),0,H5P_DEFAULT,H5P_DEFAULT);
|
||||
if (!H5Lexists(group, it.first.c_str(), 0)) {
|
||||
int len = pid == p ? it.second.size() : 0;
|
||||
writeArray(group, it.first, -1, len, it.second.data(), H5T_NATIVE_CHAR);
|
||||
}
|
||||
H5Gclose(group);
|
||||
}
|
||||
|
||||
H5Fclose(m_restart_file);
|
||||
m_restart_file = -1;
|
||||
#else
|
||||
std::cout << "HDF5Writer: compiled without HDF5 support, no data written" << std::endl;
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
//! \brief Convenience type for restart IO.
|
||||
typedef std::pair<HDF5Writer*,DataExporter::SerializeData*> read_restart_ctx;
|
||||
|
||||
|
||||
#ifdef HAS_HDF5
|
||||
static herr_t read_restart_data(hid_t group_id, const char* member_name, void* data)
|
||||
{
|
||||
read_restart_ctx* ctx = static_cast<read_restart_ctx*>(data);
|
||||
|
||||
char* c;
|
||||
int len;
|
||||
ctx->first->readArray(group_id,member_name,len,c);
|
||||
ctx->second->insert(std::make_pair(std::string(member_name),std::string(c,len)));
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
int HDF5Writer::readRestartData(DataExporter::SerializeData& data, int level)
|
||||
{
|
||||
#ifdef HAS_HDF5
|
||||
openFile(0);
|
||||
|
||||
if (level == -1) {
|
||||
while (true) {
|
||||
std::stringstream str;
|
||||
str << '/' << level+1;
|
||||
if (!checkGroupExistence(m_file, str.str().c_str()))
|
||||
break;
|
||||
++level;
|
||||
}
|
||||
}
|
||||
|
||||
std::stringstream str;
|
||||
str << '/' << level << '/';
|
||||
#ifdef HAVE_MPI
|
||||
str << m_adm.getProcId();
|
||||
#else
|
||||
str << 0;
|
||||
#endif
|
||||
int idx = 0;
|
||||
read_restart_ctx ctx(this,&data);
|
||||
int it = H5Giterate(m_file, str.str().c_str(), &idx, read_restart_data, &ctx);
|
||||
closeFile(0);
|
||||
return it < 0 ? it : level;
|
||||
#else
|
||||
std::cout << "HDF5Writer: compiled without HDF5 support, no data read" << std::endl;
|
||||
return -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
int HDF5Writer::getFieldSize(int level, const std::string& basisName,
|
||||
const std::string& fieldName)
|
||||
{
|
||||
openFile(level);
|
||||
std::stringstream str;
|
||||
str << level << "/" << basisName;
|
||||
if (!fieldName.empty())
|
||||
str << "/fields/" << fieldName;
|
||||
int patches = 0;
|
||||
while (true) {
|
||||
++patches;
|
||||
std::stringstream str2;
|
||||
str2 << str.str() << "/" << patches;
|
||||
if (!checkGroupExistence(m_file, str2.str().c_str()))
|
||||
break;
|
||||
}
|
||||
|
||||
return patches-1;
|
||||
}
|
||||
|
@ -15,9 +15,7 @@
|
||||
#define _HDF5_WRITER_H
|
||||
|
||||
#include "DataExporter.h"
|
||||
#ifdef HAS_HDF5
|
||||
#include <hdf5.h>
|
||||
#endif
|
||||
#include "HDF5Base.h"
|
||||
|
||||
class SIMbase;
|
||||
|
||||
@ -25,24 +23,18 @@ class SIMbase;
|
||||
/*!
|
||||
\brief Write data to a HDF5 file.
|
||||
|
||||
\details The HDF5 writer writes data to a HDF5 file.
|
||||
It supports parallel I/O, and can be used to add restart capability
|
||||
to applications.
|
||||
\details The HDF5 writer writes data to a HDF5 file. It supports parallel I/O.
|
||||
*/
|
||||
|
||||
class HDF5Writer : public DataWriter
|
||||
class HDF5Writer : public DataWriter, public HDF5Base
|
||||
{
|
||||
public:
|
||||
#ifndef HAS_HDF5
|
||||
using hid_t = int; //!< Type alias providing hid_t without the hdf5 library
|
||||
#endif
|
||||
//! \brief The constructor opens a named HDF5-file.
|
||||
//! \param[in] name The name (without extension) of the data file
|
||||
//! \param[in] adm The process administrator
|
||||
//! \param[in] append Whether to append to or overwrite an existing file
|
||||
//! \param[in] keepopen Whether to always keep the HDF5 open
|
||||
HDF5Writer(const std::string& name, const ProcessAdm& adm,
|
||||
bool append = false, bool keepopen = false);
|
||||
bool append = false);
|
||||
|
||||
//! \brief Empty destructor.
|
||||
virtual ~HDF5Writer() {}
|
||||
@ -52,28 +44,17 @@ public:
|
||||
|
||||
//! \brief Opens the file at a given time level.
|
||||
//! \param[in] level The requested time level
|
||||
virtual void openFile(int level) { this->openFile(level,false); }
|
||||
|
||||
//! \brief Opens the file at a given time level.
|
||||
//! \param[in] level The requested time level
|
||||
//! \param[in] restart If true, open restart file
|
||||
void openFile(int level, bool restart);
|
||||
virtual void openFile(int level);
|
||||
|
||||
//! \brief Closes the file.
|
||||
//! \param[in] level Level we just wrote to the file
|
||||
//! \param[in] force If \e true, close even if \a keepopen was \e true
|
||||
virtual void closeFile(int level, bool force = false);
|
||||
virtual void closeFile(int level);
|
||||
|
||||
//! \brief Writes a vector to file.
|
||||
//! \param[in] level The time level to write the vector at
|
||||
//! \param[in] entry The DataEntry describing the vector
|
||||
virtual void writeVector(int level, const DataEntry& entry);
|
||||
|
||||
//! \brief Reads a vector from file.
|
||||
//! \param[in] level The time level to read the vector at
|
||||
//! \param[in] entry The DataEntry describing the vector
|
||||
virtual bool readVector(int level, const DataEntry& entry);
|
||||
|
||||
//! \brief Writes data from a SIM to file.
|
||||
//! \param[in] level The time level to write the data at
|
||||
//! \param[in] entry The DataEntry describing the data to write
|
||||
@ -111,63 +92,6 @@ public:
|
||||
//! \param[in] tp The current time stepping info
|
||||
virtual bool writeTimeInfo(int level, int interval, const TimeStep& tp);
|
||||
|
||||
//! \brief Reads a text string.
|
||||
//! \param[in] name The name (path in HDF5 file) to the string
|
||||
//! \param[out] out The string to read data into
|
||||
//! \param[in] close If \e false, keep the HDF5-file open after reading
|
||||
void readString(const std::string& name, std::string& out, bool close = true);
|
||||
|
||||
//! \brief Reads a double vector.
|
||||
//! \param[in] level The time level to read at
|
||||
//! \param[in] name The name (path in HDF5 file) to the string
|
||||
//! \param[in] patch The patch to read
|
||||
//! \param[out] vec The vector to read data into
|
||||
bool readVector(int level, const std::string& name,
|
||||
int patch, std::vector<double>& vec);
|
||||
|
||||
//! \brief Reads an integer vector.
|
||||
//! \param[in] level The time level to read at
|
||||
//! \param[in] name The name (path in HDF5 file) to the string
|
||||
//! \param[in] patch The patch to read
|
||||
//! \param[out] vec The vector to read data into
|
||||
bool readVector(int level, const std::string& name,
|
||||
int patch, std::vector<int>& vec);
|
||||
|
||||
//! \brief Reads a double value.
|
||||
//! \param[in] level The time level to read at
|
||||
//! \param[in] name The name (path in HDF5 file) to the array
|
||||
//! \param[in] group The HDF5 group to read from
|
||||
//! \param[out] data The variable to read data into
|
||||
bool readDouble(int level, const std::string& group,
|
||||
const std::string& name, double& data);
|
||||
|
||||
//! \brief Checks if updated geometries exist in file at given time level.
|
||||
//! \param[in] level The time level to check
|
||||
//! \param[in] basisName Check for a particular basis
|
||||
bool hasGeometries(int level, const std::string& basisName = "");
|
||||
|
||||
//! \brief Writes restart data to file.
|
||||
//! \param[in] level Level to write data at
|
||||
//! \param[in] data Data to write
|
||||
bool writeRestartData(int level, const DataExporter::SerializeData& data);
|
||||
|
||||
//! \brief Reads restart data from file.
|
||||
//! \param[out] data The map to store data in
|
||||
//! \param[in] level Level to read (-1 to read last level in file)
|
||||
//! \returns Negative value on error, else restart level loaded
|
||||
int readRestartData(DataExporter::SerializeData& data, int level = -1);
|
||||
|
||||
//! \brief Internal helper function reading into an array of chars.
|
||||
//! \param[in] group The HDF5 group to read data from
|
||||
//! \param[in] name The name of the array
|
||||
//! \param[out] len The length of the data read
|
||||
//! \param[out] data The array to read data into
|
||||
void readArray(hid_t group, const std::string& name, int& len, char*& data);
|
||||
|
||||
//! \brief Returns number of patches for a field.
|
||||
int getFieldSize(int level, const std::string& basisName,
|
||||
const std::string& fieldName);
|
||||
|
||||
protected:
|
||||
//! \brief Internal helper function writing a data array to file.
|
||||
//! \param[in] group The HDF5 group to write data into
|
||||
@ -188,37 +112,9 @@ protected:
|
||||
void writeBasis(const SIMbase* SIM, const std::string& name,
|
||||
int basis, int level, bool redundant = false);
|
||||
|
||||
//! \brief Internal helper function reading into an array of doubles.
|
||||
//! \param[in] group The HDF5 group to read data from
|
||||
//! \param[in] name The name of the array
|
||||
//! \param[out] len The length of the data read
|
||||
//! \param[out] data The array to read data into
|
||||
void readArray(hid_t group, const std::string& name, int& len, double*& data);
|
||||
|
||||
//! \brief Internal helper function reading into an array of integers.
|
||||
//! \param[in] group The HDF5 group to read data from
|
||||
//! \param[in] name The name of the array
|
||||
//! \param[out] len The length of the data read
|
||||
//! \param[out] data The array to read data into
|
||||
void readArray(hid_t group, const std::string& name, int& len, int*& data);
|
||||
|
||||
//! \brief Internal helper function checking if a group exists in the file.
|
||||
//! \param[in] parent The HDF5 group of the parent
|
||||
//! \param[in] group The name of the group to check for
|
||||
//! \return \e true if group exists, otherwise \e false
|
||||
bool checkGroupExistence(hid_t parent, const char* group);
|
||||
|
||||
private:
|
||||
hid_t m_file; //!< The HDF5 handle for our file
|
||||
hid_t m_restart_file; //!< The HDF5 handle for our restart file
|
||||
#ifdef HAS_HDF5
|
||||
unsigned int m_flag; //!< The file flags to open HDF5 file with
|
||||
unsigned int m_restart_flag; //!< The file flags to open the restart file with
|
||||
#endif
|
||||
bool m_keepOpen; //!< If \e true, we always keep the file open
|
||||
std::string m_restart_name; //!< The restart file to use
|
||||
#ifdef HAVE_MPI
|
||||
const ProcessAdm& m_adm; //!< Pointer to process adm in use
|
||||
#endif
|
||||
};
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user