Commit 7a8eade9 authored by Kenneth Leiter's avatar Kenneth Leiter

ENH: Add ability to XPath a file when opening in order to only read a part of the file.

parent 49cd1fb0
......@@ -141,6 +141,11 @@ void XdmfMap::insert(const unsigned int localNodeId, const unsigned int remoteTa
}
}
bool XdmfMap::isInitialized() const
{
return mImpl->mMap.size() > 0;
}
void XdmfMap::populateItem(const std::map<std::string, std::string> & itemProperties, std::vector<boost::shared_ptr<XdmfItem> > & childItems)
{
std::vector<boost::shared_ptr<XdmfArray> > arrayVector;
......@@ -213,7 +218,7 @@ void XdmfMap::read()
void XdmfMap::release()
{
mImpl->mMap.clear();
}
void XdmfMap::traverse(const boost::shared_ptr<XdmfBaseVisitor> visitor)
......
......@@ -38,6 +38,11 @@ public:
void insert(const unsigned int localNodeId, const unsigned int remoteTaskId, const unsigned int remoteLocalNodeId);
/**
* Returns whether the map is initialized (contains values in memory).
*/
bool isInitialized() const;
/**
* Read data from disk into memory.
*/
......
......@@ -24,3 +24,8 @@ boost::shared_ptr<XdmfItem> XdmfReader::read(const std::string & filePath) const
{
return XdmfCoreReader::read(filePath);
}
std::vector<boost::shared_ptr<XdmfItem> > XdmfReader::read(const std::string & filePath, const std::string & xPath) const
{
return XdmfCoreReader::read(filePath, xPath);
}
......@@ -25,6 +25,8 @@ public:
boost::shared_ptr<XdmfItem> read(const std::string & filePath) const;
std::vector<boost::shared_ptr<XdmfItem> > read(const std::string & filePath, const std::string & xPath) const;
protected:
XdmfReader();
......
......@@ -67,8 +67,6 @@ public:
return myItems;
}
private:
/**
* Reads a single xmlNode into an XdmfItem object in memory. The constructed XdmfItem is added to myItems and an entry is added mapping the xmlNodePtr to the new XdmfItem in the xPathMap.
*/
......@@ -144,3 +142,34 @@ boost::shared_ptr<XdmfItem> XdmfCoreReader::read(const std::string & filePath) c
return toReturn[0];
}
std::vector<boost::shared_ptr<XdmfItem> > XdmfCoreReader::read(const std::string & filePath, const std::string & xPath) const
{
std::string xmlDir = XdmfSystemUtils::getRealPath(filePath);
size_t index = xmlDir.find_last_of("/\\");
if(index != std::string::npos)
{
xmlDir = xmlDir.substr(0, index + 1);
}
const xmlDocPtr document = xmlReadFile(filePath.c_str(), NULL, 0);
const xmlXPathContextPtr xPathContext = xmlXPtrNewContext(document, NULL, NULL);
if(document == NULL)
{
assert(false);
}
std::vector<boost::shared_ptr<XdmfItem> > toReturn;
std::map<xmlNodePtr, boost::shared_ptr<XdmfItem> > xPathMap;
xmlXPathObjectPtr xPathObject = xmlXPathEvalExpression((xmlChar*)xPath.c_str(), xPathContext);
for(unsigned int i=0; i<xPathObject->nodesetval->nodeNr; ++i)
{
mImpl->readSingleNode(xPathObject->nodesetval->nodeTab[i], xPathContext, xPathMap, toReturn, xmlDir);
}
xmlXPathFreeObject(xPathObject);
xmlXPathFreeContext(xPathContext);
xmlFreeDoc(document);
xmlCleanupParser();
return toReturn;
}
......@@ -8,6 +8,7 @@ class XdmfItem;
// Includes
#include <boost/shared_ptr.hpp>
#include <string>
#include <vector>
/**
* @brief Reads an Xdmf structured file stored on disk into memory.
......@@ -29,6 +30,15 @@ public:
*/
virtual boost::shared_ptr<XdmfItem> read(const std::string & filePath) const;
/**
* Read part of an Xdmf file from disk into memory.
*
* @param filePath the path of the Xdmf file to read in from disk.
* @param xPath an XPath corresponding to the portion of the file to read.
* @return a vector of XdmfItems that are included in the XPath.
*/
virtual std::vector<boost::shared_ptr<XdmfItem> > read(const std::string & filePath, const std::string & xPath) const;
protected:
/**
......
......@@ -7,6 +7,7 @@
#include "XdmfArrayType.hpp"
#include "XdmfHDF5Controller.hpp"
#include "XdmfHDF5Writer.hpp"
#include "XdmfSystemUtils.hpp"
/**
* PIMPL
......@@ -16,14 +17,16 @@ class XdmfHDF5Writer::XdmfHDF5WriterImpl {
public:
XdmfHDF5WriterImpl(const std::string & hdf5FilePath) :
mFilePath(hdf5FilePath),
mFilePath(XdmfSystemUtils::getRealPath(hdf5FilePath)),
mDataSetId(0),
mMode(Default)
{
};
~XdmfHDF5WriterImpl()
{
};
int mDataSetId;
std::string mFilePath;
Mode mMode;
......
......@@ -25,10 +25,10 @@ public:
mWriteXPaths(true),
mXMLCurrentNode(NULL),
mXMLDocument(NULL),
mXMLFilePath(XdmfSystemUtils::getRealPath(xmlFilePath)),
mXPathCount(0),
mXPathString("")
{
mXMLFilePath = XdmfSystemUtils::getRealPath(xmlFilePath);
};
~XdmfWriterImpl()
......@@ -191,18 +191,18 @@ void XdmfWriter::visit(XdmfArray & array, const boost::shared_ptr<XdmfBaseVisito
xmlTextValues << array.getValuesString();
}
bool oldWriteXPaths = mImpl->mWriteXPaths;
mImpl->mWriteXPaths = false;
// Write XML (metadata) description
if(isSubclassed)
{
boost::shared_ptr<XdmfArray> arrayToWrite = XdmfArray::New();
array.swap(arrayToWrite);
mImpl->mXMLCurrentNode = mImpl->mXMLCurrentNode->last;
bool oldWriteXPaths = mImpl->mWriteXPaths;
mImpl->mWriteXPaths = false;
this->visit(dynamic_cast<XdmfItem &>(*arrayToWrite.get()), visitor);
xmlAddChild(mImpl->mXMLCurrentNode->last, xmlNewText((xmlChar*)xmlTextValues.str().c_str()));
mImpl->mXMLCurrentNode = mImpl->mXMLCurrentNode->parent;
mImpl->mWriteXPaths = oldWriteXPaths;
array.swap(arrayToWrite);
}
else
......@@ -210,6 +210,8 @@ void XdmfWriter::visit(XdmfArray & array, const boost::shared_ptr<XdmfBaseVisito
this->visit(dynamic_cast<XdmfItem &>(array), visitor);
xmlAddChild(mImpl->mXMLCurrentNode->last, xmlNewText((xmlChar*)xmlTextValues.str().c_str()));
}
mImpl->mWriteXPaths = oldWriteXPaths;
}
}
......
......@@ -10,10 +10,12 @@ int main(int argc, char* argv[])
boost::shared_ptr<XdmfWriter> writer = XdmfWriter::New("TestXdmfReader1.xmf");
writer->setLightDataLimit(10);
boost::shared_ptr<XdmfGrid> grid = XdmfTestDataGenerator::createHexahedron();
boost::shared_ptr<XdmfGrid> grid1 = XdmfTestDataGenerator::createHexahedron();
boost::shared_ptr<XdmfGrid> grid2 = XdmfTestDataGenerator::createHexahedron();
boost::shared_ptr<XdmfDomain> domain = XdmfDomain::New();
domain->insert(grid);
domain->insert(grid1);
domain->insert(grid2);
domain->accept(writer);
boost::shared_ptr<XdmfReader> reader = XdmfReader::New();
......@@ -25,5 +27,14 @@ int main(int argc, char* argv[])
assert(XdmfTestCompareFiles::compareFiles("TestXdmfReader1.xmf", "TestXdmfReader2.xmf"));
std::vector<boost::shared_ptr<XdmfItem> > readItems = reader->read("TestXdmfReader1.xmf", "/Xdmf/Domain/Grid[1]");
assert(readItems.size() == 1);
boost::shared_ptr<XdmfGrid> readGrid = boost::shared_dynamic_cast<XdmfGrid>(readItems[0]);
assert(readGrid->getName().compare("Hexahedron") == 0);
std::vector<boost::shared_ptr<XdmfItem> > readItems2 = reader->read("TestXdmfReader1.xmf", "//Attribute");
assert(readItems2.size() == 4);
boost::shared_ptr<XdmfAttribute> readAttribute = boost::shared_dynamic_cast<XdmfAttribute>(readItems2[0]);
assert(readAttribute->getName().compare("Nodal Attribute") == 0 || readAttribute->getName().compare("Cell Attribute"));
return 0;
}
......@@ -42,6 +42,7 @@ extern "C"
#include "XdmfGridCollection.hpp"
#include "XdmfGridCollectionType.hpp"
#include "XdmfHDF5Writer.hpp"
#include "XdmfMap.hpp"
#include "XdmfPartitioner.hpp"
#include "XdmfSet.hpp"
#include "XdmfSetType.hpp"
......@@ -60,30 +61,30 @@ boost::shared_ptr<XdmfGridCollection> XdmfPartitioner::partition(const boost::sh
boost::shared_ptr<XdmfHDF5Writer> heavyDataWriter) const
{
int metisElementType;
int numNodesPerElement;
int nodesPerElement;
boost::shared_ptr<const XdmfTopologyType> topologyType = gridToPartition->getTopology()->getType();
if(topologyType == XdmfTopologyType::Triangle() || topologyType == XdmfTopologyType::Triangle_6())
{
metisElementType = 1;
numNodesPerElement = 3;
nodesPerElement = 3;
}
else if(topologyType == XdmfTopologyType::Quadrilateral() || topologyType == XdmfTopologyType::Quadrilateral_8())
{
metisElementType = 4;
numNodesPerElement = 4;
nodesPerElement = 4;
}
else if(topologyType == XdmfTopologyType::Tetrahedron() || topologyType == XdmfTopologyType::Tetrahedron_10())
{
metisElementType = 2;
numNodesPerElement = 4;
nodesPerElement = 4;
}
else if(topologyType == XdmfTopologyType::Hexahedron() || topologyType == XdmfTopologyType::Hexahedron_20() ||
topologyType == XdmfTopologyType::Hexahedron_24() || topologyType == XdmfTopologyType::Hexahedron_27() ||
topologyType == XdmfTopologyType::Hexahedron_64())
{
metisElementType = 3;
numNodesPerElement = 8;
nodesPerElement = 8;
}
else
{
......@@ -96,20 +97,20 @@ boost::shared_ptr<XdmfGridCollection> XdmfPartitioner::partition(const boost::sh
}
int numElements = gridToPartition->getTopology()->getNumberElements();
idxtype * metisConnectivity = new idxtype[numNodesPerElement * numElements];
idxtype * metisConnectivity = new idxtype[nodesPerElement * numElements];
for(unsigned int i=0; i<numElements; ++i)
{
gridToPartition->getTopology()->getValuesCopy(i*topologyType->getNodesPerElement(), &metisConnectivity[i*numNodesPerElement], numNodesPerElement);
gridToPartition->getTopology()->getValuesCopy(i*topologyType->getNodesPerElement(), &metisConnectivity[i*nodesPerElement], nodesPerElement);
}
int numNodes = gridToPartition->getGeometry()->getNumberPoints();
// Need to remap connectivity for nonlinear elements so that metis handles it properly.
std::map<idxtype, idxtype> xdmfIdToMetisId;
if(numNodesPerElement != topologyType->getNodesPerElement())
if(nodesPerElement != topologyType->getNodesPerElement())
{
unsigned int index = 0;
for (unsigned int i=0; i<numElements * numNodesPerElement; ++i)
for (unsigned int i=0; i<numElements * nodesPerElement; ++i)
{
std::map<idxtype, idxtype>::const_iterator val = xdmfIdToMetisId.find(metisConnectivity[i]);
if (val != xdmfIdToMetisId.end())
......@@ -173,8 +174,7 @@ boost::shared_ptr<XdmfGridCollection> XdmfPartitioner::partition(const boost::sh
}
delete [] elementsPartition;
boost::shared_ptr<XdmfAttribute> globalNodeIds = gridToPartition->getAttribute("GlobalNodeId");
bool generateGlobalNodeIds = !globalNodeIds;
bool generateGlobalNodeIds = !gridToPartition->getAttribute("GlobalNodeId");
boost::shared_ptr<XdmfGridCollection> partitionedGrids = XdmfGridCollection::New();
partitionedGrids->setType(XdmfGridCollectionType::Spatial());
......@@ -243,7 +243,7 @@ boost::shared_ptr<XdmfGridCollection> XdmfPartitioner::partition(const boost::sh
if (generateGlobalNodeIds)
{
globalNodeIds = XdmfAttribute::New();
boost::shared_ptr<XdmfAttribute> globalNodeIds = XdmfAttribute::New();
globalNodeIds->setName("GlobalNodeId");
globalNodeIds->setType(XdmfAttributeType::GlobalId());
globalNodeIds->setCenter(XdmfAttributeCenter::Node());
......@@ -395,6 +395,29 @@ boost::shared_ptr<XdmfGridCollection> XdmfPartitioner::partition(const boost::sh
}
currSet->release();
}
// Add XdmfMap to map boundary nodes between partitions
std::vector<boost::shared_ptr<XdmfAttribute> > globalNodeIds;
for(unsigned int i=0; i<partitionedGrids->getNumberGrids(); ++i)
{
boost::shared_ptr<XdmfAttribute> globalNodeId = partitionedGrids->getGrid(i)->getAttribute("GlobalNodeId");
globalNodeId->read();
globalNodeIds.push_back(globalNodeId);
}
std::vector<boost::shared_ptr<XdmfMap> > maps = XdmfMap::New(globalNodeIds);
for(unsigned int i=0; i<partitionedGrids->getNumberGrids(); ++i)
{
boost::shared_ptr<XdmfMap> map = maps[i];
partitionedGrids->getGrid(i)->setMap(map);
if(heavyDataWriter)
{
globalNodeIds[i]->release();
map->accept(heavyDataWriter);
map->release();
}
}
return partitionedGrids;
}
......
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