ParaView plugin - setting multiple vtkMultiBlockDataSets as output

Hi, I am working on a ParaView plugin that currently reads grid and fields from a data source, then creates multiple vtkUnstructuredGrids which are added as blocks to a single vtkMultiBlockDataSet. This vtkMultiBlockDataSet is then passed as an output to ParaView.

My plugin structure is somewhat similar to the one here
with the difference that my plugin is using/inherits from vtkMultiBlockDataSetAlgorithm.

Shortened code structure of my plugin .cxx source file:

// my_plugin.cxx
int my_plugin::RequestData(vtkInformation *vtkNotUsed(request),
                           vtkInformationVector **vtkNotUsed(inputVector),
                           vtkInformationVector *outputVector)
{
    // Get the info object
    vtkInformation *outInfo = outputVector->GetInformationObject(0);

    // MultiBlock object, to hold all vtkUnstructuredGrids
    vtkSmartPointer<vtkMultiBlockDataSet> mainMB =
        vtkSmartPointer<vtkMultiBlockDataSet>::New();
    for(int i; i < num_blocks; ++i)
    {
        // Creating vtkUnstructuredGrid
        vtkSmartPointer<vtkUnstructuredGrid> UG=
            vtkSmartPointer<vtkUnstructuredGrid>::New();

        ... // filling the UG

        // Adding UG as block to vtkMultiBlockDataSet
        mainMB->SetBlock(i, UG);
    }

    // Set the output format
    vtkMultiBlockDataSet *outputMB = vtkMultiBlockDataSet::SafeDownCast(
        outInfo->Get(vtkMultiBlockDataSet::DATA_OBJECT()));
    // Make shallow copy of the output
    outputMB->ShallowCopy(mainMB);
    return 1;
}

The plugin performs very nicely, however, in my data source the data is time dependant. Now I am able to read and set as output a single time slice (I am using IntVectorProperty to specify which one) as vtkMultiBlockDataSet.

At the moment I’ve included vtkXMLMultiBlockDataWriter withing the plugin code to write the .vtm (and belonging.vtu files) for each time slice locally on my PC which I then manually open them in ParaView. ParaView then enables me to use each .vtm as a frame and I can play a very nice animation-like overall display of the (2D) data . If possible I would like to reproduce the same thing within the plugin itself (getting data directly to ParaView, without VTM writer in-between).
Is there a way to set the plugin to output multiple vtkMultiBlockDataSets as if I opened a set of .vtm files?
I realize there is a SetNumberOfOutputPorts option but this doesn’t come into account for me as only after plugin execution it is known how many time slices are present in the data source I’m working with and so far I haven’t found out any way to dynamically set the number of output ports.

Any help in this regard is highly appreciated. Thanks in advance.

Your multiblock design is not adapted to timesteps.

You will have to implement an actual timesteps-aware reader. See here :
https://vtk.org/Wiki/VTK/Time_Support
https://vtk.org/Wiki/VTK/Tutorials/New_Pipeline

and
VTK/IO/XML/vtkXMLReader.cxx

Thank you, Mathieu, for fast answer. This gave me more insight into this matter. However, I have an issue getting the time steps recognized by ParaView GUI (the frame buttons (“play” etc.) on top of the ParaView GUI). By default I am noticing that there are 10 time steps: [0, 0.111111, 0.222222, 0.333333, …, 1.0].

I am setting

myPlugin::myPlugin()
{

    // Time support:
    this->TimeStep = 0; 
    this->TimeStepRange[0] = 0;
    this->TimeStepRange[1] = 0;
    this->NumberOfTimeSteps = 0;
    this->TimeSteps = NULL;
}

