Commit 5af93610 authored by Burlen Loring's avatar Burlen Loring
Browse files

programmable data adaptor

Add a data adptor that implements the data adptor API
with call backs. This enables the creation of new data
adaptors using functional as opposed to polymorphic
approach. This will simplify data adaptor creation in
Python and Fortran.
parent 7373d88d
......@@ -2,8 +2,8 @@ if (ENABLE_SENSEI)
message(STATUS "Enabled: sensei library")
set(sensei_sources Error.cxx AnalysisAdaptor.cxx Autocorrelation.cxx
ConfigurableAnalysis.cxx DataAdaptor.cxx PosthocIO.cxx Histogram.cxx
VTKHistogram.cxx VTKDataAdaptor.cxx)
ConfigurableAnalysis.cxx DataAdaptor.cxx ProgrammableDataAdaptor.cxx
PosthocIO.cxx Histogram.cxx VTKHistogram.cxx VTKDataAdaptor.cxx)
set(sensei_libs mpi pugixml vtk thread ArrayIO timer diy grid)
......
#include "ProgrammableDataAdaptor.h"
#include "senseiConfig.h"
#include "Error.h"
#include <vtkObjectFactory.h>
namespace sensei
{
//-----------------------------------------------------------------------------
senseiNewMacro(ProgrammableDataAdaptor);
//----------------------------------------------------------------------------
ProgrammableDataAdaptor::ProgrammableDataAdaptor() :
GetMeshCallback(nullptr), AddArrayCallback(nullptr),
GetNumberOfArraysCallback(nullptr), GetArrayNameCallback(nullptr),
ReleaseDataCallback(nullptr)
{
}
//----------------------------------------------------------------------------
ProgrammableDataAdaptor::~ProgrammableDataAdaptor()
{
}
//----------------------------------------------------------------------------
void ProgrammableDataAdaptor::SetGetMeshCallback(
const GetMeshCallbackType &callback)
{
this->GetMeshCallback = callback;
}
//----------------------------------------------------------------------------
void ProgrammableDataAdaptor::SetAddArrayCallback(
const AddArrayCallbackType &callback)
{
this->AddArrayCallback = callback;
}
//----------------------------------------------------------------------------
void ProgrammableDataAdaptor::SetGetNumberOfArraysCallback(
const GetNumberOfArraysCallbackType &callback)
{
this->GetNumberOfArraysCallback = callback;
}
//----------------------------------------------------------------------------
void ProgrammableDataAdaptor::SetGetArrayNameCallback(
const GetArrayNameCallbackType &callback)
{
this->GetArrayNameCallback = callback;
}
//----------------------------------------------------------------------------
void ProgrammableDataAdaptor::SetReleaseDataCallback(
const ReleaseDataCallbackType &callback)
{
this->ReleaseDataCallback = callback;
}
//----------------------------------------------------------------------------
vtkDataObject *ProgrammableDataAdaptor::GetMesh(bool structure_only)
{
if (!this->GetMeshCallback)
{
SENSEI_ERROR("No GetMeshCallback has been provided")
return nullptr;
}
return this->GetMeshCallback(structure_only);
}
//----------------------------------------------------------------------------
bool ProgrammableDataAdaptor::AddArray(vtkDataObject* mesh, int association,
const std::string& arrayname)
{
if (!this->AddArrayCallback)
return true;
return this->AddArrayCallback(mesh, association, arrayname);
}
//----------------------------------------------------------------------------
unsigned int ProgrammableDataAdaptor::GetNumberOfArrays(int association)
{
if (!this->GetNumberOfArraysCallback)
return 0;
return this->GetNumberOfArraysCallback(association);
}
//----------------------------------------------------------------------------
std::string ProgrammableDataAdaptor::GetArrayName(int association,
unsigned int index)
{
if (!this->GetArrayNameCallback)
return "";
return this->GetArrayNameCallback(association, index);
}
//----------------------------------------------------------------------------
void ProgrammableDataAdaptor::ReleaseData()
{
if (this->ReleaseDataCallback)
this->ReleaseDataCallback();
}
}
#ifndef sensei_ProgrammableDataAdaptor_h
#define sensei_ProgrammableDataAdaptor_h
#include "senseiConfig.h"
#include "DataAdaptor.h"
#include <string>
#include <functional>
namespace sensei
{
/// @class ProgrammableDataAdaptor
/// @brief ProgrammableDataAdaptor is class that implements the data interface with user provided callables
///
/// ProgrammableDataAdaptor allows one to provide callbacks implementing
/// the data interface. This is an alternative to using polymorphism.
/// Callbacks can be any callable including functors and C function pointers
///
/// One can provide implementations for following sensei::DataAdaptor
/// virtual methods by passing a callable(functor/function) to the corresponding
/// set method (Set_X_Callback, where _X_ is the method name).
///
/// vtkDataObject* GetMesh(bool structure_only);
///
/// bool AddArray(vtkDataObject* mesh, int association,
/// const std::string& arrayname);
///
/// unsigned int GetNumberOfArrays(int association);
///
/// std::string GetArrayName(int association, unsigned int index);
///
/// void ReleaseData();
///
class ProgrammableDataAdaptor : public DataAdaptor
{
public:
static ProgrammableDataAdaptor *New();
senseiTypeMacro(ProgrammableDataAdaptor, DataAdaptor);
/// Set the callable that will be invoked when GetMesh is called
/// See GetMesh for details of what the callback must do.
using GetMeshCallbackType = std::function<vtkDataObject*(bool)>;
void SetGetMeshCallback(const GetMeshCallbackType &callback);
/// @brief Return the data object with appropriate structure.
///
/// This method will return a data object of the appropriate type. The data
/// object can be a vtkDataSet subclass or a vtkCompositeDataSet subclass.
/// If \c structure_only is set to true, then the geometry and topology
/// information will not be populated. For data adaptors that produce a
/// vtkCompositeDataSet subclass, passing \c structure_only will still produce
/// appropriate composite data hierarchy.
///
/// @param structure_only When set to true (default; false) the returned mesh
/// may not have any geometry or topology information.
///
/// Calls to GetMesh will be forwarded to the user provided callback
/// see SetGetMeshCallback
vtkDataObject* GetMesh(bool structure_only) override;
/// Set the callable that will be invoked when AddArray is called
/// See AddArray for details of what the callback must do.
using AddArrayCallbackType =
std::function<bool(vtkDataObject*, int, const std::string&)>;
void SetAddArrayCallback(const AddArrayCallbackType &callback);
/// @brief Adds the specified field array to the mesh.
///
/// This method will add the requested array to the mesh, if available. If the
/// array was already added to the mesh, this will not add it again. The mesh
/// should not be expected to have geometry or topology information.
///
/// @param association field association; one of
/// vtkDataObject::FieldAssociations or vtkDataObject::AttributeTypes.
/// @return true if array was added (or already added), false is request array
/// is not available.
///
/// Calls to AddArray will be forwarded to the user provided callback
/// see SetAddArrayCallback
bool AddArray(vtkDataObject* mesh, int association,
const std::string& arrayname) override;
/// Set the callable that will be invokde when GetNumberOfArrays is called.
/// See GetNumberOfArrays for details of what the callback must do
using GetNumberOfArraysCallbackType = std::function<unsigned int(int)>;
void SetGetNumberOfArraysCallback(const GetNumberOfArraysCallbackType &
callback);
/// @brief Return the number of field arrays available.
///
/// This method will return the number of field arrays available. For data
/// adaptors producing composite datasets, this is a union of arrays available
/// on all parts of the composite dataset.
///
/// @param association field association; one of
/// vtkDataObject::FieldAssociations or vtkDataObject::AttributeTypes.
/// @return the number of arrays.
unsigned int GetNumberOfArrays(int association) override;
/// Set the callable that will be invoked when GetArrayName is called.
/// See GetArrayName for details of what the callback must do.
using GetArrayNameCallbackType =
std::function<std::string(int, unsigned int)>;
void SetGetArrayNameCallback(const GetArrayNameCallbackType &callback);
/// @brief Return the name for a field array.
///
/// This method will return the name for a field array given its index.
///
/// @param association field association; one of
/// vtkDataObject::FieldAssociations or vtkDataObject::AttributeTypes.
/// @param index index for the array. Must be less than value returned
/// GetNumberOfArrays().
/// @return name of the array.
std::string GetArrayName(int association, unsigned int index) override;
///Set the callable that will be invoked when ReleaseData is called.
/// See ReleaseData for details about wwhat the callback should do.
using ReleaseDataCallbackType = std::function<void()>;
void SetReleaseDataCallback(const ReleaseDataCallbackType &callback);
/// @brief Release data allocated for the current timestep.
///
/// Releases the data allocated for the current timestep. This is expected to
/// be called after each time iteration.
void ReleaseData() override;
protected:
ProgrammableDataAdaptor();
~ProgrammableDataAdaptor();
// callbacks
GetMeshCallbackType GetMeshCallback;
AddArrayCallbackType AddArrayCallback;
GetNumberOfArraysCallbackType GetNumberOfArraysCallback;
GetArrayNameCallbackType GetArrayNameCallback;
ReleaseDataCallbackType ReleaseDataCallback;
private:
ProgrammableDataAdaptor(const ProgrammableDataAdaptor&) = delete;
void operator=(const ProgrammableDataAdaptor&) = delete;
};
}
#endif
......@@ -22,4 +22,9 @@ if (BUILD_TESTING)
testADIOSMPIBP.bp MPI BP 2
FEATURES ${ENABLE_PYTHON} ${ENABLE_ADIOS})
senseiAddTest(testProgrammableDataAdaptor
COMMAND ${MPIEXEC} -np 1 testProgrammableDataAdaptor
SOURCES testProgrammableDataAdaptor.cpp
LIBS sensei)
endif()
#include "ProgrammableDataAdaptor.h"
#include "Histogram.h"
#include <vtkDataObject.h>
#include <vtkImageData.h>
#include <vtkPointData.h>
#include <vtkDoubleArray.h>
#include <vector>
#include <iostream>
#include <mpi.h>
using std::cerr;
using std::endl;
int main(int argc, char **argv)
{
MPI_Init(&argc, &argv);
//
// *
// * *
// * * *
// * * * *
// * * * * *
// * * * * * * *
std::vector<unsigned int> baselineHist = {1,2,4,6,5,3,1};
// 0,1,2,3,4,5,6
std::vector<double> data = {0, 1,1, 2,2,2,2,
3,3,3,3,3,3, 4,4,4,4,4, 5,5,5, 6};
// get mesh callback
auto getMesh = [&data](bool) -> vtkDataObject*
{
cerr << "===getMesh" << endl;
vtkImageData *im = vtkImageData::New();
im->SetDimensions(data.size(), 1, 1);
return im;
};
// add array callback
auto addArray = [&data](vtkDataObject *mesh, int assoc,
const std::string &name) -> bool
{
cerr << "===addArray" << endl;
if ((assoc == vtkDataObject::POINT) && (name == "data"))
{
vtkDoubleArray *da = vtkDoubleArray::New();
da->SetName("data");
da->SetArray(data.data(), data.size(), 1);
static_cast<vtkImageData*>(mesh)->GetPointData()->AddArray(da);
da->Delete();
return true;
}
return false;
};
// number of arrays callback
auto getNumArrays = [](int assoc) -> unsigned int
{
cerr << "===getNumArrays" << endl;
if (assoc == vtkDataObject::POINT)
return 1;
return 0;
};
// array name callback
auto getArrayName = [](int assoc, unsigned int id) -> std::string
{
cerr << "===getArrayName" << endl;
if ((assoc == vtkDataObject::POINT) && (id == 0))
return "data";
return "";
};
// release data callback
auto releaseData = []()
{
cerr << "===releaseData" << endl;
};
sensei::ProgrammableDataAdaptor *pda = sensei::ProgrammableDataAdaptor::New();
pda->SetGetMeshCallback(getMesh);
pda->SetAddArrayCallback(addArray);
pda->SetGetNumberOfArraysCallback(getNumArrays);
pda->SetGetArrayNameCallback(getArrayName);
pda->SetReleaseDataCallback(releaseData);
int result = -1;
if (pda->GetNumberOfArrays(vtkDataObject::POINT) > 0)
{
sensei::Histogram *ha = sensei::Histogram::New();
ha->Initialize(MPI_COMM_WORLD, 7, vtkDataObject::POINT,
pda->GetArrayName(vtkDataObject::POINT, 0));
ha->Execute(pda);
pda->ReleaseData();
double min = 0.0;
double max = 0.0;
std::vector<unsigned int> hist;
ha->GetHistogram(min, max, hist);
if (hist == baselineHist)
result = 0;
pda->Delete();
ha->Delete();
}
MPI_Finalize();
return result;
}
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