Commit c5929b52 authored by Kenneth Leiter's avatar Kenneth Leiter

ENH: Add string array type

Add tests for I/O of strings (to hdf5 and xml).
Fix bug in XdmfExodusReader when reading grid centered data.
Add string I/O in python and add tests.
parent 521435d9
......@@ -167,6 +167,12 @@ public:
return XdmfArrayType::UInt32();
}
shared_ptr<const XdmfArrayType>
getArrayType(const std::string * const) const
{
return XdmfArrayType::String();
}
shared_ptr<const XdmfArrayType>
operator()(const boost::blank & array) const
{
......@@ -685,6 +691,9 @@ XdmfArray::initialize(const shared_ptr<const XdmfArrayType> arrayType,
else if(arrayType == XdmfArrayType::UInt32()) {
this->initialize<unsigned int>(size);
}
else if(arrayType == XdmfArrayType::String()) {
this->initialize<std::string>(size);
}
else if(arrayType == XdmfArrayType::Uninitialized()) {
this->release();
}
......@@ -833,11 +842,21 @@ XdmfArray::populateItem(const std::map<std::string, std::string> & itemPropertie
unsigned int index = 0;
boost::char_separator<char> sep(" \t\n");
boost::tokenizer<boost::char_separator<char> > tokens(contentVal, sep);
for(boost::tokenizer<boost::char_separator<char> >::const_iterator
iter = tokens.begin();
iter != tokens.end();
++iter, ++index) {
this->insert(index, atof((*iter).c_str()));
if(arrayType == XdmfArrayType::String()) {
for(boost::tokenizer<boost::char_separator<char> >::const_iterator
iter = tokens.begin();
iter != tokens.end();
++iter, ++index) {
this->insert(index, *iter);
}
}
else {
for(boost::tokenizer<boost::char_separator<char> >::const_iterator
iter = tokens.begin();
iter != tokens.end();
++iter, ++index) {
this->insert(index, atof((*iter).c_str()));
}
}
}
else {
......
......@@ -89,6 +89,7 @@ class XdmfHeavyDataController;
* UInt8
* UInt16
* UInt32
* String
*/
class XDMFCORE_EXPORT XdmfArray : public XdmfItem {
......@@ -527,6 +528,7 @@ private:
shared_ptr<std::vector<unsigned char> >,
shared_ptr<std::vector<unsigned short> >,
shared_ptr<std::vector<unsigned int> >,
shared_ptr<std::vector<std::string> >,
boost::shared_array<const char>,
boost::shared_array<const short>,
boost::shared_array<const int>,
......
/*****************************************************************************/
/* XDMF */
/* eXtensible Data Model and Format */
/* Xdmf */
/* Extensible Data Model and Format */
/* */
/* Id : XdmfArray.tpp */
/* */
......@@ -23,6 +23,7 @@
#include <functional>
#include <numeric>
#include <sstream>
#include "XdmfArray.hpp"
template <typename T>
......@@ -40,6 +41,12 @@ public:
return 0;
}
T
operator()(const shared_ptr<std::vector<std::string> > & array) const
{
return (T)atof(array->operator[](mIndex).c_str());
}
template<typename U>
T
operator()(const shared_ptr<std::vector<U> > & array) const
......@@ -59,6 +66,57 @@ private:
const unsigned int mIndex;
};
template <>
class XdmfArray::GetValue<std::string> :
public boost::static_visitor<std::string> {
public:
GetValue(const unsigned int index) :
mIndex(index)
{
}
std::string
operator()(const boost::blank & array) const
{
return "";
}
std::string
operator()(const shared_ptr<std::vector<std::string> > & array) const
{
return array->operator[](mIndex);
}
template<typename U>
std::string
operator()(const shared_ptr<std::vector<U> > & array) const
{
std::stringstream value;
value << array->operator[](mIndex);
return value.str();
}
std::string
operator()(const boost::shared_array<const std::string> & array) const
{
return array[mIndex];
}
template<typename U>
std::string
operator()(const boost::shared_array<const U> & array) const
{
std::stringstream value;
value << array[mIndex];
return value.str();
}
private:
const unsigned int mIndex;
};
template <typename T>
class XdmfArray::GetValues : public boost::static_visitor<void> {
public:
......@@ -82,6 +140,15 @@ public:
return;
}
void
operator()(const shared_ptr<std::vector<std::string> > & array) const
{
for(unsigned int i=0; i<mNumValues; ++i) {
mValuesPointer[i*mValuesStride] =
(T)atof(array->operator[](mStartIndex + i*mArrayStride).c_str());
}
}
template<typename U>
void
operator()(const shared_ptr<std::vector<U> > & array) const
......@@ -110,6 +177,60 @@ private:
const unsigned int mValuesStride;
};
template <>
class XdmfArray::GetValues<std::string> : public boost::static_visitor<void> {
public:
GetValues(const unsigned int startIndex,
std::string * valuesPointer,
const unsigned int numValues,
const unsigned int arrayStride,
const unsigned int valuesStride) :
mStartIndex(startIndex),
mValuesPointer(valuesPointer),
mNumValues(numValues),
mArrayStride(arrayStride),
mValuesStride(valuesStride)
{
}
void
operator()(const boost::blank & array) const
{
return;
}
template<typename U>
void
operator()(const shared_ptr<std::vector<U> > & array) const
{
for(unsigned int i=0; i<mNumValues; ++i) {
std::stringstream value;
value << array->operator[](mStartIndex + i*mArrayStride);
mValuesPointer[i*mValuesStride] = value.str();
}
}
template<typename U>
void
operator()(const boost::shared_array<const U> & array) const
{
for(unsigned int i=0; i<mNumValues; ++i) {
std::stringstream value;
value << array[mStartIndex + i*mArrayStride];
mValuesPointer[i*mValuesStride] = value.str();
}
}
private:
const unsigned int mStartIndex;
std::string * mValuesPointer;
const unsigned int mNumValues;
const unsigned int mArrayStride;
const unsigned int mValuesStride;
};
template <typename T>
class XdmfArray::Insert : public boost::static_visitor<void> {
public:
......@@ -139,6 +260,24 @@ public:
mArray->mArray);
}
void
operator()(shared_ptr<std::vector<std::string> > & array) const
{
unsigned int size = mStartIndex + mNumValues;
if(mArrayStride > 1) {
size = mStartIndex + mNumValues * mArrayStride - 1;
}
if(array->size() < size) {
array->resize(size);
mDimensions.clear();
}
for(unsigned int i=0; i<mNumValues; ++i) {
std::stringstream value;
value << mValuesPointer[i*mValuesStride];
array->operator[](mStartIndex + i*mArrayStride) = value.str();
}
}
template<typename U>
void
operator()(shared_ptr<std::vector<U> > & array) const
......@@ -177,6 +316,90 @@ private:
std::vector<unsigned int> & mDimensions;
};
template <>
class XdmfArray::Insert<std::string> : public boost::static_visitor<void> {
public:
Insert(XdmfArray * const array,
const unsigned int startIndex,
const std::string * const valuesPointer,
const unsigned int numValues,
const unsigned int arrayStride,
const unsigned int valuesStride,
std::vector<unsigned int> & dimensions) :
mArray(array),
mStartIndex(startIndex),
mValuesPointer(valuesPointer),
mNumValues(numValues),
mArrayStride(arrayStride),
mValuesStride(valuesStride),
mDimensions(dimensions)
{
}
void
operator()(const boost::blank & array) const
{
mArray->initialize<std::string>();
boost::apply_visitor(*this,
mArray->mArray);
}
void
operator()(shared_ptr<std::vector<std::string> > & array) const
{
unsigned int size = mStartIndex + mNumValues;
if(mArrayStride > 1) {
size = mStartIndex + mNumValues * mArrayStride - 1;
}
if(array->size() < size) {
array->resize(size);
mDimensions.clear();
}
for(unsigned int i=0; i<mNumValues; ++i) {
array->operator[](mStartIndex + i*mArrayStride) =
mValuesPointer[i*mValuesStride].c_str();
}
}
template<typename U>
void
operator()(shared_ptr<std::vector<U> > & array) const
{
unsigned int size = mStartIndex + mNumValues;
if(mArrayStride > 1) {
size = mStartIndex + mNumValues * mArrayStride - 1;
}
if(array->size() < size) {
array->resize(size);
mDimensions.clear();
}
for(unsigned int i=0; i<mNumValues; ++i) {
array->operator[](mStartIndex + i*mArrayStride) =
(U)atof(mValuesPointer[i*mValuesStride].c_str());
}
}
template<typename U>
void
operator()(boost::shared_array<const U> & array) const
{
mArray->internalizeArrayPointer();
boost::apply_visitor(*this,
mArray->mArray);
}
private:
XdmfArray * const mArray;
const unsigned int mStartIndex;
const std::string * const mValuesPointer;
const unsigned int mNumValues;
const unsigned int mArrayStride;
const unsigned int mValuesStride;
std::vector<unsigned int> & mDimensions;
};
template <typename T>
class XdmfArray::PushBack : public boost::static_visitor<void> {
public:
......@@ -196,6 +419,15 @@ public:
mArray->mArray);
}
void
operator()(shared_ptr<std::vector<std::string> > & array) const
{
std::stringstream value;
value << mVal;
array->push_back(value.str());
mArray->mDimensions.clear();
}
template<typename U>
void
operator()(shared_ptr<std::vector<U> > & array) const
......@@ -219,6 +451,55 @@ private:
XdmfArray * const mArray;
};
template <>
class XdmfArray::PushBack<std::string> : public boost::static_visitor<void> {
public:
PushBack(const std::string & val,
XdmfArray * const array) :
mVal(val),
mArray(array)
{
}
void
operator()(const boost::blank & array) const
{
mArray->initialize<std::string>();
boost::apply_visitor(*this,
mArray->mArray);
}
void
operator()(shared_ptr<std::vector<std::string> > & array) const
{
array->push_back(mVal);
mArray->mDimensions.clear();
}
template<typename U>
void
operator()(shared_ptr<std::vector<U> > & array) const
{
array->push_back((U)atof(mVal.c_str()));
mArray->mDimensions.clear();
}
template<typename U>
void
operator()(const boost::shared_array<const U> & array) const
{
mArray->internalizeArrayPointer();
boost::apply_visitor(*this,
mArray->mArray);
}
private:
const std::string & mVal;
XdmfArray * const mArray;
};
template <typename T>
class XdmfArray::Resize : public boost::static_visitor<void> {
public:
......@@ -240,6 +521,15 @@ public:
mArray->mArray);
}
void
operator()(shared_ptr<std::vector<std::string> > & array) const
{
std::stringstream value;
value << mVal;
array->resize(mNumValues, value.str());
mArray->mDimensions.clear();
}
template<typename U>
void
operator()(shared_ptr<std::vector<U> > & array) const
......@@ -264,6 +554,58 @@ private:
const T & mVal;
};
template <>
class XdmfArray::Resize<std::string> : public boost::static_visitor<void> {
public:
Resize(XdmfArray * const array,
const unsigned int numValues,
const std::string & val) :
mArray(array),
mNumValues(numValues),
mVal(val)
{
}
void
operator()(const boost::blank & array) const
{
mArray->initialize<std::string>();
boost::apply_visitor(*this,
mArray->mArray);
}
void
operator()(shared_ptr<std::vector<std::string> > & array) const
{
array->resize(mNumValues, mVal);
mArray->mDimensions.clear();
}
template<typename U>
void
operator()(shared_ptr<std::vector<U> > & array) const
{
array->resize(mNumValues, (U)atof(mVal.c_str()));
mArray->mDimensions.clear();
}
template<typename U>
void
operator()(const boost::shared_array<const U> & array) const
{
mArray->internalizeArrayPointer();
boost::apply_visitor(*this,
mArray->mArray);
}
private:
XdmfArray * mArray;
const unsigned int mNumValues;
const std::string & mVal;
};
struct XdmfArray::NullDeleter
{
void
......
......@@ -97,6 +97,13 @@ XdmfArrayType::UInt32()
return p;
}
shared_ptr<const XdmfArrayType>
XdmfArrayType::String()
{
static shared_ptr<const XdmfArrayType> p(new XdmfArrayType("String", 0));
return p;
}
XdmfArrayType::XdmfArrayType(const std::string & name,
const unsigned int precision) :
mName(name),
......@@ -141,6 +148,9 @@ XdmfArrayType::New(const std::map<std::string, std::string> & itemProperties)
}
return Int32();
}
else if(typeVal.compare("String") == 0) {
return String();
}
else if(typeVal.compare("Char") == 0) {
return Int8();
}
......
......@@ -47,6 +47,7 @@
* UInt8
* UInt16
* UInt32
* String
*/
class XDMFCORE_EXPORT XdmfArrayType : public XdmfItemProperty {
......@@ -67,6 +68,7 @@ public:
static shared_ptr<const XdmfArrayType> UInt8();
static shared_ptr<const XdmfArrayType> UInt16();
static shared_ptr<const XdmfArrayType> UInt32();
static shared_ptr<const XdmfArrayType> String();
/**
* Get the data size, in bytes, of the value associated with this
......
......@@ -245,6 +245,13 @@ swig -v -c++ -python -o XdmfCorePython.cpp XdmfCore.i
}
}
void insertAsString(int startIndex, PyObject * list) {
Py_ssize_t size = PyList_Size(list);
for(Py_ssize_t i = 0; i < size; ++i) {
$self->insert<std::string>(i+startIndex, PyString_AsString(PyList_GetItem(list, i)));
}
}
};
%extend XdmfArrayType {
......@@ -340,6 +347,7 @@ swig -v -c++ -python -o XdmfCorePython.cpp XdmfCore.i
%template(getValueAsUInt8) XdmfArray::getValue<unsigned char>;
%template(getValueAsUInt16) XdmfArray::getValue<unsigned short>;
%template(getValueAsUInt32) XdmfArray::getValue<unsigned int>;
%template(getValueAsString) XdmfArray::getValue<std::string>;
%template(initializeAsInt8) XdmfArray::initialize<char>;
%template(initializeAsInt16) XdmfArray::initialize<short>;
......@@ -350,6 +358,7 @@ swig -v -c++ -python -o XdmfCorePython.cpp XdmfCore.i
%template(initializeAsUInt8) XdmfArray::initialize<unsigned char>;
%template(initializeAsUInt16) XdmfArray::initialize<unsigned short>;
%template(initializeAsUInt32) XdmfArray::initialize<unsigned int>;
%template(initializeAsString) XdmfArray::initialize<std::string>;
%template(insertValueAsInt8) XdmfArray::insert<char>;
%template(insertValueAsInt16) XdmfArray::insert<short>;
......@@ -360,6 +369,7 @@ swig -v -c++ -python -o XdmfCorePython.cpp XdmfCore.i
%template(insertValueAsUInt8) XdmfArray::insert<unsigned char>;
%template(insertValueAsUInt16) XdmfArray::insert<unsigned short>;
%template(insertValueAsUInt32) XdmfArray::insert<unsigned int>;
%template(insertValueAsString) XdmfArray::insert<std::string>;
%template(pushBackAsInt8) XdmfArray::pushBack<char>;
%template(pushBackAsInt16) XdmfArray::pushBack<short>;
......@@ -370,6 +380,7 @@ swig -v -c++ -python -o XdmfCorePython.cpp XdmfCore.i
%template(pushBackAsUInt8) XdmfArray::pushBack<unsigned char>;
%template(pushBackAsUInt16) XdmfArray::pushBack<unsigned short>;
%template(pushBackAsUInt32) XdmfArray::pushBack<unsigned int>;
%template(pushBackAsString) XdmfArray::pushBack<std::string>;
%template(resizeAsInt8) XdmfArray::resize<char>;
%template(resizeAsInt16) XdmfArray::resize<short>;
......@@ -380,6 +391,7 @@ swig -v -c++ -python -o XdmfCorePython.cpp XdmfCore.i
%template(resizeAsUInt8) XdmfArray::resize<unsigned char>;
%template(resizeAsUInt16) XdmfArray::resize<unsigned short>;
%template(resizeAsUInt32) XdmfArray::resize<unsigned int>;
%template(resizeAsString) XdmfArray::resize<std::string>;
%template(UIntVector) std::vector<unsigned int>;
%template(ItemVector) std::vector<boost::shared_ptr<XdmfItem> >;
......
......@@ -115,6 +115,7 @@ XdmfHDF5Controller::read(XdmfArray * const array, const int fapl)
NULL);*/
hid_t datatype;
bool closeDatatype = false;
if(mType == XdmfArrayType::Int8()) {
datatype = H5T_NATIVE_CHAR;
}
......@@ -142,6 +143,11 @@ XdmfHDF5Controller::read(XdmfArray * const array, const int fapl)
else if(mType == XdmfArrayType::UInt32()) {
datatype = H5T_NATIVE_UINT;
}
else if(mType == XdmfArrayType::String()) {
datatype = H5Tcopy(H5T_C_S1);
H5Tset_size(datatype, H5T_VARIABLE);
closeDatatype = true;
}
else {
XdmfError::message(XdmfError::FATAL,
"Unknown XdmfArrayType encountered in hdf5 "
......@@ -156,15 +162,37 @@ XdmfHDF5Controller::read(XdmfArray * const array, const int fapl)
"allocated size in XdmfArray.");
}
status = H5Dread(dataset,
datatype,
memspace,
dataspace,
H5P_DEFAULT,
array->getValuesInternal());
if(closeDatatype) {
char ** data = new char*[numVals];
status = H5Dread(dataset,
datatype,
memspace,
dataspace,
H5P_DEFAULT,
data);
for(hssize_t i=0; i<numVals; ++i) {
array->insert<std::string>(i, data[i]);
}
status = H5Dvlen_reclaim(datatype,
dataspace,
H5P_DEFAULT,
data);
delete [] data;
}
else {
status = H5Dread(dataset,
datatype,
memspace,
dataspace,
H5P_DEFAULT,
array->getValuesInternal());
}
status = H5Sclose(dataspace);
status = H5Sclose(memspace);
status = H5Dclose(dataset);
if(closeDatatype) {
status = H5Tclose(datatype);
}
status = H5Fclose(hdf5Handle);
}
......@@ -171,6 +171,7 @@ XdmfHDF5Writer::write(XdmfArray & array,