int myPlugin::RequestInformation(vtkInformation *request,
                                 vtkInformationVector **vtkNotUsed(inputVector),
                                 vtkInformationVector *outputVector)

    vtkInformation* outInfo = outputVector->GetInformationObject(0);
    outInfo->Remove(vtkStreamingDemandDrivenPipeline::TIME_STEPS());
    outInfo->Remove(vtkStreamingDemandDrivenPipeline::TIME_RANGE());

    if (!outInfo->Has(vtkStreamingDemandDrivenPipeline::TIME_RANGE()))
    {

        this->NumberOfTimeSteps = 15; // hardcoded for testing purposes
        this->TimeSteps = new double[this->NumberOfTimeSteps];
        
        // setting testing set of time step values
        for (int step = 0; step < this->NumberOfTimeSteps; step++)
            this->TimeSteps[step] = (double)step*2.1;
        double tRange[2];
        tRange[0] = this->TimeSteps[0];
        tRange[1] = this->TimeSteps[this->NumberOfTimeSteps - 1];

        this->TimeStepRange[0] = tRange[0];
        this->TimeStepRange[1] = tRange[1];
        outInfo->Set(
            vtkStreamingDemandDrivenPipeline::TIME_STEPS(),
            this->TimeSteps,
            this->NumberOfTimeSteps);
        outInfo->Set(vtkStreamingDemandDrivenPipeline::TIME_RANGE(),
                     tRange, 2);
    }

The

outInfo->Set(
        vtkStreamingDemandDrivenPipeline::TIME_STEPS(),
        this->TimeSteps,
        this->NumberOfTimeSteps);

is supposed to update the set time steps in ParaView from (0, 0.111111 …) to (0, 2.1, 4.2 …) right? But it doesn’t do that.

The

int Plugin::RequestData(vtkInformation *vtkNotUsed(request),
                          vtkInformationVector **vtkNotUsed(inputVector),
                          vtkInformationVector *outputVector)

    // Get the info object
    vtkInformation *outInfo = outputVector->GetInformationObject(0);

    std::clog << "First time step " <<
    outInfo->Get(vtkStreamingDemandDrivenPipeline::TIME_STEPS())[0] << std::endl;

    std::clog << "Last time step: " <<
        outInfo->Get(vtkStreamingDemandDrivenPipeline::TIME_STEPS())[this->NumberOfTimeSteps-1]  << std::endl;

    int nSteps = outInfo->Length(vtkStreamingDemandDrivenPipeline::TIME_STEPS());
    double* steps = outInfo->Get(vtkStreamingDemandDrivenPipeline::TIME_STEPS());
    ...

“follow” the changes done in myPlugin:RequestInformation (I get the expected values), but

    double requestedTimeValue = outInfo->Get(vtkStreamingDemandDrivenPipeline::UPDATE_TIME_STEP());

still follows the default (0, 0.111111, 0,22222, … 1) time step values (done by using the frame command buttons such as “next frame” etc.) and returns those default values.

Do you maybe see what am I missing here?
I followed the suggested VTK/IO/XML/vtkXMLReader.cxx(excellent source for learning) and Plugins/CDIReader/CDIReader_Plugin.cxx.

Thank you for your support.

Yes.

Nothing seems out of place in you code so far.

Got it working!

In my myPlugin.xml file I’ve included

        <DoubleVectorProperty
            name="TimestepValues"
            information_only="1">
            <TimeStepsInformationHelper/>
            <Documentation>
                Available timestep values.
            </Documentation>
        </DoubleVectorProperty>

and now under the Information tab (next to Properties tab) I have all my time indices and time values listed (as a table) + the frame time values are now correct!

The

double requestedTimeValue = outInfo->Get(vtkStreamingDemandDrivenPipeline::UPDATE_TIME_STEP());

, as expected, returns the wanted time values too.

Thank you, Mathieu, for your guidance. :slight_smile:

1 Like

Nice, I forgot about the XML part.

Another relevant question.
Is it possible to update the number of time steps and time step values when myPlugin::RequestData is executed (e.g. also after pressing the Apply button)? As before that when myPlugin::RequestInformation is executed (before pressing Apply button) I don’t really know yet how many time steps will be available (from which data source the plugin should get the data from is specified later with the help of custom plugin GUI).

No, this is a design limitation.

You should do all that is required to figure out your temporal information in RequestInformation.

Alternatively, you can use a LiveSource.