Commit ae817cd9 authored by Kenneth Leiter's avatar Kenneth Leiter
Browse files

ENH: Add executable for conversion between exodus and xdmf.

Add ability of XdmfExodusWriter to handle conversion of xdmf meshes
containing spatial and temporal collections to exodus.
parent 7ea61be2
...@@ -20,6 +20,7 @@ if(XDMF_BUILD_EXODUS_IO) ...@@ -20,6 +20,7 @@ if(XDMF_BUILD_EXODUS_IO)
include_directories(${EXODUS_INCLUDE_DIR} ${NetCDF_INCLUDE_DIR}) include_directories(${EXODUS_INCLUDE_DIR} ${NetCDF_INCLUDE_DIR})
endif(EXODUS_FOUND) endif(EXODUS_FOUND)
set(XdmfUtilsSources ${XdmfUtilsSources} XdmfExodusReader XdmfExodusWriter) set(XdmfUtilsSources ${XdmfUtilsSources} XdmfExodusReader XdmfExodusWriter)
set(XdmfUtilsExecutables ${XdmfUtilsExecutables} XdmfExodusConverter)
set(XdmfUtilsLinkLibraries set(XdmfUtilsLinkLibraries
${XdmfUtilsLinkLibraries} ${XdmfUtilsLinkLibraries}
${EXODUS_LIBRARIES} ${EXODUS_LIBRARIES}
......
#include <cstdio>
#include <iostream>
#include <sstream>
#include <exodusII.h>
#include "XdmfDomain.hpp"
#include "XdmfError.hpp"
#include "XdmfExodusReader.hpp"
#include "XdmfExodusWriter.hpp"
#include "XdmfGridCollection.hpp"
#include "XdmfHDF5Writer.hpp"
#include "XdmfReader.hpp"
#include "XdmfWriter.hpp"
namespace {
//
// print usage
//
inline void
printUsage(const char * programName)
{
std::cerr << "usage: " << programName << " "
<< "<input file> [output file]"
<< std::endl;
//
//
//
return;
}
//
// process command line
//
void
processCommandLine(std::string & inputFileName,
std::string & outputFileName,
int ac,
char * av[])
{
int c;
bool errorFlag = false;
while( (c=getopt(ac, av, "")) != -1 )
switch(c){
case '?':
errorFlag = true;
break;
}
if (optind >= ac)
errorFlag = true;
else {
inputFileName = av[optind];
++optind;
}
if (optind < ac) {
outputFileName = av[optind];
++optind;
}
//
// check errorFlag
//
if (errorFlag == true) {
printUsage(av[0]);
std::exit(EXIT_FAILURE);
}
}
}
/**
* XdmfExodusConverter is a command line utility for converting
* between Xdmf and Exodus files. If given an Xdmf file, the tool
* converts the file to Exodus and if given a path to an Exodus file,
* the tool converts the file to Xdmf.
*
* Usage:
* XdmfExodusConverter <path-of-file-to-convert>
* (Optional: <path-to-output-file>)
*
*/
int main(int argc, char* argv[])
{
std::string inputFileName = "";
std::string outputFileName = "";
processCommandLine(inputFileName,
outputFileName,
argc,
argv);
std::cout << inputFileName << std::endl;
FILE * refFile = fopen(inputFileName.c_str(), "r");
if (refFile) {
// Success
fclose(refFile);
}
else {
std::cout << "Cannot open file: " << argv[1] << std::endl;
return 1;
}
std::string meshName;
if(outputFileName.compare("") == 0) {
meshName = inputFileName;
}
else {
meshName = outputFileName;
}
if(meshName.find_last_of("/\\") != std::string::npos) {
meshName = meshName.substr(meshName.find_last_of("/\\") + 1,
meshName.length());
}
if (meshName.rfind(".") != std::string::npos) {
meshName = meshName.substr(0, meshName.rfind("."));
}
int CPU_word_size = sizeof(double);
int IO_word_size = 0; // Get from file
float version;
const int exodusHandle =
ex_open(argv[1], EX_READ, &CPU_word_size, &IO_word_size, &version);
if(exodusHandle < 0) {
// Xdmf to Exodus
shared_ptr<XdmfReader> reader = XdmfReader::New();
shared_ptr<XdmfDomain> domain =
shared_dynamic_cast<XdmfDomain>(reader->read(inputFileName));
std::stringstream exodusFileName;
exodusFileName << meshName << ".exo";
shared_ptr<XdmfExodusWriter> writer = XdmfExodusWriter::New();
if(domain->getNumberUnstructuredGrids() == 1) {
const shared_ptr<XdmfUnstructuredGrid> grid =
domain->getUnstructuredGrid(0);
writer->write(exodusFileName.str(),
grid);
std::cout << "Wrote: " << exodusFileName.str() << std::endl;
}
else if(domain->getNumberGridCollections() == 1) {
const shared_ptr<XdmfGridCollection> grid =
domain->getGridCollection(0);
writer->write(exodusFileName.str(),
grid);
std::cout << "Wrote: " << exodusFileName.str() << std::endl;
}
else {
XdmfError::message(XdmfError::FATAL,
"Cannot find grid in Xdmf file to convert to "
"exodus.");
}
}
else {
// Exodus to Xdmf
std::stringstream heavyFileName;
heavyFileName << meshName << ".h5";
shared_ptr<XdmfHDF5Writer> heavyDataWriter =
XdmfHDF5Writer::New(heavyFileName.str());
heavyDataWriter->setReleaseData(true);
shared_ptr<XdmfExodusReader> exodusReader = XdmfExodusReader::New();
shared_ptr<XdmfUnstructuredGrid> readGrid =
exodusReader->read(inputFileName,
heavyDataWriter);
shared_ptr<XdmfDomain> newDomain = XdmfDomain::New();
newDomain->insert(readGrid);
std::stringstream xmlFileName;
xmlFileName << meshName << ".xmf";
shared_ptr<XdmfWriter> writer = XdmfWriter::New(xmlFileName.str(),
heavyDataWriter);
newDomain->accept(writer);
std::cout << "Wrote: " << xmlFileName.str() << std::endl;
}
/*
shared_ptr<XdmfReader> reader = XdmfReader::New();
shared_ptr<XdmfDomain> domain =
shared_dynamic_cast<XdmfDomain>(reader->read(inputFileName));
if(unpartition) {
if(domain->getNumberGridCollections() == 0) {
std::cout << "No grid collections to unpartition" << std::endl;
return 1;
}
}
else {
if(domain->getNumberUnstructuredGrids() == 0 &&
domain->getNumberGridCollections() == 0 &&
domain->getNumberGraphs() == 0) {
std::cout << "No grids or graphs to partition" << std::endl;
return 1;
}
}
std::stringstream heavyFileName;
heavyFileName << meshName << ".h5";
shared_ptr<XdmfHDF5Writer> heavyDataWriter =
XdmfHDF5Writer::New(heavyFileName.str());
shared_ptr<XdmfDomain> newDomain = XdmfDomain::New();
shared_ptr<XdmfPartitioner> partitioner = XdmfPartitioner::New();
if(unpartition) {
shared_ptr<XdmfUnstructuredGrid> toWrite =
partitioner->unpartition(domain->getGridCollection(0));
newDomain->insert(toWrite);
}
else {
if(domain->getNumberGraphs() == 0) {
shared_ptr<XdmfUnstructuredGrid> gridToPartition;
if(domain->getNumberUnstructuredGrids() == 0) {
// repartition
gridToPartition =
partitioner->unpartition(domain->getGridCollection(0));
}
else {
gridToPartition = domain->getUnstructuredGrid(0);
}
shared_ptr<XdmfGridCollection> toWrite =
partitioner->partition(gridToPartition,
numPartitions,
metisScheme,
heavyDataWriter);
newDomain->insert(toWrite);
}
else {
shared_ptr<XdmfGraph> graphToPartition = domain->getGraph(0);
partitioner->partition(graphToPartition,
numPartitions);
newDomain->insert(graphToPartition);
}
}
std::stringstream xmlFileName;
xmlFileName << meshName << ".xmf";
shared_ptr<XdmfWriter> writer = XdmfWriter::New(xmlFileName.str(),
heavyDataWriter);
newDomain->accept(writer);
std::cout << "Wrote: " << xmlFileName.str() << std::endl;
*/
}
...@@ -22,6 +22,7 @@ ...@@ -22,6 +22,7 @@
/*****************************************************************************/ /*****************************************************************************/
#include <exodusII.h> #include <exodusII.h>
#include <set>
#include <sstream> #include <sstream>
#include "XdmfArrayType.hpp" #include "XdmfArrayType.hpp"
#include "XdmfAttribute.hpp" #include "XdmfAttribute.hpp"
...@@ -38,6 +39,8 @@ ...@@ -38,6 +39,8 @@
#include "XdmfUnstructuredGrid.hpp" #include "XdmfUnstructuredGrid.hpp"
#include "XdmfError.hpp" #include "XdmfError.hpp"
#include <iostream>
// //
// local methods // local methods
// //
...@@ -123,9 +126,184 @@ namespace { ...@@ -123,9 +126,184 @@ namespace {
else if(topologyType == XdmfTopologyType::Edge_3()) { else if(topologyType == XdmfTopologyType::Edge_3()) {
return "EDGE"; return "EDGE";
} }
XdmfError::message(XdmfError::FATAL,
"Topology type not supported by ExodusII");
return ""; return "";
} }
/**
* Pull general information from grid in order to initialize exodus
* file.
*
* This should be called once per element block (spatial partition) in
* the xdmf file.
*/
void
getGridInformation(const shared_ptr<XdmfUnstructuredGrid> grid,
int & num_dim,
int & num_nodes,
int & num_elem,
int & num_elem_blk,
std::vector<int> & elem_blk_ids,
std::vector<char *> & elem_type,
std::vector<int> & num_elem_this_blk,
std::vector<int> & num_nodes_per_elem,
std::vector<int> & num_attr,
std::map<std::string, std::set<int> > & nodeSets,
std::map<std::string, std::set<int> > & sideSets)
{
// get topology
const shared_ptr<XdmfTopology> topology = grid->getTopology();
const int numberElements = topology->getNumberElements();
num_dim = grid->getGeometry()->getType()->getDimensions();
num_elem += numberElements;
num_elem_blk++;
elem_blk_ids.push_back(10 + num_elem_blk);
// get exodus topology type
const std::string exodusTopologyType =
xdmfToExodusTopologyType(topology->getType());
char * cellTypeCStr = new char[exodusTopologyType.size() + 1];
strcpy(cellTypeCStr, exodusTopologyType.c_str());
elem_type.push_back(cellTypeCStr);
num_elem_this_blk.push_back(numberElements);
num_nodes_per_elem.push_back(topology->getType()->getNodesPerElement());
num_attr.push_back(0);
for(unsigned int i=0; i<grid->getNumberSets(); ++i) {
shared_ptr<XdmfSet> set = grid->getSet(i);
if(set->getType() == XdmfSetType::Cell()) {
sideSets[set->getName()] = std::set<int>();
}
else if(set->getType() == XdmfSetType::Node()) {
nodeSets[set->getName()] = std::set<int>();
}
}
}
/**
* Convert between Xdmf and Exodus topology numberings
*/
void
convertXdmfToExodusTopology(int * elem_connectivity,
const shared_ptr<const XdmfTopologyType> topType,
int num_elem)
{
if(topType == XdmfTopologyType::Hexahedron_20() ||
topType == XdmfTopologyType::Hexahedron_27()) {
int * ptr = elem_connectivity;
int itmp[4];
for(int i=0; i<num_elem; ++i) {
ptr += 12;
for (unsigned int j=0; j<4; ++j, ++ptr) {
itmp[j] = *ptr;
*ptr = ptr[4];
}
for(unsigned int j=0; j<4; ++j, ++ptr) {
*ptr = itmp[j];
}
if(topType == XdmfTopologyType::Hexahedron_27()) {
itmp[0] = *ptr;
*ptr = ptr[6];
ptr++;
itmp[1] = *ptr;
*ptr = ptr[3];
ptr++;
itmp[2] = *ptr;
*ptr = ptr[3];
ptr++;
itmp[3] = *ptr;
for (unsigned int j=0; j<4; ++j, ++ptr) {
*ptr = itmp[j];
}
}
}
}
else if(topType == XdmfTopologyType::Wedge_15() ||
topType == XdmfTopologyType::Wedge_18()) {
int * ptr = elem_connectivity;
int itmp[3];
for(int i=0; i<num_elem; ++i) {
ptr += 9;
for(unsigned int j=0; j<3; ++j, ++ptr) {
itmp[j] = *ptr;
*ptr = ptr[3];
}
for(unsigned int j=0; j<3; ++j, ++ptr) {
*ptr = itmp[j];
}
if(topType == XdmfTopologyType::Wedge_18()) {
itmp[0] = *(ptr);
itmp[1] = *(ptr+1);
itmp[2] = *(ptr+2);
*(ptr++) = itmp[2];
*(ptr++) = itmp[0];
*(ptr++) = itmp[1];
}
}
}
}
/**
* Write sets from grid to exodus file.
*/
void
writeSets(int exodusHandle,
const shared_ptr<XdmfUnstructuredGrid> grid)
{
const unsigned int numberSets = grid->getNumberSets();
const int setId = 20;
std::vector<int> values;
for(unsigned int i=0; i<numberSets; ++i) {
const shared_ptr<XdmfSet> set = grid->getSet(i);
bool releaseSet = false;
if(!set->isInitialized()) {
set->read();
releaseSet = true;
}
std::string name = set->getName();
if(name.size() > MAX_STR_LENGTH) {
name = name.substr(0, MAX_STR_LENGTH);
}
const unsigned int setSize = set->getSize();
values.resize(setSize);
for(unsigned int k=0; k<setSize; ++k) {
// Add 1 to xdmf ids because exodus ids begin at 1
values[k] = set->getValue<int>(k) + 1;
}
if(set->getType() == XdmfSetType::Cell()) {
ex_put_side_set_param(exodusHandle, setId + i, setSize, 0);
ex_put_side_set(exodusHandle, setId + i, &(values[0]), NULL);
ex_put_name(exodusHandle, EX_SIDE_SET, setId + i, name.c_str());
}
else if(set->getType() == XdmfSetType::Node()) {
ex_put_node_set_param(exodusHandle, setId + i, setSize, 0);
ex_put_node_set(exodusHandle, setId + i, &(values[0]));
ex_put_name(exodusHandle, EX_NODE_SET, setId + i, name.c_str());
}
if(releaseSet) {
set->release();
}
}
}
} }
shared_ptr<XdmfExodusWriter> shared_ptr<XdmfExodusWriter>
...@@ -148,7 +326,7 @@ XdmfExodusWriter::write(const std::string & filePath, ...@@ -148,7 +326,7 @@ XdmfExodusWriter::write(const std::string & filePath,
const shared_ptr<XdmfUnstructuredGrid> gridToWrite) const const shared_ptr<XdmfUnstructuredGrid> gridToWrite) const
{ {
// Open Exodus File // open exodus file
int wordSize = 8; int wordSize = 8;
int storeSize = 8; int storeSize = 8;
int exodusHandle = ex_create(filePath.c_str(), int exodusHandle = ex_create(filePath.c_str(),
...@@ -156,7 +334,7 @@ XdmfExodusWriter::write(const std::string & filePath, ...@@ -156,7 +334,7 @@ XdmfExodusWriter::write(const std::string & filePath,
&wordSize, &wordSize,
&storeSize); &storeSize);
// Initialize Exodus File // initialize exodus file
std::string title = gridToWrite->getName(); std::string title = gridToWrite->getName();
if(title.size() > MAX_STR_LENGTH) { if(title.size() > MAX_STR_LENGTH) {
title = title.substr(0, MAX_STR_LENGTH); title = title.substr(0, MAX_STR_LENGTH);
...@@ -166,7 +344,7 @@ XdmfExodusWriter::write(const std::string & filePath, ...@@ -166,7 +344,7 @@ XdmfExodusWriter::write(const std::string & filePath,
shared_ptr<XdmfGridCollection>(); shared_ptr<XdmfGridCollection>();
shared_ptr<XdmfUnstructuredGrid> currGrid = gridToWrite; shared_ptr<XdmfUnstructuredGrid> currGrid = gridToWrite;
// Check if they are temporal collections and use the first grid to // check if they are temporal collections and use the first grid to
// determine geometry and topology. // determine geometry and topology.
if(shared_ptr<XdmfGridCollection> tmpGrid = if(shared_ptr<XdmfGridCollection> tmpGrid =
shared_dynamic_cast<XdmfGridCollection>(gridToWrite)) { shared_dynamic_cast<XdmfGridCollection>(gridToWrite)) {
...@@ -176,15 +354,15 @@ XdmfExodusWriter::write(const std::string & filePath, ...@@ -176,15 +354,15 @@ XdmfExodusWriter::write(const std::string & filePath,
gridCollection = tmpGrid; gridCollection = tmpGrid;
} }
else { else {
// Only Temporal Collections are currently supported. // only temporal collections are currently supported.
XdmfError::message(XdmfError::FATAL, "Only Temporal Collections are currently supported or no unstructured grids provided in XdmfExodusWriter::write"); XdmfError::message(XdmfError::FATAL, "Only Temporal Collections are currently supported or no unstructured grids provided in XdmfExodusWriter::write");
} }
} }
else { else {
// This is expected to fail when we've already found a grid. // this is expected to fail when we've already found a grid.
} }
// Make sure geometry and topology are non null // make sure geometry and topology are non null
if(!(currGrid->getGeometry() && currGrid->getTopology())) if(!(currGrid->getGeometry() && currGrid->getTopology()))
XdmfError::message(XdmfError::FATAL, "Current grid's geometry or topology is null in XdmfExodusWriter::write"); XdmfError::message(XdmfError::FATAL, "Current grid's geometry or topology is null in XdmfExodusWriter::write");
...@@ -213,27 +391,32 @@ XdmfExodusWriter::write(const std::string & filePath, ...@@ -213,27 +391,32 @@ XdmfExodusWriter::write(const std::string & filePath,
num_node_sets, num_node_sets,
num_side_sets); num_side_sets);
shared_ptr<XdmfGeometry> geometry = currGrid->getGeometry();
bool releaseGeometry = false;
if(!geometry->isInitialized()) {
geometry->read();
releaseGeometry = true;
}
double * x = new double[num_nodes]; double * x = new double[num_nodes];
double * y = new double[num_nodes]; double * y = new double[num_nodes];
double * z = new double[num_nodes]; double * z = new double[num_nodes];
// Write nodal coordinate values to exodus // Write nodal coordinate values to exodus
currGrid->getGeometry()->getValues(0, x, num_nodes, 3); geometry->getValues(0, x, num_nodes, 3);
currGrid->getGeometry()->getValues(1, y, num_nodes, 3); geometry->getValues(1, y, num_nodes, 3);
if(currGrid->getGeometry()->getType() == XdmfGeometryType::XYZ()) { if(geometry->getType() == XdmfGeometryType::XYZ()) {
currGrid->getGeometry()->getValues(2, z, num_nodes, 3); geometry->getValues(2, z, num_nodes, 3);
}
if(releaseGeometry) {
geometry->release();
} }
ex_put_coord(exodusHandle, x ,y ,z); ex_put_coord(exodusHandle, x ,y ,z);
delete [] x; delete [] x;
delete [] y; delete [] y;
delete [] z; delete [] z;
// Write Element block parameters // write element block parameters
std::string exodusTopologyType = std::string exodusTopologyType =
xdmfToExodusTopologyType(currGrid->getTopology()->getType()); xdmfToExodusTopologyType(currGrid->getTopology()->getType());
if (exodusTopologyType.compare("") == 0) {
// Topology Type not supported by ExodusII
XdmfError::message(XdmfError::FATAL, "Topology type not supported by ExodusII in XdmfExodusWriter::write");
}
ex_put_elem_block(exodusHandle, ex_put_elem_block(exodusHandle,
10, 10,
exodusTopologyType.c_str(), exodusTopologyType.c_str(),
...@@ -241,86 +424,28 @@ XdmfExodusWriter::write(const std::string & filePath, ...@@ -241,86 +424,28 @@ XdmfExodusWriter::write(const std::string & filePath,
currGrid->getTopology()->getType()->getNodesPerElement(), currGrid->getTopology()->getType()->getNodesPerElement(),
num_side_sets); num_side_sets);
// Write Element Connectivity // write element connectivity
shared_ptr<XdmfTopology> topology = currGrid->getTopology();
bool releaseTopology = false;
if(!topology->isInitialized()) {
topology->read();
releaseTopology = true;
}