Commit bc563cc9 authored by Utkarsh Ayachit's avatar Utkarsh Ayachit

Add support for composite datasets to vtkExtractTemporalFieldData.

vtkExtractTemporalFieldData poorly handled composite datasets, esp.
those generated by readers like vtkExodusIIReader. Added ability to the
filter to use only the 1st non-empty leaf node's field-data to produce
the output -- a more suitable solution for vtkExodusIIReader's output,
since vtkExodusIIReader duplicates global data on all leaf nodes.

Added a test, extractTemporalFieldData, that tests this filter along
with the new functionality.

Needed to address paraview/paraview#16100.
parent 6e113ad4
Pipeline #25994 passed with stage
vtk_add_test_python(
ExtractEdgesQuadraticCells.py
ExtractTensors.py
extractPolyData.py
extractRectGrid.py
extractTemporalFieldData.py,NO_RT,NO_VALID
ExtractTensors.py
extractUGrid.py
extractVectors.py
)
#!/usr/bin/env python
import vtk
from vtk.test import Testing
from vtk.util.misc import vtkGetDataRoot
VTK_DATA_ROOT = vtkGetDataRoot()
reader = vtk.vtkExodusIIReader()
reader.SetFileName(VTK_DATA_ROOT + "/Data/can.ex2")
reader.UpdateInformation()
for i in range(reader.GetNumberOfObjectArrays(reader.GLOBAL)):
name = reader.GetObjectArrayName(reader.GLOBAL, i)
reader.SetObjectArrayStatus(reader.GLOBAL, name, 1)
extractTFD = vtk.vtkExtractTemporalFieldData()
extractTFD.SetInputConnection(reader.GetOutputPort())
extractTFD.Update()
data = extractTFD.GetOutputDataObject(0)
assert data.IsA("vtkMultiBlockDataSet")
block = data.GetBlock(0).GetBlock(0)
assert block.IsA("vtkTable")
assert block.GetNumberOfRows() == reader.GetNumberOfTimeSteps()
assert block.GetNumberOfColumns() > 0
extractTFD.HandleCompositeDataBlocksIndividuallyOff()
extractTFD.Update()
data = extractTFD.GetOutputDataObject(0)
assert data.IsA("vtkTable")
assert data.GetNumberOfRows() == reader.GetNumberOfTimeSteps()
assert data.GetNumberOfColumns() > 0
......@@ -2,11 +2,12 @@ vtk_module(vtkFiltersExtraction
GROUPS
StandAlone
TEST_DEPENDS
vtkInteractionStyle
vtkIOExodus
vtkIOLegacy
vtkIOXML
vtkRendering${VTK_RENDERING_BACKEND}
vtkTestingRendering
vtkInteractionStyle
KIT
vtkFilters
DEPENDS
......@@ -17,4 +18,4 @@ vtk_module(vtkFiltersExtraction
vtkCommonDataModel
vtkFiltersCore
vtkFiltersStatistics
)
\ No newline at end of file
)
......@@ -14,44 +14,53 @@
=========================================================================*/
#include "vtkExtractTemporalFieldData.h"
#include "vtkCellData.h"
#include "vtkDataSet.h"
#include "vtkCompositeDataIterator.h"
#include "vtkDataSetAttributes.h"
#include "vtkDataSet.h"
#include "vtkDoubleArray.h"
#include "vtkIdTypeArray.h"
#include "vtkInformation.h"
#include "vtkInformationVector.h"
#include "vtkMultiBlockDataSet.h"
#include "vtkNew.h"
#include "vtkObjectFactory.h"
#include "vtkPointData.h"
#include "vtkTable.h"
#include "vtkSelection.h"
#include "vtkStreamingDemandDrivenPipeline.h"
#include "vtkUnsignedCharArray.h"
#include "vtkGenericCell.h"
#include "vtkStdString.h"
#include <vector>
#include "vtkTable.h"
#include <vector>
vtkStandardNewMacro(vtkExtractTemporalFieldData);
class vtkExtractTemporalFieldData::vtkInternals
{
public:
std::vector<double> TimeSteps;
};
vtkObjectFactoryNewMacro(vtkExtractTemporalFieldData);
//----------------------------------------------------------------------------
vtkExtractTemporalFieldData::vtkExtractTemporalFieldData()
{
this->NumberOfTimeSteps = 0;
this->Internals = new vtkExtractTemporalFieldData::vtkInternals();
this->HandleCompositeDataBlocksIndividually = true;
}
//----------------------------------------------------------------------------
vtkExtractTemporalFieldData::~vtkExtractTemporalFieldData()
{
delete this->Internals;
this->Internals = NULL;
}
//----------------------------------------------------------------------------
int vtkExtractTemporalFieldData::GetNumberOfTimeSteps()
{
return static_cast<int>(this->Internals->TimeSteps.size());
}
//----------------------------------------------------------------------------
void vtkExtractTemporalFieldData::PrintSelf(ostream& os, vtkIndent indent)
{
this->Superclass::PrintSelf(os,indent);
os << indent << "NumberOfTimeSteps: " << this->NumberOfTimeSteps << endl;
os << indent << "HandleCompositeDataBlocksIndividually: "
<< this->HandleCompositeDataBlocksIndividually << endl;
}
//----------------------------------------------------------------------------
......@@ -59,32 +68,35 @@ int vtkExtractTemporalFieldData::FillInputPortInformation(
int vtkNotUsed(port), vtkInformation* info)
{
info->Set(vtkAlgorithm::INPUT_REQUIRED_DATA_TYPE(), "vtkDataSet");
info->Append(vtkAlgorithm::INPUT_REQUIRED_DATA_TYPE(), "vtkCompositeDataSet");
return 1;
}
//----------------------------------------------------------------------------
int vtkExtractTemporalFieldData::ProcessRequest(
vtkInformation* request,
vtkInformationVector** inputVector,
vtkInformationVector* outputVector)
int vtkExtractTemporalFieldData::RequestDataObject(
vtkInformation*, vtkInformationVector** inputVector, vtkInformationVector* outputVector)
{
if(request->Has(vtkDemandDrivenPipeline::REQUEST_INFORMATION()))
vtkDataObject* input = vtkDataObject::GetData(inputVector[0], 0);
if (vtkCompositeDataSet::SafeDownCast(input) &&
this->HandleCompositeDataBlocksIndividually)
{
return this->RequestInformation(request, inputVector, outputVector);
if (vtkMultiBlockDataSet::GetData(outputVector, 0) == NULL)
{
vtkNew<vtkMultiBlockDataSet> mb;
outputVector->GetInformationObject(0)->Set(
vtkDataObject::DATA_OBJECT(), mb.Get());
}
}
else if(
request->Has(vtkStreamingDemandDrivenPipeline::REQUEST_DATA()))
else if (vtkTable::GetData(outputVector, 0) == NULL)
{
return this->RequestData(request,
inputVector,
outputVector);
vtkNew<vtkTable> table;
outputVector->GetInformationObject(0)->Set(
vtkDataObject::DATA_OBJECT(), table.Get());
}
return this->Superclass::ProcessRequest(request, inputVector, outputVector);
return 1;
}
//----------------------------------------------------------------------------
int vtkExtractTemporalFieldData::RequestInformation(
vtkInformation* vtkNotUsed(request),
......@@ -92,14 +104,18 @@ int vtkExtractTemporalFieldData::RequestInformation(
vtkInformationVector* outputVector)
{
vtkInformation *inInfo = inputVector[0]->GetInformationObject(0);
if ( inInfo->Has(vtkStreamingDemandDrivenPipeline::TIME_STEPS()) )
if (inInfo->Has(vtkStreamingDemandDrivenPipeline::TIME_STEPS()))
{
this->NumberOfTimeSteps =
inInfo->Length( vtkStreamingDemandDrivenPipeline::TIME_STEPS() );
int size = inInfo->Length(vtkStreamingDemandDrivenPipeline::TIME_STEPS());
this->Internals->TimeSteps.resize(size);
if (size > 0)
{
inInfo->Get(vtkStreamingDemandDrivenPipeline::TIME_STEPS(), &this->Internals->TimeSteps[0]);
}
}
else
{
this->NumberOfTimeSteps = 0;
this->Internals->TimeSteps.clear();
}
// The output of this filter does not contain a specific time, rather
......@@ -107,98 +123,107 @@ int vtkExtractTemporalFieldData::RequestInformation(
// respond to time requests. Therefore, we remove all time information
// from the output.
vtkInformation* outInfo = outputVector->GetInformationObject(0);
if (outInfo->Has(vtkStreamingDemandDrivenPipeline::TIME_STEPS()))
{
outInfo->Remove(vtkStreamingDemandDrivenPipeline::TIME_STEPS());
}
if (outInfo->Has(vtkStreamingDemandDrivenPipeline::TIME_RANGE()))
{
outInfo->Remove(vtkStreamingDemandDrivenPipeline::TIME_RANGE());
}
int wholeExtent[6] = {0, 0, 0, 0, 0, 0};
wholeExtent[1] = this->NumberOfTimeSteps - 1;
outInfo->Set(vtkStreamingDemandDrivenPipeline::WHOLE_EXTENT(),
wholeExtent, 6);
outInfo->Remove(vtkStreamingDemandDrivenPipeline::TIME_STEPS());
outInfo->Remove(vtkStreamingDemandDrivenPipeline::TIME_RANGE());
return 1;
}
//----------------------------------------------------------------------------
int vtkExtractTemporalFieldData::RequestData(
vtkInformation*,
vtkInformationVector** inputVector,
vtkInformationVector* outputVector)
{
if (this->NumberOfTimeSteps == 0)
if (this->GetNumberOfTimeSteps() == 0)
{
vtkErrorMacro("No time steps in input data!");
return 0;
}
// get the output data object
vtkInformation* outInfo = outputVector->GetInformationObject(0);
vtkTable *output = vtkTable::GetData(outInfo);
// get the input data object
vtkInformation* inInfo = inputVector[0]->GetInformationObject(0);
vtkDataSet *input = vtkDataSet::GetData(inInfo);
this->CopyDataToOutput(inInfo, input, output);
vtkDataObject* inputDO = vtkDataObject::GetData(inputVector[0], 0);
if (vtkCompositeDataSet* cd = vtkCompositeDataSet::SafeDownCast(inputDO))
{
vtkSmartPointer<vtkCompositeDataIterator> iter;
iter.TakeReference(cd->NewIterator());
if (this->HandleCompositeDataBlocksIndividually)
{
vtkMultiBlockDataSet* output = vtkMultiBlockDataSet::GetData(outputVector, 0);
assert(output);
output->CopyStructure(cd);
for (iter->InitTraversal(); !iter->IsDoneWithTraversal(); iter->GoToNextItem())
{
if (vtkDataSet* inputDS = vtkDataSet::SafeDownCast(iter->GetCurrentDataObject()))
{
vtkNew<vtkTable> outputBlock;
this->CopyDataToOutput(inputDS, outputBlock.Get());
output->SetDataSet(iter, outputBlock.Get());
}
}
}
else
{
vtkTable *output = vtkTable::GetData(outputVector, 0);
assert(output);
for (iter->InitTraversal(); !iter->IsDoneWithTraversal(); iter->GoToNextItem())
{
if (vtkDataSet* inputDS = vtkDataSet::SafeDownCast(iter->GetCurrentDataObject()))
{
if (this->CopyDataToOutput(inputDS, output))
{
break;
}
}
}
}
}
else if (vtkDataSet* input = vtkDataSet::SafeDownCast(inputDO))
{
vtkTable *output = vtkTable::GetData(outputVector, 0);
this->CopyDataToOutput(input, output);
}
else
{
vtkErrorMacro("Incorrect input type.");
return 0;
}
return 1;
}
//----------------------------------------------------------------------------
void vtkExtractTemporalFieldData::CopyDataToOutput(
vtkInformation* inInfo,
vtkDataSet *input, vtkTable *output)
bool vtkExtractTemporalFieldData::CopyDataToOutput(vtkDataSet *input, vtkTable *output)
{
vtkDataSetAttributes *opd = output->GetRowData();
vtkDataSetAttributes *outRowData = output->GetRowData();
vtkFieldData *ifd = input->GetFieldData();
int numArrays = 0;
if(!ifd || !opd)
if (!ifd || !outRowData)
{
vtkErrorMacro("Unsupported field type.");
return;
return false;
}
int numTimeSteps = this->GetNumberOfTimeSteps();
assert(numTimeSteps > 0);
for (vtkIdType j=0; j<ifd->GetNumberOfArrays(); j++)
{
vtkDataArray* inFieldArray = ifd->GetArray(j);
if (inFieldArray &&
inFieldArray->GetName() &&
!inFieldArray->IsA("vtkIdTypeArray") &&
inFieldArray->GetNumberOfTuples() == this->NumberOfTimeSteps)
inFieldArray->GetNumberOfTuples() == numTimeSteps)
{
vtkDataArray *outPointArray = vtkDataArray::CreateDataArray(inFieldArray->GetDataType());
//outPointArray->DeepCopy(inFieldArray);
outPointArray->SetNumberOfComponents(inFieldArray->GetNumberOfComponents());
outPointArray->SetNumberOfTuples(this->NumberOfTimeSteps);
for(vtkIdType i=0; i<inFieldArray->GetNumberOfComponents(); i++)
{
outPointArray->CopyComponent(i,inFieldArray,i);
}
outPointArray->SetName(inFieldArray->GetName());
opd->AddArray(outPointArray);
outPointArray->Delete();
numArrays++;
vtkDataArray *outArray = inFieldArray->NewInstance();
outArray->ShallowCopy(inFieldArray);
outRowData->AddArray(outArray);
outArray->Delete();
}
}
double *timesteps = NULL;
if ( inInfo->Has(vtkStreamingDemandDrivenPipeline::TIME_STEPS()) )
if (outRowData->GetNumberOfArrays() == 0)
{
timesteps = inInfo->Get(vtkStreamingDemandDrivenPipeline::TIME_STEPS());
return false;
}
// Add an array to hold the time at each step
vtkDoubleArray *timeArray = vtkDoubleArray::New();
vtkNew<vtkDoubleArray> timeArray;
timeArray->SetNumberOfComponents(1);
timeArray->SetNumberOfTuples(this->NumberOfTimeSteps);
timeArray->SetNumberOfTuples(numTimeSteps);
if (ifd->GetArray("Time"))
{
timeArray->SetName("TimeData");
......@@ -207,25 +232,8 @@ void vtkExtractTemporalFieldData::CopyDataToOutput(
{
timeArray->SetName("Time");
}
for(int m=0; m<this->NumberOfTimeSteps; m++)
{
timeArray->SetTuple1(m, timesteps[m]);
}
opd->AddArray(timeArray);
timeArray->Delete();
// This array is used to make particular samples as invalid.
// This happens when we are looking at a location which is not contained
// by a cell or at a cell or point id that is destroyed.
// It is used in the parallel subclass as well.
vtkUnsignedCharArray* validPts = vtkUnsignedCharArray::New();
validPts->SetName("vtkValidPointMask");
validPts->SetNumberOfTuples(this->NumberOfTimeSteps);
opd->AddArray(validPts);
// if no valid field arrays were found, which would happen if the reader
// did not have the requested data, set validity to 0, otherwise 1.
int validity = numArrays ? 1 : 0;
validPts->FillComponent(0,validity);
validPts->Delete();
std::copy(this->Internals->TimeSteps.begin(), this->Internals->TimeSteps.end(),
timeArray->GetPointer(0));
outRowData->AddArray(timeArray.Get());
return true;
}
......@@ -17,11 +17,19 @@
// vtkExtractTemporalFieldData extracts arrays from the input vtkFieldData.
// These arrays are assumed to contain temporal data, where the nth tuple
// contains the value for the nth timestep.
// The output is a 1D rectilinear grid where the
// XCoordinates correspond to time (the same array is also copied to
// a point array named Time or TimeData (if Time exists in the input).
//
// For composite datasets, the filter has two modes, it can treat each block in
// the dataset individually (default) or just look at the first non-empty field data
// (common for readers vtkExodusIIReader). For latter, set
// HandleCompositeDataBlocksIndividually to false.
//
// The output is a vtkTable (or a multiblock of vtkTables) based of whether
// HandleCompositeDataBlocksIndividually is true and input is a composite
// dataset.
//
// This algorithm does not produce a TIME_STEPS or TIME_RANGE information
// because it works across time.
//
// .Section Caveat
// This algorithm works only with source that produce TIME_STEPS().
// Continuous time range is not yet supported.
......@@ -30,55 +38,59 @@
#define vtkExtractTemporalFieldData_h
#include "vtkFiltersExtractionModule.h" // For export macro
#include "vtkTableAlgorithm.h"
#include "vtkDataObjectAlgorithm.h"
class vtkDataSet;
class vtkTable;
class vtkDataSetAttributes;
class VTKFILTERSEXTRACTION_EXPORT vtkExtractTemporalFieldData : public vtkTableAlgorithm
class VTKFILTERSEXTRACTION_EXPORT vtkExtractTemporalFieldData : public vtkDataObjectAlgorithm
{
public:
static vtkExtractTemporalFieldData *New();
vtkTypeMacro(vtkExtractTemporalFieldData,vtkTableAlgorithm);
vtkTypeMacro(vtkExtractTemporalFieldData,vtkDataObjectAlgorithm);
void PrintSelf(ostream& os, vtkIndent indent);
// Description:
// Get the number of time steps
vtkGetMacro(NumberOfTimeSteps,int);
int GetNumberOfTimeSteps();
// Description:
// When set to true (default), if the input is a vtkCompositeDataSet, then
// each block in the input dataset in processed separately. If false, then the first
// non-empty FieldData is considered.
vtkSetMacro(HandleCompositeDataBlocksIndividually, bool);
vtkGetMacro(HandleCompositeDataBlocksIndividually, bool);
vtkBooleanMacro(HandleCompositeDataBlocksIndividually, bool);
protected:
vtkExtractTemporalFieldData();
~vtkExtractTemporalFieldData();
virtual int ProcessRequest(vtkInformation*,
vtkInformationVector**,
vtkInformationVector*);
virtual int RequestInformation(vtkInformation* request,
vtkInformationVector** inputVector,
vtkInformationVector* outputVector);
virtual int RequestData(vtkInformation* request,
vtkInformationVector** inputVector,
vtkInformationVector* outputVector);
virtual int FillInputPortInformation(int port, vtkInformation* info);
int RequestDataObject(vtkInformation*,
vtkInformationVector**,
vtkInformationVector*) VTK_OVERRIDE;
int RequestInformation(vtkInformation* request,
vtkInformationVector** inputVector,
vtkInformationVector* outputVector) VTK_OVERRIDE;
int RequestData(vtkInformation* request,
vtkInformationVector** inputVector,
vtkInformationVector* outputVector) VTK_OVERRIDE;
int FillInputPortInformation(int port, vtkInformation* info) VTK_OVERRIDE;
// Description:
// This looks at the arrays in the vtkFieldData of input and copies them
// to the output point data.
void CopyDataToOutput(vtkInformation* inInfo,
vtkDataSet *input, vtkTable *output);
int NumberOfTimeSteps;
// Returns true if the input had an "appropriate" field data.
bool CopyDataToOutput(vtkDataSet *input, vtkTable *output);
bool HandleCompositeDataBlocksIndividually;
private:
vtkExtractTemporalFieldData(const vtkExtractTemporalFieldData&) VTK_DELETE_FUNCTION;
void operator=(const vtkExtractTemporalFieldData&) VTK_DELETE_FUNCTION;
class vtkInternals;
vtkInternals* Internals;
};
#endif
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