Commit 048eabaf authored by Kenneth Leiter's avatar Kenneth Leiter

ENH: Split heavy data writing from XdmfWriter into XdmfHDF5Writer. This paves...

ENH: Split heavy data writing from XdmfWriter into XdmfHDF5Writer.  This paves the way for the possiblity of having multiple
heavy data and light data writers.  Modify New() macro to accept parameters.
parent 0532b592
......@@ -42,6 +42,7 @@ set(XdmfSources
XdmfGeometry
XdmfGeometryType
XdmfGrid
XdmfHDF5Writer
XdmfItem
XdmfItemProperty
XdmfObject
......
......@@ -14,7 +14,9 @@ swig -v -c++ -python -o XdmfPython.cpp Xdmf.i
#include <XdmfGeometry.hpp>
#include <XdmfGeometryType.hpp>
#include <XdmfGrid.hpp>
#include <XdmfHDF5Writer.hpp>
#include <XdmfItem.hpp>
#include <XdmfItemProperty.hpp>
#include <XdmfObject.hpp>
#include <XdmfTopology.hpp>
#include <XdmfTopologyType.hpp>
......@@ -51,6 +53,7 @@ namespace boost {
%template(XdmfDomainPtr) boost::shared_ptr<XdmfDomain>;
%template(XdmfGeometryPtr) boost::shared_ptr<XdmfGeometry>;
%template(XdmfGridPtr) boost::shared_ptr<XdmfGrid>;
%template(XdmfHDF5WriterPtr) boost::shared_ptr<XdmfHDF5Writer>;
%template(XdmfItemPtr) boost::shared_ptr<XdmfItem>;
%template(XdmfObjPtr) boost::shared_ptr<XdmfObject>;
%template(XdmfTopologyPtr) boost::shared_ptr<XdmfTopology>;
......@@ -94,6 +97,7 @@ SWIG_SHARED_PTR_DERIVED(XdmfWriter, XdmfObject);
%include XdmfObject.hpp
%include XdmfItem.hpp
%include XdmfItemProperty.hpp
%include XdmfVisitor.hpp
%include XdmfWriter.hpp
......
// Kenneth Leiter
// Xdmf Smart Pointer Test
#include <sstream>
#include "XdmfArray.hpp"
#include "XdmfItem.hpp"
#include "XdmfHDF5Writer.hpp"
XdmfHDF5Writer::XdmfHDF5Writer() :
mHeavyFileName("output.h5"),
mHDF5Handle(H5Fcreate("output.h5", H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT))
{
std::cout << "Created XdmfHDF5Writer " << this << std::endl;
}
XdmfHDF5Writer::~XdmfHDF5Writer()
{
herr_t status = H5Fclose(mHDF5Handle);
std::cout << "Deleted XdmfHDF5Writer " << this << std::endl;
}
std::string XdmfHDF5Writer::createHDF5Group(std::stringstream & groupPath, int index)
{
groupPath << "/" << mDataHierarchy[index];
hid_t handle = H5Gopen(mHDF5Handle, groupPath.str().c_str(), H5P_DEFAULT);
if(handle < 0)
{
// Open failed, create a new group
handle = H5Gcreate(mHDF5Handle, groupPath.str().c_str(), H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
}
H5Gclose(handle);
// + 2 because the last value in mDataHierarchy == dataset name
if(index + 2 < mDataHierarchy.size())
{
return createHDF5Group(groupPath, index + 1);
}
return groupPath.str().c_str();
}
std::string XdmfHDF5Writer::getHDF5GroupHandle()
{
if(mDataHierarchy.size() > 1)
{
// Save old error handler and turn off error handling for now
H5E_auto_t old_func;
void* old_client_data;
H5Eget_auto(0, &old_func, &old_client_data);
H5Eset_auto2(0, NULL, NULL);
std::stringstream emptyPath;
std::string handle = createHDF5Group(emptyPath);
// Restore previous error handler
H5Eset_auto2(0, old_func, old_client_data);
return handle;
}
return "";
}
void XdmfHDF5Writer::popDataHierarchy()
{
mDataHierarchy.pop_back();
}
void XdmfHDF5Writer::pushDataHierarchy(const XdmfItem & item)
{
const std::map<std::string, std::string> itemProperties = item.getItemProperties();
std::map<std::string, std::string>::const_iterator name = itemProperties.find("Name");
if(name == itemProperties.end())
{
mDataHierarchy.push_back(item.getItemTag());
}
else
{
mDataHierarchy.push_back(name->second);
}
}
std::string XdmfHDF5Writer::visit(XdmfArray & array, boost::shared_ptr<Loki::BaseVisitor> visitor)
{
herr_t status;
hsize_t size = array.getSize();
hid_t dataspace = H5Screate_simple(1, &size, NULL);
hid_t handle = mHDF5Handle;
std::string groupName = getHDF5GroupHandle();
if(groupName.compare("") != 0)
{
handle = H5Gopen(mHDF5Handle, groupName.c_str(), H5P_DEFAULT);
}
hid_t dataset = H5Dcreate(handle, mDataHierarchy.back().c_str(), array.getHDF5Type(), dataspace, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
status = H5Dwrite(dataset, array.getHDF5Type(), H5S_ALL, H5S_ALL, H5P_DEFAULT, array.getValuesPointer());
if(groupName.compare("") != 0)
{
H5Gclose(handle);
}
status = H5Dclose(dataset);
status = H5Sclose(dataspace);
std::stringstream dataSetName;
dataSetName << mHeavyFileName << ":" << groupName << "/" << mDataHierarchy.back();
return dataSetName.str();
}
void XdmfHDF5Writer::visit(XdmfItem & item, boost::shared_ptr<Loki::BaseVisitor> visitor)
{
this->pushDataHierarchy(item);
item.traverse(visitor);
this->popDataHierarchy();
}
#ifndef XDMFHDF5WRITER_HPP_
#define XDMFHDF5WRITER_HPP_
// Forward Declarations
class XdmfArray;
// Includes
#include <hdf5.h>
#include "XdmfVisitor.hpp"
/**
* @brief Traverse the Xdmf graph and write heavy data stored in XdmfArrays to HDF5 on disk.
*
* XdmfHDF5Writer traverses an Xdmf graph structure and writes data stored in XdmfArrays to HDF5.
* Writing begins by calling the accept() operation on any XdmfItem and supplying this writer
* as the parameter.
*/
class XdmfHDF5Writer : public XdmfVisitor,
public Loki::Visitor<XdmfArray, std::string> {
public:
XdmfNewMacro(XdmfHDF5Writer);
/**
* Pop a string from the data hierarchy. This should be called whenever an XdmfItem is finished
* traversal, including in light data writers that work in conjunction with this heavy data writer.
*/
void popDataHierarchy();
/**
* Push a string associated with this XdmfItem to the dataHierarchy. This should be called
* whenever an XdmfItem is traversed, including in light data writers that work in conjunction
* with this heavy data writer. The data hierarchy ensures that HDF5 datasets are created at
* correct locations in the hdf5 file. This string is either the item property "Name" or the
* item tag.
*
* @param item the XdmfItem being traversed.
*/
void pushDataHierarchy(const XdmfItem & item);
/**
* Write an XdmfArray to HDF5.
*
* @param array an XdmfArray to write to HDF5.
* @param visitor a smart pointer to this visitor --- aids in grid traversal.
*
* @return a string containing the path to the hdf5 dataset written.
*/
std::string visit(XdmfArray & array, boost::shared_ptr<Loki::BaseVisitor> visitor);
/**
* Traverse an XdmfItem structure in order to find XdmfArrays to write to HDF5.
*
* @param item an XdmfItem to traverse.
* @param visitor a smart pointer to this visitor --- aids in grid traversal.
*/
void visit(XdmfItem & item, boost::shared_ptr<Loki::BaseVisitor> visitor);
protected:
XdmfHDF5Writer();
virtual ~XdmfHDF5Writer();
private:
XdmfHDF5Writer(const XdmfHDF5Writer & hdf5Writer); // Not implemented.
void operator=(const XdmfHDF5Writer & hdf5Writer); // Not implemented.
/**
* Create a new HDF5 group if needed based on the dataHierarchy. This is a recursive function used by getHDF5GroupHandle to construct
* new hdf5 groups.
*
* @param groupPath the current place in the dataHierarchy being processed.
* @param index the index in the dataHierarchy being processed.
*
* @return a string containing the path to the created group.
*/
std::string createHDF5Group(std::stringstream & groupPath, int index = 0);
/**
* Get a handle to a hdf5 group to write into. Uses the dataHierarchy to construct an appropriate hdf5 group name
* at the current point in writing.
*
* @return a string containing the path to the created group.
*/
std::string getHDF5GroupHandle();
std::vector<std::string> mDataHierarchy;
hid_t mHDF5Handle;
std::string mHeavyFileName;
};
#endif /* XDMFWRITER_HPP_ */
......@@ -4,9 +4,9 @@
// Includes
#include <boost/shared_ptr.hpp>
#define XdmfNewMacro(type) \
#define XdmfNewMacro(type, ...) \
template <typename T> friend void boost::checked_delete(T * x); \
static boost::shared_ptr<type> New() \
static boost::shared_ptr<type> New(__VA_ARGS__) \
{ \
boost::shared_ptr<type> p(new type()); \
return p; \
......
......@@ -4,17 +4,17 @@
#include <sstream>
#include "XdmfArray.hpp"
#include "XdmfItem.hpp"
#include "XdmfHDF5Writer.hpp"
#include "XdmfWriter.hpp"
XdmfWriter::XdmfWriter() :
mHDF5Writer(XdmfHDF5Writer::New()),
mLightDataLimit(100),
mHeavyFileName("output.h5"),
mHDF5Handle(H5Fcreate("output.h5", H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT)),
mXMLDocument(xmlNewDoc((xmlChar*)"1.0")),
mXMLCurrentNode(xmlNewNode(NULL, (xmlChar*)"Xdmf"))
{
xmlDocSetRootElement(mXMLDocument, mXMLCurrentNode);
std::cout << "Created visitor " << this << std::endl;
std::cout << "Created XdmfWriter " << this << std::endl;
}
XdmfWriter::~XdmfWriter()
......@@ -22,49 +22,7 @@ XdmfWriter::~XdmfWriter()
xmlSaveFormatFile("output.xmf", mXMLDocument, 1);
xmlFreeDoc(mXMLDocument);
xmlCleanupParser();
herr_t status = H5Fclose(mHDF5Handle);
std::cout << "Deleted visitor " << this << std::endl;
}
std::string XdmfWriter::createHDF5Group(std::stringstream & groupPath, int index)
{
groupPath << "/" << mDataHierarchy[index];
hid_t handle = H5Gopen(mHDF5Handle, groupPath.str().c_str(), H5P_DEFAULT);
if(handle < 0)
{
// Open failed, create a new group
handle = H5Gcreate(mHDF5Handle, groupPath.str().c_str(), H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
}
H5Gclose(handle);
// + 2 because we ignore last value in mDataHierarchy (== dataset name)
if(index + 2 < mDataHierarchy.size())
{
return createHDF5Group(groupPath, index + 1);
}
return groupPath.str().c_str();
}
std::string XdmfWriter::getHDF5GroupHandle()
{
if(mDataHierarchy.size() > 1)
{
// Save old error handler and turn off error handling for now
H5E_auto_t old_func;
void* old_client_data;
H5Eget_auto(0, &old_func, &old_client_data);
H5Eset_auto2(0, NULL, NULL);
std::stringstream emptyPath;
std::string handle = createHDF5Group(emptyPath);
// Restore previous error handler
H5Eset_auto2(0, old_func, old_client_data);
return handle;
}
return "";
std::cout << "Deleted XdmfWriter " << this << std::endl;
}
unsigned int XdmfWriter::getLightDataLimit() const
......@@ -87,24 +45,7 @@ void XdmfWriter::visit(XdmfArray & array, boost::shared_ptr<Loki::BaseVisitor> v
std::stringstream xmlTextValues;
if(array.getSize() > mLightDataLimit)
{
herr_t status;
hsize_t size = array.getSize();
hid_t dataspace = H5Screate_simple(1, &size, NULL);
hid_t handle = mHDF5Handle;
std::string groupName = getHDF5GroupHandle();
if(groupName.compare("") != 0)
{
handle = H5Gopen(mHDF5Handle, groupName.c_str(), H5P_DEFAULT);
}
hid_t dataset = H5Dcreate(handle, mDataHierarchy.back().c_str(), array.getHDF5Type(), dataspace, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
xmlTextValues << mHeavyFileName << ":" << groupName << "/" << mDataHierarchy.back();
status = H5Dwrite(dataset, array.getHDF5Type(), H5S_ALL, H5S_ALL, H5P_DEFAULT, array.getValuesPointer());
if(groupName.compare("") != 0)
{
H5Gclose(handle);
}
status = H5Dclose(dataset);
status = H5Sclose(dataspace);
xmlTextValues << mHDF5Writer->visit(array, mHDF5Writer);
}
else
{
......@@ -120,22 +61,12 @@ void XdmfWriter::visit(XdmfItem & item, boost::shared_ptr<Loki::BaseVisitor> vis
xmlNodePtr parentNode = mXMLCurrentNode;
mXMLCurrentNode = xmlNewChild(mXMLCurrentNode, NULL, (xmlChar*)item.getItemTag().c_str(), NULL);
const std::map<std::string, std::string> itemProperties = item.getItemProperties();
bool pushedHDF5Name = false;
for(std::map<std::string, std::string>::const_iterator iter = itemProperties.begin(); iter != itemProperties.end(); ++iter)
{
if(iter->first.compare("Name") == 0)
{
mDataHierarchy.push_back(iter->second);
pushedHDF5Name = true;
}
xmlNewProp(mXMLCurrentNode, (xmlChar*)iter->first.c_str(), (xmlChar*)iter->second.c_str());
}
if(!pushedHDF5Name)
{
mDataHierarchy.push_back(item.getItemTag());
}
mHDF5Writer->pushDataHierarchy(item);
item.traverse(visitor);
mHDF5Writer->popDataHierarchy();
mXMLCurrentNode = parentNode;
mDataHierarchy.pop_back();
}
......@@ -3,19 +3,20 @@
// Forward Declarations
class XdmfArray;
class XdmfHDF5Writer;
// Includes
#include <hdf5.h>
#include <libxml/tree.h>
#include <vector>
#include "XdmfVisitor.hpp"
/**
* @brief Traverse the Xdmf graph and write data stored to disk.
* @brief Traverse the Xdmf graph and write light and heavy data stored to disk.
*
* XdmfWriter visits each node of an Xdmf graph structure and writes the data to disk. Writing begins by calling the
* accept() operation on any XdmfItem and supplying an XdmfWriter as the parameter.
* The XdmfItem as well as all children attached to the XdmfItem are written to disk.
* accept() operation on any XdmfItem and supplying this writer as the parameter. The XdmfItem as well as all children
* attached to the XdmfItem are written to disk. Heavy data is written to HDF5 format using the XdmfHDF5Writer and light
* data is written to XML.
*/
class XdmfWriter : public XdmfVisitor,
public Loki::Visitor<XdmfArray> {
......@@ -41,16 +42,16 @@ public:
/**
* Write an XdmfArray to disk
*
* @param array a pointer to an XdmfArray to write to disk.
* @param visitor a smart pointer to this XdmfVisitor --- aids in grid traversal.
* @param array an XdmfArray to write to disk.
* @param visitor a smart pointer to this visitor --- aids in grid traversal.
*/
void visit(XdmfArray & array, boost::shared_ptr<Loki::BaseVisitor> visitor);
/**
* Write an XdmfItem to disk
*
* @param item a pointer to an XdmfItem to write to disk.
* @param visitor a smart pointer to this XdmfVisitor --- aids in grid traversal.
* @param item an XdmfItem to write to disk.
* @param visitor a smart pointer to this visitor --- aids in grid traversal.
*/
void visit(XdmfItem & item, boost::shared_ptr<Loki::BaseVisitor> visitor);
......@@ -64,27 +65,7 @@ private:
XdmfWriter(const XdmfWriter & writer); // Not implemented.
void operator=(const XdmfWriter & writer); // Not implemented.
/**
* Create a new HDF5 group if needed based on the dataHierarchy. This is a recursive function used by getHDF5GroupHandle to construct
* new hdf5 groups.
*
* @param groupPath the current place in the dataHierarchy being processed.
* @param index the index in the dataHierarchy being processed.
*
* @return a string containing the path to the created group.
*/
std::string createHDF5Group(std::stringstream & groupPath, int index = 0);
/**
* Get a handle to a hdf5 group to write into. Uses the dataHierarchy to construct an appropriate hdf5 group name
* at the current point in writing.
*
* @return a string containing the path to the created group.
*/
std::string getHDF5GroupHandle();
std::vector<std::string> mDataHierarchy;
hid_t mHDF5Handle;
boost::shared_ptr<XdmfHDF5Writer> mHDF5Writer;
std::string mHeavyFileName;
unsigned int mLightDataLimit;
xmlDocPtr mXMLDocument;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment