XdmfHDF5Writer.cpp 5.58 KB
Newer Older
1 2 3
// Kenneth Leiter
// Xdmf Smart Pointer Test

4
#include <hdf5.h>
5 6
#include <sstream>
#include "XdmfArray.hpp"
7
#include "XdmfHDF5Controller.hpp"
8 9
#include "XdmfHDF5Writer.hpp"

10 11 12 13 14 15 16
/**
 * PIMPL
 */
class XdmfHDF5Writer::XdmfHDF5WriterImpl {

public:

17
	XdmfHDF5WriterImpl(const std::string & hdf5FilePath) :
18
		mHDF5FilePath(hdf5FilePath),
19 20 21
		mLastWrittenDataSet(""),
		mDataSetId(0),
		mMode(Default)
22 23 24 25 26
	{
	};
	~XdmfHDF5WriterImpl()
	{
	};
27
	int mDataSetId;
28
	std::string mHDF5FilePath;
29
	std::string mLastWrittenDataSet;
30
	Mode mMode;
31 32
};

33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97
class XdmfHDF5Writer::GetHDF5Type : public boost::static_visitor <hid_t> {
public:

	GetHDF5Type()
	{
	}

	hid_t getHDF5Type(const char * const) const
	{
		return H5T_NATIVE_CHAR;
	}

	hid_t getHDF5Type(const short * const) const
	{
		return H5T_NATIVE_SHORT;
	}

	hid_t getHDF5Type(const int * const) const
	{
		return H5T_NATIVE_INT;
	}

	hid_t getHDF5Type(const long * const) const
	{
		return H5T_NATIVE_LONG;
	}

	hid_t getHDF5Type(const float * const) const
	{
		return H5T_NATIVE_FLOAT;
	}

	hid_t getHDF5Type(const double * const) const
	{
		return H5T_NATIVE_DOUBLE;
	}

	hid_t getHDF5Type(const unsigned char * const) const
	{
		return H5T_NATIVE_UCHAR;
	}

	hid_t getHDF5Type(const unsigned short * const) const
	{
		return H5T_NATIVE_USHORT;
	}

	hid_t getHDF5Type(const unsigned int * const) const
	{
		return H5T_NATIVE_UINT;
	}

	template<typename T>
	hid_t operator()(const boost::shared_ptr<std::vector<T> > & array) const
	{
		return this->getHDF5Type(&(array.get()->operator[](0)));
	}

	template<typename T>
	hid_t operator()(const boost::shared_array<const T> & array) const
	{
		return this->getHDF5Type(array.get());
	}
};

98
XdmfHDF5Writer::XdmfHDF5Writer(const std::string & hdf5FilePath) :
99
	mImpl(new XdmfHDF5WriterImpl(hdf5FilePath))
100 101 102 103 104 105
{
	std::cout << "Created XdmfHDF5Writer " << this << std::endl;
}

XdmfHDF5Writer::~XdmfHDF5Writer()
{
106
	delete mImpl;
107 108 109
	std::cout << "Deleted XdmfHDF5Writer " << this << std::endl;
}

110 111 112 113 114
std::string XdmfHDF5Writer::getLastWrittenDataSet() const
{
	return mImpl->mLastWrittenDataSet;
}

115 116 117 118 119
void XdmfHDF5Writer::setMode(const Mode mode)
{
	mImpl->mMode = mode;
}

120
void XdmfHDF5Writer::visit(XdmfArray & array, const boost::shared_ptr<XdmfBaseVisitor> visitor)
121
{
122
	hid_t datatype = -1;
123 124
	mImpl->mLastWrittenDataSet = "";

125
	if(array.mHaveArray)
126
	{
127
		datatype = boost::apply_visitor(GetHDF5Type(), array.mArray);
128
	}
129
	else if(array.mHaveArrayPointer)
130
	{
131
		datatype = boost::apply_visitor(GetHDF5Type(), array.mArrayPointer);
132
	}
133 134 135 136
	else if(array.mHDF5Controller)
	{
		mImpl->mLastWrittenDataSet = array.mHDF5Controller->getDataSetPath();
	}
137

138 139
	if(datatype != -1)
	{
140
		std::string hdf5FilePath = mImpl->mHDF5FilePath;
141
		std::stringstream dataSetName;
142 143 144 145 146 147 148 149 150 151 152

		if((mImpl->mMode == Overwrite || mImpl->mMode == Append) && array.mHDF5Controller)
		{
			// Write to the previous dataset
			dataSetName << array.mHDF5Controller->getDataSetName();
			hdf5FilePath = array.mHDF5Controller->getHDF5FilePath();
		}
		else
		{
			dataSetName << "Data" << mImpl->mDataSetId;
		}
153 154

		// Open a hdf5 dataset and write to it on disk.
155 156
		herr_t status;
		hsize_t size = array.getSize();
157 158 159 160 161 162 163 164
		hid_t hdf5Handle;

		// 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);

165
		if(H5Fis_hdf5(hdf5FilePath.c_str()) > 0)
166
		{
167
			hdf5Handle = H5Fopen(hdf5FilePath.c_str(), H5F_ACC_RDWR, H5P_DEFAULT);
168 169 170
		}
		else
		{
171
			hdf5Handle = H5Fcreate(hdf5FilePath.c_str(), H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT);
172 173
		}
		hid_t dataset = H5Dopen(hdf5Handle, dataSetName.str().c_str(), H5P_DEFAULT);
174 175 176 177

		hid_t dataspace = H5S_ALL;
		hid_t memspace = H5S_ALL;

178 179
		if(dataset < 0)
		{
180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215
			hsize_t unlimited = H5S_UNLIMITED;
			memspace = H5Screate_simple(1, &size, &unlimited);
			hid_t property = H5Pcreate(H5P_DATASET_CREATE);
			hsize_t chunkSize = 1024;
			status = H5Pset_chunk(property, 1, &chunkSize);
			dataset = H5Dcreate(hdf5Handle, dataSetName.str().c_str(), datatype, memspace, H5P_DEFAULT, property, H5P_DEFAULT);
			status = H5Pclose(property);
		}
		else
		{
			// Need to resize dataset to fit new data
			if(mImpl->mMode == Append)
			{
				// Get size of old dataset
				dataspace = H5Dget_space(dataset);
				hssize_t datasize = H5Sget_simple_extent_npoints(dataspace);
				status = H5Sclose(dataspace);

				// Resize to fit size of old and new data.
				hsize_t newSize = size + datasize;
				status = H5Dset_extent(dataset, &newSize);

				// Select hyperslab to write to.
				memspace = H5Screate_simple(1, &size, NULL);
				dataspace = H5Dget_space(dataset);
				hsize_t start = datasize;
				status = H5Sselect_hyperslab(dataspace, H5S_SELECT_SET, &start, NULL, &size, NULL) ;
			}
			else
			{
				status = H5Dset_extent(dataset, &size);
			}
		}
		status = H5Dwrite(dataset, datatype, memspace, dataspace, H5P_DEFAULT, array.getValuesPointer());
		if(dataspace != H5S_ALL)
		{
216 217
			status = H5Sclose(dataspace);
		}
218 219 220 221
		if(memspace != H5S_ALL)
		{
			status = H5Sclose(memspace);
		}
222
		status = H5Dclose(dataset);
223
		status = H5Fclose(hdf5Handle);
224

225 226
		// Restore previous error handler
		H5Eset_auto2(0, old_func, old_client_data);
227

228
		std::stringstream writtenDataSet;
229
		writtenDataSet << hdf5FilePath << ":" << dataSetName.str();
230

231 232
		mImpl->mLastWrittenDataSet = writtenDataSet.str();

233 234 235 236
		// Attach a new controller to the array if needed.
		if(mImpl->mMode == Default || !array.mHDF5Controller)
		{
			boost::shared_ptr<XdmfHDF5Controller> newDataSetController = XdmfHDF5Controller::New(writtenDataSet.str(), array.getPrecision(),
237
				array.getSize(), array.getType());
238 239 240
			array.setHDF5Controller(newDataSetController);
			mImpl->mDataSetId++;
		}
241
	}
242
}