Commit 6d9117d2 authored by Berk Geveci's avatar Berk Geveci

New simplified interface for developing reader.

The goal of this branch is to introduce a new hierarchy
of reader superclasses that make it easier to develop readers
by implementing / hiding some of the common functionality readers
have. This includes things such as file series as time series,
file series as partitions, caching etc. In collaboration with
a new executive (vtkReaderExecutive), the reader superclasses
implement much of the hard work and provide a simple API for the
subclasses to implement. For example, a parallel reader may
only have to implement 3 methods: GetMesh(), GetPoints() and
GetArrays() to get support for file series as time series and
caching (not implemented yet). This functionality is demonstrated
by making the Plot3D reader subclass from the new superclass.
The testing is automatic since there are numerous tests using
Plot3D files.
parent 39f1798c
......@@ -31,11 +31,14 @@ SET(Module_SRCS
vtkMoleculeAlgorithm.cxx
vtkMultiBlockDataSetAlgorithm.cxx
vtkMultiTimeStepAlgorithm.cxx
vtkParallelReader.cxx
vtkPassInputTypeAlgorithm.cxx
vtkPiecewiseFunctionAlgorithm.cxx
vtkPiecewiseFunctionShiftScale.cxx
vtkPointSetAlgorithm.cxx
vtkPolyDataAlgorithm.cxx
vtkReaderAlgorithm.cxx
vtkReaderExecutive.cxx
vtkRectilinearGridAlgorithm.cxx
vtkScalarTree.cxx
vtkSimpleImageToImageFilter.cxx
......
/*=========================================================================
Program: Visualization Toolkit
Module: vtkParallelReader.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 "vtkParallelReader.h"
#include "vtkInformation.h"
#include "vtkMath.h"
#include "vtkObjectFactory.h"
#include "vtkStreamingDemandDrivenPipeline.h"
#include <vector>
#include <numeric>
struct vtkParallelReaderInternal
{
using FileNamesType = std::vector<std::string>;
FileNamesType FileNames;
};
//----------------------------------------------------------------------------
vtkParallelReader::vtkParallelReader()
{
this->Internal = new vtkParallelReaderInternal;
this->CurrentFileIndex = -1;
}
//----------------------------------------------------------------------------
vtkParallelReader::~vtkParallelReader()
{
delete this->Internal;
}
//----------------------------------------------------------------------------
void vtkParallelReader::PrintSelf(ostream& os, vtkIndent indent)
{
this->Superclass::PrintSelf(os, indent);
}
//----------------------------------------------------------------------------
void vtkParallelReader::AddFileName(const char* fname)
{
if(fname == nullptr || strlen(fname) == 0)
{
return;
}
this->Internal->FileNames.push_back(fname);
this->Modified();
}
//----------------------------------------------------------------------------
void vtkParallelReader::ClearFileNames()
{
this->Internal->FileNames.clear();
this->Modified();
}
//----------------------------------------------------------------------------
int vtkParallelReader::GetNumberOfFileNames() const
{
return static_cast<int>(this->Internal->FileNames.size());
}
//----------------------------------------------------------------------------
const char* vtkParallelReader::GetFileName(int i) const
{
return this->Internal->FileNames[i].c_str();
}
//----------------------------------------------------------------------------
const char* vtkParallelReader::GetCurrentFileName() const
{
if (this->CurrentFileIndex < 0 ||
this->CurrentFileIndex >= (int)this->Internal->FileNames.size())
{
return nullptr;
}
return this->Internal->FileNames[this->CurrentFileIndex].c_str();
}
//----------------------------------------------------------------------------
int vtkParallelReader::ReadMetaData(vtkInformation* metadata)
{
metadata->Set(vtkAlgorithm::CAN_HANDLE_PIECE_REQUEST(), 1);
if(this->Internal->FileNames.empty())
{
// No file names specified. No meta-data. There is still
// no need to return with an error.
return 1;
}
size_t nTimes = this->Internal->FileNames.size();
std::vector<double> times(nTimes);
bool hasTime = true;
auto iter = times.begin();
for(const auto& fname: this->Internal->FileNames)
{
auto time = this->GetTimeValue(fname);
if (vtkMath::IsNan(time))
{
hasTime = false;
break;
}
*iter++ = time;
}
if (!hasTime)
{
std::iota(times.begin(), times.end(), 0);
}
double timeRange[2];
timeRange[0] = times[0];
timeRange[1] = times[nTimes - 1];
metadata->Set(
vtkStreamingDemandDrivenPipeline::TIME_STEPS(), &times[0], (int)nTimes);
metadata->Set(
vtkStreamingDemandDrivenPipeline::TIME_RANGE(), timeRange, 2);
return 1;
}
//----------------------------------------------------------------------------
int vtkParallelReader::ReadMesh(
int piece, int npieces, int nghosts, int timestep, vtkDataObject* output)
{
int nTimes = static_cast<int>(this->Internal->FileNames.size());
if (timestep >= nTimes)
{
vtkErrorMacro("Cannot read time step " << timestep << ". Only " <<
nTimes << " time steps are available.");
return 0;
}
if (this->ReadMesh(
this->Internal->FileNames[timestep], piece, npieces, nghosts, output))
{
this->CurrentFileIndex = timestep;
return 1;
}
return 0;
}
//----------------------------------------------------------------------------
int vtkParallelReader::ReadPoints(
int piece, int npieces, int nghosts, int timestep, vtkDataObject* output)
{
int nTimes = static_cast<int>(this->Internal->FileNames.size());
if (timestep >= nTimes)
{
vtkErrorMacro("Cannot read time step " << timestep << ". Only " <<
nTimes << " time steps are available.");
return 0;
}
return this->ReadPoints(
this->Internal->FileNames[timestep], piece, npieces, nghosts, output);
}
//----------------------------------------------------------------------------
int vtkParallelReader::ReadArrays(
int piece, int npieces, int nghosts, int timestep, vtkDataObject* output)
{
int nTimes = static_cast<int>(this->Internal->FileNames.size());
if (timestep >= nTimes)
{
vtkErrorMacro("Cannot read time step " << timestep << ". Only " <<
nTimes << " time steps are available.");
return 0;
}
return this->ReadArrays(
this->Internal->FileNames[timestep], piece, npieces, nghosts, output);
}
//----------------------------------------------------------------------------
double vtkParallelReader::GetTimeValue(const std::string&)
{
return vtkMath::Nan();
}
/*=========================================================================
Program: Visualization Toolkit
Module: vtkParallelReader.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.
=========================================================================*/
/**
* @class vtkParallelReader
* @brief Superclass for algorithms that are parallel aware
*
* vtkParallelReader is a vtkReaderAlgorithm subclass that provides
* a specialized API to develop readers that are parallel aware (i.e.
* can handle piece requests) but do not natively support time series.
* This reader adds support for file series in order to support time
* series.
*/
#ifndef vtkParallelReader_h
#define vtkParallelReader_h
#include "vtkCommonExecutionModelModule.h" // For export macro
#include "vtkReaderAlgorithm.h"
#include <string> // needed for std::string in the interface
struct vtkParallelReaderInternal;
class VTKCOMMONEXECUTIONMODEL_EXPORT vtkParallelReader : public vtkReaderAlgorithm
{
public:
vtkTypeMacro(vtkParallelReader,vtkReaderAlgorithm);
void PrintSelf(ostream& os, vtkIndent indent) override;
/**
* Add a filename to be read. Since this superclass handles
* file series to support time, multiple filenames can be added.
* Note that the time values are either integers growing sequentially,
* or are obtained from individual files as supported by the subclass.
*/
void AddFileName(const char* fname);
/**
* Removes all filenames stored by the reader.
*/
void ClearFileNames();
/**
* Returns the number of filenames stored by the reader.
*/
int GetNumberOfFileNames() const;
/**
* Returns a particular filename stored by the reader.
*/
const char* GetFileName(int i) const;
/**
* Returns the filename that was last loaded by the reader.
* This is set internally in ReadMesh()
*/
const char* GetCurrentFileName() const;
//@{
/**
* This is the superclass API overridden by this class
* to provide time support internally. Subclasses should
* not normally have to override these methods.
*/
int ReadMetaData(vtkInformation* metadata) override;
int ReadMesh(
int piece, int npieces, int nghosts, int timestep,
vtkDataObject* output) override;
int ReadPoints(
int piece, int npieces, int nghosts, int timestep,
vtkDataObject* output) override;
int ReadArrays(
int piece, int npieces, int nghosts, int timestep,
vtkDataObject* output) override;
//@}
protected:
vtkParallelReader();
~vtkParallelReader() override;
/**
* A subclass can override this method to provide an actual
* time value for a given file (this method is called for
* each filename stored by the reader). If time values is not
* available, the subclass does not have to override.
*/
virtual double GetTimeValue(const std::string& fname);
/**
* A method that needs to be override by the subclass to provide
* the mesh (topology). Note that the filename is passed to this
* method and should be used by the subclass. The subclass directly
* adds the structure/topology to the provided data object.
*/
virtual int ReadMesh(const std::string& fname,
int piece,
int npieces,
int nghosts,
vtkDataObject* output) = 0;
/**
* A method that needs to be override by the subclass to provide
* the point coordinates. Note that the filename is passed to this
* method and should be used by the subclass. The subclass directly
* adds the coordinates to the provided data object.
*/
virtual int ReadPoints(const std::string& fname,
int piece,
int npieces,
int nghosts,
vtkDataObject* output) = 0;
/**
* A method that needs to be override by the subclass to provide
* data arrays. Note that the filename is passed to this
* method and should be used by the subclass. The subclass directly
* adds data arrays to the provided data object.
*/
virtual int ReadArrays(const std::string& fname,
int piece,
int npieces,
int nghosts,
vtkDataObject* output) = 0;
int CurrentFileIndex;
private:
vtkParallelReader(const vtkParallelReader&) = delete;
void operator=(const vtkParallelReader&) = delete;
vtkParallelReaderInternal* Internal;
};
#endif
/*=========================================================================
Program: Visualization Toolkit
Module: vtkReaderAlgorithm.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 "vtkReaderAlgorithm.h"
#include "vtkObjectFactory.h"
//----------------------------------------------------------------------------
vtkReaderAlgorithm::vtkReaderAlgorithm()
{
// by default assume filters have one input and one output
// subclasses that deviate should modify this setting
this->SetNumberOfOutputPorts(1);
}
//----------------------------------------------------------------------------
vtkReaderAlgorithm::~vtkReaderAlgorithm() = default;
//----------------------------------------------------------------------------
void vtkReaderAlgorithm::PrintSelf(ostream& os, vtkIndent indent)
{
this->Superclass::PrintSelf(os, indent);
}
/*=========================================================================
Program: Visualization Toolkit
Module: vtkReaderAlgorithm.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.
=========================================================================*/
/**
* @class vtkReaderAlgorithm
* @brief Superclass for readers that implement a simplified API.
*
* This class and associated subclasses were created to make it easier to
* develop readers. When directly subclassing from other algorithm classes
* one has to learn a general purpose API that somewhat obfuscates pipeline
* functionality behind information keys. One has to know how to find
* time and pieces requests using keys for example. Furthermore, these
* classes together with specialized executives can implement common
* reader functionality for things such as file series (for time and/or
* partitions), caching, mapping time requests to indices etc.
* This class implements the most basic API which is specialized as
* needed by subclasses (for file series for example).
*/
#ifndef vtkReaderAlgorithm_h
#define vtkReaderAlgorithm_h
#include "vtkCommonExecutionModelModule.h" // For export macro
#include "vtkAlgorithm.h"
class VTKCOMMONEXECUTIONMODEL_EXPORT vtkReaderAlgorithm : public vtkAlgorithm
{
public:
vtkTypeMacro(vtkReaderAlgorithm,vtkAlgorithm);
void PrintSelf(ostream& os, vtkIndent indent) override;
/**
* Provide meta-data for the pipeline. These include things like
* time steps and whole extent. Subclasses may have specialized
* interfaces making this simpler.
*/
virtual int ReadMetaData(vtkInformation* metadata) = 0;
/**
* Read the mesh (connectivity) for a given set of data partitioning,
* number of ghost levels and time step (index). The reader populates
* the data object passed in as the last argument. It is OK to read
* more than the mesh (points, arrays etc.). However, this may interfere
* with any caching implemented by the executive (i.e. cause more reads).
*/
virtual int ReadMesh(
int piece, int npieces, int nghosts, int timestep,
vtkDataObject* output) = 0;
/**
* Read the points. The reader populates the input data object. This is
* called after ReadMesh() so the data object should already contain the
* mesh.
*/
virtual int ReadPoints(
int piece, int npieces, int nghosts, int timestep,
vtkDataObject* output) = 0;
/**
* Read all the arrays (point, cell, field etc.). This is called after
* ReadPoints() so the data object should already contain the mesh and
* points.
*/
virtual int ReadArrays(
int piece, int npieces, int nghosts, int timestep,
vtkDataObject* output) = 0;
protected:
vtkReaderAlgorithm();
~vtkReaderAlgorithm() override;
private:
vtkReaderAlgorithm(const vtkReaderAlgorithm&) = delete;
void operator=(const vtkReaderAlgorithm&) = delete;
};
#endif
/*=========================================================================
Program: Visualization Toolkit
Module: vtkReaderExecutive.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 "vtkReaderExecutive.h"
#include "vtkAlgorithm.h"
#include "vtkDataObject.h"
#include "vtkInformation.h"
#include "vtkInformationVector.h"
#include "vtkObjectFactory.h"
#include "vtkReaderAlgorithm.h"
vtkStandardNewMacro(vtkReaderExecutive);
//----------------------------------------------------------------------------
vtkReaderExecutive::vtkReaderExecutive()
{
}
//----------------------------------------------------------------------------
vtkReaderExecutive::~vtkReaderExecutive()
{}
//----------------------------------------------------------------------------
void vtkReaderExecutive::PrintSelf(ostream& os, vtkIndent indent)
{
this->Superclass::PrintSelf(os, indent);
}
//----------------------------------------------------------------------------
int vtkReaderExecutive::CallAlgorithm(vtkInformation* request, int direction,
vtkInformationVector** inInfo,
vtkInformationVector* outInfo)
{
// Copy default information in the direction of information flow.
this->CopyDefaultInformation(request, direction, inInfo, outInfo);
// Invoke the request on the algorithm.
this->InAlgorithm = 1;
int result = 1; // this->Algorithm->ProcessRequest(request, inInfo, outInfo);
vtkReaderAlgorithm* reader = vtkReaderAlgorithm::SafeDownCast(this->Algorithm);
if (!reader)
{
return 0;
}
if (request->Has(REQUEST_INFORMATION()))
{
result = reader->ReadMetaData(outInfo->GetInformationObject(0));
}
else if (request->Has(REQUEST_DATA()))
{
typedef vtkStreamingDemandDrivenPipeline vtkSDDP;
vtkInformation* reqs = outInfo->GetInformationObject(0);
int piece = reqs->Has(vtkSDDP::UPDATE_PIECE_NUMBER()) ?
reqs->Get(vtkSDDP::UPDATE_PIECE_NUMBER()) : 0 ;
int npieces = reqs->Has(vtkSDDP::UPDATE_NUMBER_OF_PIECES()) ?
reqs->Get(vtkSDDP::UPDATE_NUMBER_OF_PIECES()) : 1;
int nghosts = reqs->Get(UPDATE_NUMBER_OF_GHOST_LEVELS());
int hasTime = reqs->Has(vtkSDDP::UPDATE_TIME_STEP());
double* steps =
reqs->Get(vtkStreamingDemandDrivenPipeline::TIME_STEPS());
int timeIndex = 0;
if (hasTime && steps)
{
double requestedTimeStep =
reqs->Get(vtkStreamingDemandDrivenPipeline::UPDATE_TIME_STEP());
int length =
reqs->Length(vtkStreamingDemandDrivenPipeline::TIME_STEPS());
// find the first time value larger than requested time value
// this logic could be improved
int cnt = 0;
while (cnt < length-1 && steps[cnt] < requestedTimeStep)
{
cnt++;
}
timeIndex = cnt;
}
vtkDataObject* output = vtkDataObject::GetData(outInfo);
result = reader->ReadMesh(
piece, npieces, nghosts, timeIndex, output);
if (result)
{
result = reader->ReadPoints(
piece, npieces, nghosts, timeIndex, output);
}
if (result)
{
result = reader->ReadArrays(
piece, npieces, nghosts, timeIndex, output);
}
}
this->InAlgorithm = 0;
// If the algorithm failed report it now.
if(!result)
{
vtkErrorMacro("Algorithm " << this->Algorithm->GetClassName()
<< "(" << this->Algorithm
<< ") returned failure for request: "
<< *request);
}
return result;
}
/*=========================================================================
Program: Visualization Toolkit
Module: vtkReaderExecutive.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.
=========================================================================*/
/**
* @class vtkReaderExecutive
* @brief Executive that works with vtkReaderAlgorithm and subclasses.
*
* vtkReaderExecutive is an executive that supports simplified API readers
* that are written by subclassing from the vtkReaderAlgorithm hierarchy.
* Currently, its main functionality is to call the basic reader API instead
* if the standard ProcessRequest() method that other algorithms use.
* In time, this is likely to add functionality such as caching. See
* vtkReaderAlgorithm for the API.
*
* Note that this executive assumes that the reader has one output port.
*/
#ifndef vtkReaderExecutive_h
#define vtkReaderExecutive_h
#include "vtkCommonExecutionModelModule.h" // For export macro
#include "vtkStreamingDemandDrivenPipeline.h"
class VTKCOMMONEXECUTIONMODEL_EXPORT vtkReaderExecutive :
public vtkStreamingDemandDrivenPipeline
{
public:
static vtkReaderExecutive* New();
vtkTypeMacro(vtkReaderExecutive,vtkStreamingDemandDrivenPipeline);
void PrintSelf(ostream& os, vtkIndent indent) override;
/**
* Overwritten to call the vtkReaderAlgorithm API instead of
* ProcessRequest().
*/
virtual int CallAlgorithm(vtkInformation* request, int direction,
vtkInformationVector** inInfo,
vtkInformationVector* outInfo) override;
protected:
vtkReaderExecutive();
~vtkReaderExecutive() override;
private:
vtkReaderExecutive(const vtkReaderExecutive&) = delete;
void operator=(const vtkReaderExecutive&) = delete;
};
#endif
This source diff could not be displayed because it is too large. You can view the blob instead.
......@@ -34,9 +34,10 @@
* alpha, tuple 2: re, tuple 3: time). In addition, the solution file contains
* the flow density (scalar), flow momentum (vector), and flow energy (scalar).
*
* Note that this reader does not support time series data which is usually
* stored as a series of Q and optionally XYZ files. If you want to read such
* a file series, use vtkPlot3DMetaReader.
* This reader supports a limited form of time series data which are stored
* as a series of Q files. Using the AddFileName() method provided by the
* superclass, one can define a file series. For other cases, for example where
* the XYZ or function files vary over time, use vtkPlot3DMetaReader.
*
* The reader can generate additional scalars and vectors (or "functions")
* from this information. To use vtkMultiBlockPLOT3DReader, you must specify the
......@@ -88,7 +89,7 @@
#include <vector> // For holding function-names
#include "vtkIOParallelModule.h" // For export macro
#include "vtkMultiBlockDataSetAlgorithm.h"
#include "vtkParallelReader.h"
class vtkDataArray;
class vtkDataSetAttributes;
......@@ -98,6 +99,7 @@ class vtkMultiProcessController;
class vtkStructuredGrid;
class vtkUnsignedCharArray;
struct vtkMultiBlockPLOT3DReaderInternals;
class vtkMultiBlockDataSet;
namespace Functors
{
......@@ -120,7 +122,7 @@ namespace Functors
}
class VTKIOPARALLEL_EXPORT vtkMultiBlockPLOT3DReader : public vtkMultiBlockDataSetAlgorithm
class VTKIOPARALLEL_EXPORT vtkMultiBlockPLOT3DReader : public vtkParallelReader
{
friend class Functors::ComputeFunctor;
friend class Functors::ComputeTemperatureFunctor;
......@@ -140,25 +142,42 @@ friend class Functors::ComputeVorticityFunctor;
friend class Functors::ComputeStrainRateFunctor;
public:
static vtkMultiBlockPLOT3DReader *New();
vtkTypeMacro(vtkMultiBlockPLOT3DReader,vtkMultiBlockDataSetAlgorithm);
vtkTypeMacro(vtkMultiBlockPLOT3DReader,vtkParallelReader);
void PrintSelf(ostream& os, vtkIndent indent) override;
//@{
/**
* Get the output data object for a port on this algorithm.
*/
vtkMultiBlockDataSet* GetOutput();
vtkMultiBlockDataSet* GetOutput(int);
//@}
//@{
/**
* Set/Get the PLOT3D geometry filename.
*/
void SetFileName(const char* name) { this->SetXYZFileName(name); }
const char* GetFileName() { return this->GetXYZFileName(); }
const char* GetFileName(int i) { return this->vtkParallelReader::GetFileName(i); }
virtual void SetXYZFileName( const char* );
vtkGetStringMacro(XYZFileName);
//@}
//@{
/**
* Set/Get the PLOT3D solution filename.