Commit ea5dbd14 authored by Kenneth Leiter's avatar Kenneth Leiter

ENH: Add XdmfDiff to compare Xdmf files for equality.

parent 1c814a2d
......@@ -4,6 +4,7 @@ option(XDMF_BUILD_EXODUS_IO OFF)
option(XDMF_BUILD_PARTITIONER OFF)
set(XdmfUtilsSources
XdmfDiff
XdmfTopologyConverter)
set(XdmfUtilsLinkLibraries Xdmf)
......
/*****************************************************************************/
/* XDMF */
/* eXtensible Data Model and Format */
/* */
/* Id : XdmfDiff.cpp */
/* */
/* Author: */
/* Kenneth Leiter */
/* kenneth.leiter@arl.army.mil */
/* US Army Research Laboratory */
/* Aberdeen Proving Ground, MD */
/* */
/* Copyright @ 2011 US Army Research Laboratory */
/* All Rights Reserved */
/* See Copyright.txt for details */
/* */
/* This software is distributed WITHOUT ANY WARRANTY; without */
/* even the implied warranty of MERCHANTABILITY or FITNESS */
/* FOR A PARTICULAR PURPOSE. See the above copyright notice */
/* for more information. */
/* */
/*****************************************************************************/
#include <cmath>
#include <iomanip>
#include <iostream>
#include "XdmfArray.hpp"
#include "XdmfArrayType.hpp"
#include "XdmfDiff.hpp"
#include "XdmfVisitor.hpp"
//
// local methods
//
namespace {
/**
* @brief Internal class that traverses all items in xdmf hierarchy and
* adds them to mItems.
*/
class XdmfDiffVisitor : public XdmfVisitor {
public:
static shared_ptr<XdmfDiffVisitor>
New()
{
shared_ptr<XdmfDiffVisitor> p(new XdmfDiffVisitor());
return p;
};
~XdmfDiffVisitor()
{
};
void
visit(XdmfItem & item,
const shared_ptr<XdmfBaseVisitor> visitor)
{
mItems.push_back(&item);
item.traverse(visitor);
}
std::vector<XdmfItem *> mItems;
protected:
XdmfDiffVisitor()
{
}
};
template <typename T>
void
diffArrays(XdmfArray * array1,
XdmfArray * array2,
const double absoluteTolerance,
bool & returnValue) {
bool releaseArray1 = false;
if(!array1->isInitialized()) {
array1->read();
releaseArray1 = true;
}
bool releaseArray2 = false;
if(!array2->isInitialized()) {
array2->read();
releaseArray2 = true;
}
const unsigned int size = array1->getSize();
for(unsigned int i=0; i<size; ++i) {
const T array1Value = array1->getValue<T>(i);
const T array2Value = array2->getValue<T>(i);
const T difference =
static_cast<T>(std::fabs(array1Value - array2Value));
if(difference > absoluteTolerance) {
std::cout << "At Index " << i << " | Expected: "
<< array1Value << " | Got: " << array2Value << std::endl;
returnValue = false;
}
}
if(releaseArray1) {
array1->release();
}
if(releaseArray2) {
array2->release();
}
}
}
shared_ptr<XdmfDiff>
XdmfDiff::New()
{
shared_ptr<XdmfDiff> p(new XdmfDiff());
return p;
}
XdmfDiff::XdmfDiff() :
mAbsoluteTolerance(0.0)
{
}
XdmfDiff::~XdmfDiff()
{
}
bool
XdmfDiff::compare(const shared_ptr<XdmfItem> item1,
const shared_ptr<XdmfItem> item2) const
{
bool returnValue = true;
shared_ptr<XdmfDiffVisitor> diffVisitor1 = XdmfDiffVisitor::New();
shared_ptr<XdmfDiffVisitor> diffVisitor2 = XdmfDiffVisitor::New();
item1->accept(diffVisitor1);
item2->accept(diffVisitor2);
assert(diffVisitor1->mItems.size() == diffVisitor2->mItems.size());
std::vector<XdmfArray *>::size_type arrayOffset = 0;
for(std::vector<XdmfItem *>::size_type i=0;
i<diffVisitor1->mItems.size();
++i) {
XdmfItem * item1 = diffVisitor1->mItems[i];
XdmfItem * item2 = diffVisitor2->mItems[i];
// compare item tags
const std::string itemTag1 = item1->getItemTag();
const std::string itemTag2 = item2->getItemTag();
if(itemTag1.compare(itemTag2) != 0) {
std::cout << "Error: Expected " << itemTag1 << " and got " << itemTag2
<< ". The files are not structured the same" << std::endl;
return false;
}
// compare item properties
const std::map<std::string, std::string> itemProperties1 =
item1->getItemProperties();
const std::map<std::string, std::string> itemProperties2 =
item2->getItemProperties();
assert(itemProperties1.size() == itemProperties2.size());
for(std::map<std::string, std::string>::const_iterator iter1 =
itemProperties1.begin();
iter1 != itemProperties1.end();
++iter1) {
const std::string & key = iter1->first;
const std::map<std::string, std::string>::const_iterator iter2 =
itemProperties2.find(key);
if(iter2 == itemProperties2.end()) {
assert(false);
}
const std::string & value1 = iter1->second;
const std::string & value2 = iter2->second;
if(value1.compare(value2) != 0) {
std::cout << "Error: For: " << itemTag1 << " | Key: " << key
<< "Expected: " << value1 << " | Got: " << value2
<< std::endl;
returnValue = false;
}
}
// compare array values
XdmfArray * array1 = dynamic_cast<XdmfArray *>(item1);
if(array1) {
XdmfArray * array2 = dynamic_cast<XdmfArray *>(item2);
if(array1->getSize() != array2->getSize()) {
std::cout << "Error: For: " << itemTag1
<< " Different number of values stored. Expected: "
<< array1->getSize() << " | Got: " << array2->getSize()
<< std::endl;
returnValue = false;
}
const shared_ptr<const XdmfArrayType> arrayType =
array1->getArrayType();
if(arrayType != array2->getArrayType()) {
std::cout << "Error: For: " << itemTag1
<< " Different type of values stored. Expected: "
<< arrayType->getName() << " | Got: "
<< array2->getArrayType()->getName() << std::endl;
returnValue = false;
}
if(arrayType == XdmfArrayType::Int8()) {
diffArrays<char>(array1,
array2,
mAbsoluteTolerance,
returnValue);
}
else if(arrayType == XdmfArrayType::Int16()) {
diffArrays<short>(array1,
array2,
mAbsoluteTolerance,
returnValue);
}
else if(arrayType == XdmfArrayType::Int32()) {
diffArrays<int>(array1,
array2,
mAbsoluteTolerance,
returnValue);
}
else if(arrayType == XdmfArrayType::Int64()) {
diffArrays<long>(array1,
array2,
mAbsoluteTolerance,
returnValue);
}
else if(arrayType == XdmfArrayType::UInt8()) {
diffArrays<unsigned char>(array1,
array2,
mAbsoluteTolerance,
returnValue);
}
else if(arrayType == XdmfArrayType::UInt16()) {
diffArrays<unsigned short>(array1,
array2,
mAbsoluteTolerance,
returnValue);
}
else if(arrayType == XdmfArrayType::UInt32()) {
diffArrays<unsigned int>(array1,
array2,
mAbsoluteTolerance,
returnValue);
}
else if(arrayType == XdmfArrayType::Float32()) {
diffArrays<float>(array1,
array2,
mAbsoluteTolerance,
returnValue);
}
else if(arrayType == XdmfArrayType::Float64()) {
std::cout << std::setprecision(15);
diffArrays<double>(array1,
array2,
mAbsoluteTolerance,
returnValue);
}
else {
assert(false);
}
}
}
return returnValue;
}
double
XdmfDiff::getAbsoluteTolerance() const
{
return mAbsoluteTolerance;
}
void
XdmfDiff::setAbsoluteTolerance(const double absoluteTolerance)
{
mAbsoluteTolerance = absoluteTolerance;
}
/*****************************************************************************/
/* XDMF */
/* eXtensible Data Model and Format */
/* */
/* Id : XdmfDiff.hpp */
/* */
/* Author: */
/* Kenneth Leiter */
/* kenneth.leiter@arl.army.mil */
/* US Army Research Laboratory */
/* Aberdeen Proving Ground, MD */
/* */
/* Copyright @ 2011 US Army Research Laboratory */
/* All Rights Reserved */
/* See Copyright.txt for details */
/* */
/* This software is distributed WITHOUT ANY WARRANTY; without */
/* even the implied warranty of MERCHANTABILITY or FITNESS */
/* FOR A PARTICULAR PURPOSE. See the above copyright notice */
/* for more information. */
/* */
/*****************************************************************************/
#ifndef XDMFDIFF_HPP_
#define XDMFDIFF_HPP_
// Forward Declarations
class XdmfItem;
// Includes
#include <string>
#include "XdmfSharedPtr.hpp"
/**
* @brief Compare differences between data stored in two Xdmf
* structures.
*/
class XdmfDiff {
public:
/**
* Create a new XdmfDiff.
*
* @return constructed XdmfDiff.
*/
static shared_ptr<XdmfDiff> New();
virtual ~XdmfDiff();
/**
* Compare the contents of two Xdmf structures.
*
* @param item1 an Xdmf structure to compare.
* @param item2 an Xdmf structure to compare.
*
* @return true if the Xdmf structures are equivalent.
*/
bool
compare(const shared_ptr<XdmfItem> item1,
const shared_ptr<XdmfItem> item2) const;
/**
* Get the absolute tolerance used for comparing values between Xdmf
* structures.
*
* @return double the absolute tolerance.
*/
double
getAbsoluteTolerance() const;
/**
* Set the absolute tolerance for comparing values between Xdmf
* structures.
*
* @param absoluteTolerance the absolute tolerance to set.
*/
void
setAbsoluteTolerance(const double absoluteTolerance);
protected:
XdmfDiff();
private:
XdmfDiff(const XdmfDiff &); // Not implemented.
void operator=(const XdmfDiff &); // Not implemented.
double mAbsoluteTolerance;
};
#endif /* XDMFDIFF_HPP_ */
......@@ -21,6 +21,7 @@ swig -v -c++ -python -o XdmfUtilsPython.cpp XdmfUtils.i
#include <XdmfInformation.hpp>
#include <XdmfItem.hpp>
#include <XdmfItemProperty.hpp>
#include <XdmfSharedPtr.hpp>
#include <XdmfSystemUtils.hpp>
#include <XdmfVisitor.hpp>
#include <XdmfWriter.hpp>
......@@ -49,6 +50,7 @@ swig -v -c++ -python -o XdmfUtilsPython.cpp XdmfUtils.i
#include <XdmfUnstructuredGrid.hpp>
// XdmfUtils Includes
#include <XdmfDiff.hpp>
#include <XdmfExodusReader.hpp>
#include <XdmfExodusWriter.hpp>
#include <XdmfPartitioner.hpp>
......@@ -66,6 +68,7 @@ swig -v -c++ -python -o XdmfUtilsPython.cpp XdmfUtils.i
#endif /* SWIGPYTHON */
// Shared Pointer Templates
%shared_ptr(XdmfDiff)
#ifdef XDMF_BUILD_EXODUS_IO
%shared_ptr(XdmfExodusReader)
%shared_ptr(XdmfExodusWriter)
......@@ -75,6 +78,7 @@ swig -v -c++ -python -o XdmfUtilsPython.cpp XdmfUtils.i
#endif
%shared_ptr(XdmfTopologyConverter)
%include XdmfDiff.hpp
#ifdef XDMF_BUILD_EXODUS_IO
%include XdmfExodusReader.hpp
%include XdmfExodusWriter.hpp
......
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