Commit 4b7c680c authored by Utkarsh Ayachit's avatar Utkarsh Ayachit
Browse files

Fixing XML reader/writer for AMR datasets.

Adding new classes vtkXMLUniformGridAMRDataWriter /
vtkXMLPUniformGridAMRDataWriter based on vtkXMLHierarchicalBoxDataWriter /
vtkXMLPHierarchicalBoxDataWriter to write all types of AMR datasets in VTK XML
format. vtkXMLHierarchicalBoxDataWriter and vtkXMLPHierarchicalBoxDataWriter are
now simply empty subclasses for backwards compatibility.

The XML file format had to be extended to write enough meta-data to support
loading of Overlapping AMR datasets correctly. Consequently, the version number
was updated to 1.1.

Adding vtkXMLUniformGridAMRReader for reading VTK XML files for AMR datasets
(overlapping and nonoverlapping). Also added a new test TestAMRXMLIO.
vtkXMLUniformGridAMRReader reader v1.1. For older versions, added a converter
vtkXMLHierarchicalBoxDataFileConverter (and a test) that converts the xml to the
new format. vtkXMLUniformGridAMRReader provides appropriate meta-data in
RequestInformation() pass, similar to other AMR reader such as Flash/Enzo.

...
parent 50a963e5
......@@ -34,9 +34,9 @@
#include "vtkUniformGrid.h"
#include "vtkUniformGrid.h"
#include "vtkXMLHierarchicalBoxDataReader.h"
#include "vtkXMLHierarchicalBoxDataWriter.h"
#include "vtkXMLImageDataWriter.h"
#include "vtkXMLMultiBlockDataWriter.h"
#include "vtkXMLUniformGridAMRWriter.h"
namespace AMRCommon {
......
......@@ -10,6 +10,7 @@ set(Module_SRCS
vtkWindBladeReader.cxx
vtkXMLPHierarchicalBoxDataWriter.cxx
vtkXMLPMultiBlockDataWriter.cxx
vtkXMLPUniformGridAMRWriter.cxx
)
vtk_module_library(vtkIOParallel ${Module_SRCS})
......@@ -14,128 +14,23 @@
=========================================================================*/
#include "vtkXMLPHierarchicalBoxDataWriter.h"
#include "vtkMultiProcessController.h"
#include "vtkObjectFactory.h"
#include "assert.h"
//----------------------------------------------------------------------------
vtkStandardNewMacro(vtkXMLPHierarchicalBoxDataWriter);
vtkCxxSetObjectMacro(vtkXMLPHierarchicalBoxDataWriter,
Controller,
vtkMultiProcessController);
//----------------------------------------------------------------------------
vtkXMLPHierarchicalBoxDataWriter::vtkXMLPHierarchicalBoxDataWriter()
{
this->Controller = 0;
this->SetController(vtkMultiProcessController::GetGlobalController());
this->vtkXMLPHierarchicalBoxDataWriter::SetWriteMetaFile(1);
}
//----------------------------------------------------------------------------
vtkXMLPHierarchicalBoxDataWriter::~vtkXMLPHierarchicalBoxDataWriter()
{
this->SetController(0);
}
//----------------------------------------------------------------------------
void vtkXMLPHierarchicalBoxDataWriter::PrintSelf(ostream& os, vtkIndent indent)
{
this->Superclass::PrintSelf(os, indent);
os << indent << "Controller: ";
if (this->Controller)
{
this->Controller->PrintSelf(os, indent.GetNextIndent());
}
else
{
os << "(none)" << endl;
}
}
//----------------------------------------------------------------------------
void vtkXMLPHierarchicalBoxDataWriter::SetWriteMetaFile(int flag)
{
this->Modified();
if(this->Controller == NULL || this->Controller->GetLocalProcessId() == 0)
{
if(this->WriteMetaFile != flag)
{
this->WriteMetaFile = flag;
}
}
else
{
this->WriteMetaFile = 0;
}
}
//----------------------------------------------------------------------------
void vtkXMLPHierarchicalBoxDataWriter::FillDataTypes(
vtkCompositeDataSet* cdInput)
{
this->Superclass::FillDataTypes(cdInput);
if (!this->Controller )
{
return;
}
int myid = this->Controller->GetLocalProcessId();
int numProcs = this->Controller->GetNumberOfProcesses();
unsigned int numLeafNodes = this->GetNumberOfDataTypes();
int* myDataTypes = this->GetDataTypesPointer();
if (numProcs == 1 || numLeafNodes == 0)
{
return;
}
// Collect information about amr-boxes (we don't need to gather refinement
// ratio informations since those are certainly consistent on all processes
// since we expect the same composite structure on all nodes.
assert(this->AMRBoxes != NULL);
if (myid == 0)
{
int *gathered_data_types = new int [numLeafNodes*numProcs];
for (unsigned int cc=0; cc < numProcs*numLeafNodes; cc++)
{
gathered_data_types[cc] = -1;
}
this->Controller->Gather(myDataTypes,
gathered_data_types, numLeafNodes, 0);
int *gathered_amx_box_dims = new int [numLeafNodes*6*numProcs];
memset(gathered_amx_box_dims, 0, numLeafNodes*6*numProcs*sizeof(int));
this->Controller->Gather(this->AMRBoxes, gathered_amx_box_dims,
numLeafNodes*6, 0);
for (int procNo=1; procNo<numProcs; procNo++)
{
for (unsigned int pieceNo=0; pieceNo<numLeafNodes; pieceNo++)
{
if (myDataTypes[pieceNo] == -1 &&
gathered_data_types[procNo*numLeafNodes+pieceNo] >= 0)
{
myDataTypes[pieceNo] =
gathered_data_types[procNo*numLeafNodes + pieceNo];
memcpy(&this->AMRBoxes[pieceNo*6],
&gathered_amx_box_dims[(procNo*numLeafNodes + pieceNo)*6],
sizeof(int)*6);
}
}
}
delete[] gathered_data_types;
delete[] gathered_amx_box_dims;
}
else
{
this->Controller->Gather(myDataTypes, NULL, numLeafNodes, 0);
this->Controller->Gather(this->AMRBoxes, NULL, numLeafNodes*6, 0);
}
}
......@@ -13,59 +13,31 @@
=========================================================================*/
// .NAME vtkXMLPHierarchicalBoxDataWriter - parallel writer for
// vtkHierarchicalBoxDataSet.
// vtkHierarchicalBoxDataSet for backwards compatibility.
// .SECTION Description
// vtkXMLPCompositeDataWriter writes (in parallel or serially) the VTK XML
// multi-group, multi-block hierarchical and hierarchical box files. XML
// multi-group data files are meta-files that point to a list of serial VTK
// XML files.
// vtkXMLPHierarchicalBoxDataWriter is an empty subclass of
// vtkXMLPUniformGridAMRWriter for backwards compatibility.
#ifndef __vtkXMLPHierarchicalBoxDataWriter_h
#define __vtkXMLPHierarchicalBoxDataWriter_h
#include "vtkIOParallelModule.h" // For export macro
#include "vtkXMLHierarchicalBoxDataWriter.h"
#include "vtkXMLPUniformGridAMRWriter.h"
class vtkMultiProcessController;
class VTKIOPARALLEL_EXPORT vtkXMLPHierarchicalBoxDataWriter : public vtkXMLHierarchicalBoxDataWriter
class VTKIOPARALLEL_EXPORT vtkXMLPHierarchicalBoxDataWriter :
public vtkXMLPUniformGridAMRWriter
{
public:
static vtkXMLPHierarchicalBoxDataWriter* New();
vtkTypeMacro(vtkXMLPHierarchicalBoxDataWriter, vtkXMLHierarchicalBoxDataWriter);
vtkTypeMacro(vtkXMLPHierarchicalBoxDataWriter, vtkXMLPUniformGridAMRWriter);
void PrintSelf(ostream& os, vtkIndent indent);
// Description:
// Controller used to communicate data type of blocks.
// By default, the global controller is used. If you want another
// controller to be used, set it with this.
// If no controller is set, only the local blocks will be written
// to the meta-file.
virtual void SetController(vtkMultiProcessController*);
vtkGetObjectMacro(Controller, vtkMultiProcessController);
// Description:
// Set whether this instance will write the meta-file. WriteMetaFile
// is set to flag only on process 0 and all other processes have
// WriteMetaFile set to 0 by default.
virtual void SetWriteMetaFile(int flag);
//BTX
protected:
vtkXMLPHierarchicalBoxDataWriter();
~vtkXMLPHierarchicalBoxDataWriter();
virtual void FillDataTypes(vtkCompositeDataSet*);
vtkMultiProcessController* Controller;
private:
vtkXMLPHierarchicalBoxDataWriter(const vtkXMLPHierarchicalBoxDataWriter&); // Not implemented.
void operator=(const vtkXMLPHierarchicalBoxDataWriter&); // Not implemented.
//ETX
};
#endif
/*=========================================================================
Program: Visualization Toolkit
Module: vtkXMLPUniformGridAMRWriter.cxx
Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
All rights reserved.
See Copyright.txt or http://www.kitware.com/Copyright.htm 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 "vtkXMLPUniformGridAMRWriter.h"
#include "vtkMultiProcessController.h"
#include "vtkObjectFactory.h"
#include "assert.h"
//----------------------------------------------------------------------------
vtkStandardNewMacro(vtkXMLPUniformGridAMRWriter);
vtkCxxSetObjectMacro(vtkXMLPUniformGridAMRWriter,
Controller,
vtkMultiProcessController);
//----------------------------------------------------------------------------
vtkXMLPUniformGridAMRWriter::vtkXMLPUniformGridAMRWriter()
{
this->Controller = 0;
this->SetController(vtkMultiProcessController::GetGlobalController());
// this should be called after the controller is set.
this->SetWriteMetaFile(1);
}
//----------------------------------------------------------------------------
vtkXMLPUniformGridAMRWriter::~vtkXMLPUniformGridAMRWriter()
{
this->SetController(0);
}
//----------------------------------------------------------------------------
void vtkXMLPUniformGridAMRWriter::PrintSelf(ostream& os, vtkIndent indent)
{
this->Superclass::PrintSelf(os, indent);
os << indent << "Controller: ";
if (this->Controller)
{
this->Controller->PrintSelf(os, indent.GetNextIndent());
}
else
{
os << "(none)" << endl;
}
}
//----------------------------------------------------------------------------
void vtkXMLPUniformGridAMRWriter::SetWriteMetaFile(int flag)
{
this->Modified();
if(this->Controller == NULL || this->Controller->GetLocalProcessId() == 0)
{
if(this->WriteMetaFile != flag)
{
this->WriteMetaFile = flag;
}
}
else
{
this->WriteMetaFile = 0;
}
}
//----------------------------------------------------------------------------
void vtkXMLPUniformGridAMRWriter::FillDataTypes(
vtkCompositeDataSet* cdInput)
{
this->Superclass::FillDataTypes(cdInput);
if (!this->Controller )
{
return;
}
int myid = this->Controller->GetLocalProcessId();
int numProcs = this->Controller->GetNumberOfProcesses();
unsigned int numLeafNodes = this->GetNumberOfDataTypes();
int* myDataTypes = this->GetDataTypesPointer();
if (numProcs == 1 || numLeafNodes == 0)
{
return;
}
if (myid == 0)
{
// Collect information about data-types from all satellites and the
// "combine" the information. Only the root-node needs to have the
// combined information, since only the root-node writes the XML.
int *gathered_data_types = new int [numLeafNodes*numProcs];
for (unsigned int cc=0; cc < numProcs*numLeafNodes; cc++)
{
gathered_data_types[cc] = -1;
}
this->Controller->Gather(myDataTypes,
gathered_data_types, numLeafNodes, 0);
for (int procNo=1; procNo<numProcs; procNo++)
{
for (unsigned int pieceNo=0; pieceNo<numLeafNodes; pieceNo++)
{
if (myDataTypes[pieceNo] == -1 &&
gathered_data_types[procNo*numLeafNodes+pieceNo] >= 0)
{
myDataTypes[pieceNo] =
gathered_data_types[procNo*numLeafNodes + pieceNo];
}
}
}
delete[] gathered_data_types;
}
else
{
this->Controller->Gather(myDataTypes, NULL, numLeafNodes, 0);
}
}
/*=========================================================================
Program: Visualization Toolkit
Module: vtkXMLPUniformGridAMRWriter.h
Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
All rights reserved.
See Copyright.txt or http://www.kitware.com/Copyright.htm 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.
=========================================================================*/
// .NAME vtkXMLPUniformGridAMRWriter - parallel writer for
// vtkUniformGridAMR and subclasses.
// .SECTION Description
// vtkXMLPCompositeDataWriter writes (in parallel or serially) vtkUniformGridAMR
// and subclasses. When running in parallel all processes are expected to have
// the same meta-data (i.e. amr-boxes, structure, etc.) however they may now
// have the missing data-blocks. This class extends
// vtkXMLUniformGridAMRWriter to communicate information about data blocks
// to the root node so that the root node can write the XML file describing the
// structure correctly.
#ifndef __vtkXMLPUniformGridAMRWriter_h
#define __vtkXMLPUniformGridAMRWriter_h
#include "vtkIOParallelModule.h" // For export macro
#include "vtkXMLUniformGridAMRWriter.h"
class vtkMultiProcessController;
class VTKIOPARALLEL_EXPORT vtkXMLPUniformGridAMRWriter : public vtkXMLUniformGridAMRWriter
{
public:
static vtkXMLPUniformGridAMRWriter* New();
vtkTypeMacro(vtkXMLPUniformGridAMRWriter, vtkXMLUniformGridAMRWriter);
void PrintSelf(ostream& os, vtkIndent indent);
// Description:
// Controller used to communicate data type of blocks.
// By default, the global controller is used. If you want another
// controller to be used, set it with this.
// If no controller is set, only the local blocks will be written
// to the meta-file.
virtual void SetController(vtkMultiProcessController*);
vtkGetObjectMacro(Controller, vtkMultiProcessController);
// Description:
// Set whether this instance will write the meta-file. WriteMetaFile
// is set to flag only on process 0 and all other processes have
// WriteMetaFile set to 0 by default.
virtual void SetWriteMetaFile(int flag);
//BTX
protected:
vtkXMLPUniformGridAMRWriter();
~vtkXMLPUniformGridAMRWriter();
// Description:
// Overridden to reduce information about data-types across all processes.
virtual void FillDataTypes(vtkCompositeDataSet*);
vtkMultiProcessController* Controller;
private:
vtkXMLPUniformGridAMRWriter(const vtkXMLPUniformGridAMRWriter&); // Not implemented.
void operator=(const vtkXMLPUniformGridAMRWriter&); // Not implemented.
//ETX
};
#endif
......@@ -6,6 +6,7 @@ set(Module_SRCS
vtkXMLDataSetWriter.cxx
vtkXMLFileReadTester.cxx
vtkXMLGenericDataObjectReader.cxx
vtkXMLHierarchicalBoxDataFileConverter.cxx
vtkXMLHierarchicalBoxDataReader.cxx
vtkXMLHierarchicalBoxDataWriter.cxx
vtkXMLHierarchicalDataReader.cxx
......@@ -42,6 +43,8 @@ set(Module_SRCS
vtkXMLStructuredDataWriter.cxx
vtkXMLStructuredGridReader.cxx
vtkXMLStructuredGridWriter.cxx
vtkXMLUniformGridAMRReader.cxx
vtkXMLUniformGridAMRWriter.cxx
vtkXMLUnstructuredDataReader.cxx
vtkXMLUnstructuredDataWriter.cxx
vtkXMLUnstructuredGridReader.cxx
......
create_test_sourcelist(Tests ${vtk-module}CxxTests.cxx
TestAMRXMLIO.cxx
TestDataObjectXMLIO.cxx
TestXML.cxx
TestXMLHierarchicalBoxDataFileConverter.cxx
EXTRA_INCLUDE vtkTestDriver.h
)
......
#include "vtkAMRGaussianPulseSource.h"
#include "vtkNew.h"
#include "vtkNonOverlappingAMR.h"
#include "vtkOverlappingAMR.h"
#include "vtkTestUtilities.h"
#include "vtkXMLGenericDataObjectReader.h"
#include "vtkXMLUniformGridAMRReader.h"
#include "vtkXMLUniformGridAMRWriter.h"
#include "vtkStructuredData.h"
#include <string>
namespace
{
#define vtk_assert(x)\
if (! (x) ) { cerr << "ERROR: Condition FAILED!! : " << #x << endl; return false;}
bool Validate(vtkOverlappingAMR* input, vtkOverlappingAMR* result)
{
vtk_assert(input->GetNumberOfLevels() == result->GetNumberOfLevels());
vtk_assert(input->GetOrigin()[0] == result->GetOrigin()[0]);
vtk_assert(input->GetOrigin()[1] == result->GetOrigin()[1]);
vtk_assert(input->GetOrigin()[2] == result->GetOrigin()[2]);
for (unsigned int level=0; level < input->GetNumberOfLevels(); level++)
{
vtk_assert(input->GetNumberOfDataSets(level) ==
result->GetNumberOfDataSets(level));
}
cout << "Audit Input" << endl;
input->Audit();
cout << "Audit Output" << endl;
result->Audit();
return true;
}
bool TestAMRXMLIO_OverlappingAMR2D(std::string output_dir)
{
vtkNew<vtkAMRGaussianPulseSource> pulse;
pulse->SetDimension(2);
pulse->SetRootSpacing(5);
std::string filename = output_dir + "/TestAMRXMLIO_OverlappingAMR2D.vth";
vtkNew<vtkXMLUniformGridAMRWriter> writer;
writer->SetInputConnection(pulse->GetOutputPort());
writer->SetFileName(filename.c_str());
writer->Write();
vtkNew<vtkXMLGenericDataObjectReader> reader;
reader->SetFileName(filename.c_str());
reader->Update();
return Validate(vtkOverlappingAMR::SafeDownCast(
pulse->GetOutputDataObject(0)),
vtkOverlappingAMR::SafeDownCast(reader->GetOutputDataObject(0)));
}
bool TestAMRXMLIO_OverlappingAMR3D(std::string output_dir)
{
vtkNew<vtkAMRGaussianPulseSource> pulse;
pulse->SetDimension(3);
pulse->SetRootSpacing(13);
std::string filename = output_dir + "/TestAMRXMLIO_OverlappingAMR3D.vth";
vtkNew<vtkXMLUniformGridAMRWriter> writer;
writer->SetInputConnection(pulse->GetOutputPort());
writer->SetFileName(filename.c_str());
writer->Write();
vtkNew<vtkXMLGenericDataObjectReader> reader;
reader->SetFileName(filename.c_str());
reader->Update();
return Validate(vtkOverlappingAMR::SafeDownCast(
pulse->GetOutputDataObject(0)),
vtkOverlappingAMR::SafeDownCast(reader->GetOutputDataObject(0)));
}
bool TestAMRXMLIO_HierarchicalBox(
const std::string& input_dir, const std::string &output_dir)
{
std::string filename = input_dir + "/AMR/HierarchicalBoxDataset.v1.1.vthb";
// for vtkHierarchicalBoxDataSet, vtkXMLGenericDataObjectReader creates the
// legacy reader by default. For version 1.1, we should use the
// vtkXMLUniformGridAMRReader explicitly. vtkHierarchicalBoxDataSet itself is
// obsolete.
vtkNew<vtkXMLUniformGridAMRReader> reader;
reader->SetFileName(filename.c_str());
reader->Update();
vtkOverlappingAMR* output = vtkOverlappingAMR::SafeDownCast(
reader->GetOutputDataObject(0));
vtk_assert(output->GetNumberOfLevels() == 4);
vtk_assert(output->GetNumberOfDataSets(0) == 1);
vtk_assert(output->GetNumberOfDataSets(1) == 8);
vtk_assert(output->GetNumberOfDataSets(2) == 40);
vtk_assert(output->GetNumberOfDataSets(3) == 32);
vtk_assert(output->GetGridDescription() == VTK_XYZ_GRID);
output->Audit();
filename = output_dir + "/TestAMRXMLIO_HierarchicalBox.vth";
vtkNew<vtkXMLUniformGridAMRWriter> writer;
writer->SetFileName(filename.c_str());
writer->SetInputDataObject(output);
writer->Write();
vtkNew<vtkXMLUniformGridAMRReader> reader2;
reader2->SetFileName(filename.c_str());
reader2->Update();
return Validate(output,
vtkOverlappingAMR::SafeDownCast(reader2->GetOutputDataObject(0)));
}
}
#define VTK_SUCCESS 0
#define VTK_FAILURE 1
int TestAMRXMLIO(int argc, char*argv[])
{
char* temp_dir = vtkTestUtilities::GetArgOrEnvOrDefault(
"-T", argc, argv, "VTK_TEMP_DIR", "Testing/Temporary");
if (!temp_dir)
{
cerr << "Could not determine temporary directory." << endl;
return VTK_FAILURE;
}
std::string output_dir = temp_dir;
delete [] temp_dir;
cout << "Test Overlapping AMR (2D)" << endl;
if (!TestAMRXMLIO_OverlappingAMR2D(output_dir))
{
return VTK_FAILURE;
}
cout << "Test Overlapping AMR (3D)" << endl;
if (!TestAMRXMLIO_OverlappingAMR3D(output_dir))
{
return VTK_FAILURE;
}
char* data_dir = vtkTestUtilities::GetDataRoot(argc, argv);
if (!data_dir)
{
cerr << "Could not determine data directory." << endl;
return VTK_FAILURE;
}
std::string input_dir = data_dir;
input_dir += "/Data";
delete [] data_dir;
cout << "Test HierarchicalBox AMR (v1.1)" << endl;
if (!TestAMRXMLIO_HierarchicalBox(input_dir, output_dir))
{
return VTK_FAILURE;
}
return VTK_SUCCESS;