]> SALOME platform Git repositories - modules/paravis.git/commitdiff
Salome HOME
Create plugin as a filter which allows analyze difference between two time steps...
authorrnv <rnv@opencascade.com>
Wed, 26 Nov 2014 10:33:26 +0000 (13:33 +0300)
committerrnv <rnv@opencascade.com>
Wed, 26 Nov 2014 10:33:26 +0000 (13:33 +0300)
Added the following server manager properties:
1. Property is responsible for enumeration the scalar array names of input data set;
2. Property is responsible for specifying the first time step;
3. Property is responsible for specifying the second time step;
4. Property is responsible for specifying the prefix of new array name.

Filter is capable of reading various data objects.
Also filter can return the corresponding errors if the input data are not correct or property of user interface controls is invalid. This filter appointed into "Temporal" group of filters.
Added the icon to this filter.

src/Plugins/CMakeLists.txt
src/Plugins/DifferenceTimesteps/CMakeLists.txt [new file with mode: 0644]
src/Plugins/DifferenceTimesteps/DifferenceTimesteps.xml [new file with mode: 0644]
src/Plugins/DifferenceTimesteps/DifferenceTimestepsGUI.xml [new file with mode: 0644]
src/Plugins/DifferenceTimesteps/pqDifferenceTimesteps.qrc [new file with mode: 0644]
src/Plugins/DifferenceTimesteps/resources/timesteps-icon.png [new file with mode: 0644]
src/Plugins/DifferenceTimesteps/vtkDifferenceTimestepsFilter.cxx [new file with mode: 0644]
src/Plugins/DifferenceTimesteps/vtkDifferenceTimestepsFilter.h [new file with mode: 0644]

index 52b6e529985881572ce5cfbeb7a55d8c442df4df..357a744896424e58cfcbd7d914404b13a486e4f4 100755 (executable)
@@ -32,6 +32,7 @@ SET(_subdirs
   ElevationSurface
   ScaleVector
   EllipseBuilder
+  DifferenceTimesteps
   )
   
 IF(NOT SALOME_LIGHT_ONLY)
diff --git a/src/Plugins/DifferenceTimesteps/CMakeLists.txt b/src/Plugins/DifferenceTimesteps/CMakeLists.txt
new file mode 100644 (file)
index 0000000..5208ade
--- /dev/null
@@ -0,0 +1,38 @@
+# Copyright (C) 2014  CEA/DEN, EDF R&D
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+#
+# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+#
+# Author : Maxim Glibin
+
+PROJECT(DifferenceTimesteps)
+
+cmake_minimum_required(VERSION 2.8)
+
+FIND_PACKAGE(ParaView REQUIRED)
+INCLUDE(${PARAVIEW_USE_FILE})
+
+ADD_PARAVIEW_PLUGIN(DifferenceTimesteps "1.0"
+  SERVER_MANAGER_XML DifferenceTimesteps.xml
+  SERVER_MANAGER_SOURCES vtkDifferenceTimestepsFilter.cxx
+  GUI_RESOURCES pqDifferenceTimesteps.qrc
+  GUI_RESOURCE_FILES DifferenceTimestepsGUI.xml
+  )
+
+INSTALL(
+  TARGETS DifferenceTimesteps
+  DESTINATION lib/paraview
+)
diff --git a/src/Plugins/DifferenceTimesteps/DifferenceTimesteps.xml b/src/Plugins/DifferenceTimesteps/DifferenceTimesteps.xml
new file mode 100644 (file)
index 0000000..669b722
--- /dev/null
@@ -0,0 +1,124 @@
+<ServerManagerConfiguration>
+  <ProxyGroup name="filters">
+    <SourceProxy name="DifferenceTimesteps"
+                 class="vtkDifferenceTimestepsFilter"
+                 label="Difference Timesteps">
+      <Documentation
+        long_help="The filter computes difference between two selected timesteps from multiblock data set."
+        short_help="Computes difference between two selected timesteps.">
+      </Documentation>
+
+      <InputProperty name="Input"
+                     command="SetInputConnection">
+        <ProxyGroupDomain name="groups">
+          <Group name="sources" />
+          <Group name="filters" />
+        </ProxyGroupDomain>
+        <DataTypeDomain name="input_type">
+          <DataType value="vtkDataObject" />
+        </DataTypeDomain>
+        <InputArrayDomain name="input_array"
+                          attribute_type="any">
+        </InputArrayDomain>
+        <Documentation>
+          This property specifies the input to DifferenceTimesteps filter.
+        </Documentation>
+      </InputProperty>
+
+      <StringVectorProperty name="SelectInputScalars"
+                            label="Array to process"
+                            command="SetInputArrayToProcess"
+                            number_of_elements="5"
+                            element_types="0 0 0 0 2"
+                            animateable="0">
+        <ArrayListDomain name="array_list"
+                         attribute_type="Scalars"
+                         input_domain_name="input_array">
+          <RequiredProperties>
+            <Property name="Input"
+                      function="Input" />
+          </RequiredProperties>
+        </ArrayListDomain>
+        <FieldDataDomain name="field_list">
+          <RequiredProperties>
+            <Property name="Input"
+                      function="Input" />
+          </RequiredProperties>
+        </FieldDataDomain>
+        <Documentation>
+          This property indicates the scalar array name to compute difference.
+        </Documentation>
+      </StringVectorProperty>
+
+      <DoubleVectorProperty
+        name="TimestepValues"
+        repeatable="1"
+        information_only="1">
+        <TimeStepsInformationHelper/>
+        <Documentation>
+          Available timestep values.
+        </Documentation>
+      </DoubleVectorProperty>
+
+      <IntVectorProperty
+         name="RangeIndicesTimeStepsInfo"
+         command="GetRangeIndicesTimeSteps"
+         number_of_elements="2"
+         default_values="0 0"
+         information_only="1">
+        <SimpleIntInformationHelper/>
+      </IntVectorProperty>
+
+      <IntVectorProperty
+        name="FirstTimeStepIndex"
+        label="First time step"
+        command="SetFirstTimeStepIndex"
+        number_of_elements="1"
+        default_values="0"
+        animateable="1"
+        information_property="RangeIndicesTimeStepsInfo">
+        <IntRangeDomain name="range" default_mode="min">
+          <RequiredProperties>
+            <Property name="RangeIndicesTimeStepsInfo"
+                      function="Range" />
+          </RequiredProperties>
+        </IntRangeDomain>
+        <Documentation>
+          Define a first time step.
+        </Documentation>
+      </IntVectorProperty>
+
+      <IntVectorProperty
+        name="SecondTimeStepIndex"
+        label="Second time step"
+        command="SetSecondTimeStepIndex"
+        number_of_elements="1"
+        default_values="0"
+        animateable="0"
+        information_property="RangeIndicesTimeStepsInfo">
+        <IntRangeDomain name="range" default_mode="max">
+          <RequiredProperties>
+            <Property name="RangeIndicesTimeStepsInfo"
+                      function="Range" />
+          </RequiredProperties>
+        </IntRangeDomain>
+        <Documentation>
+          Define a second time step.
+        </Documentation>
+      </IntVectorProperty>
+
+      <StringVectorProperty
+        name="ArrayNamePrefix"
+        label="Name prefix array"
+        command="SetArrayNamePrefix"
+        number_of_elements="1"
+        animateable="0"
+        default_values="diff_" >
+        <Documentation>
+          Prefix to a new array name.
+        </Documentation>
+      </StringVectorProperty>
+
+    </SourceProxy>
+  </ProxyGroup>
+</ServerManagerConfiguration>
diff --git a/src/Plugins/DifferenceTimesteps/DifferenceTimestepsGUI.xml b/src/Plugins/DifferenceTimesteps/DifferenceTimestepsGUI.xml
new file mode 100644 (file)
index 0000000..e2a0455
--- /dev/null
@@ -0,0 +1,5 @@
+<ParaViewFilters>
+    <Category name="Temporal" menu_label="&amp;Temporal">
+        <Proxy group="filters" name="DifferenceTimesteps" icon=":/DifferenceTimestepsIcons/resources/timesteps-icon.png" omit_from_toolbar="1"/>
+    </Category>
+</ParaViewFilters>
diff --git a/src/Plugins/DifferenceTimesteps/pqDifferenceTimesteps.qrc b/src/Plugins/DifferenceTimesteps/pqDifferenceTimesteps.qrc
new file mode 100644 (file)
index 0000000..85fa5c3
--- /dev/null
@@ -0,0 +1,5 @@
+<RCC>
+  <qresource prefix="/DifferenceTimestepsIcons" >
+    <file>resources/timesteps-icon.png</file>
+  </qresource>
+</RCC>
diff --git a/src/Plugins/DifferenceTimesteps/resources/timesteps-icon.png b/src/Plugins/DifferenceTimesteps/resources/timesteps-icon.png
new file mode 100644 (file)
index 0000000..28feea5
Binary files /dev/null and b/src/Plugins/DifferenceTimesteps/resources/timesteps-icon.png differ
diff --git a/src/Plugins/DifferenceTimesteps/vtkDifferenceTimestepsFilter.cxx b/src/Plugins/DifferenceTimesteps/vtkDifferenceTimestepsFilter.cxx
new file mode 100644 (file)
index 0000000..7749f9c
--- /dev/null
@@ -0,0 +1,507 @@
+// Copyright (C) 2014  CEA/DEN, EDF R&D
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+//
+// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+//
+// Author : Maxim Glibin
+
+#include "vtkDifferenceTimestepsFilter.h"
+
+#include <vtkCellData.h>
+#include <vtkDataArray.h>
+#include <vtkDataObjectTreeIterator.h>
+#include <vtkDataSet.h>
+#include <vtkDoubleArray.h>
+#include <vtkInformation.h>
+#include <vtkInformationVector.h>
+#include <vtkMultiBlockDataSet.h>
+#include <vtkObjectFactory.h>
+#include <vtkPointData.h>
+#include <vtkStreamingDemandDrivenPipeline.h>
+#include <vtkStringArray.h>
+#include <vtkUnstructuredGrid.h>
+
+// Temporal difference of data array
+vtkDataArray* DataTempDiffArray(vtkDataArray* theDataArray,
+                                vtkIdType     theNumComp,
+                                vtkIdType     theNumTuple,
+                                const char*   thePrefix)
+{
+  // Create the new array
+  vtkAbstractArray *anAbstractArray = theDataArray->CreateArray(theDataArray->GetDataType());
+  vtkDataArray *anOutput = vtkDataArray::SafeDownCast(anAbstractArray);
+
+  // Initialize and appoint a new name
+  anOutput->SetNumberOfComponents(theNumComp);
+  anOutput->SetNumberOfTuples(theNumTuple);
+  vtkstd::string aNewName = vtkstd::string(thePrefix) + theDataArray->GetName();
+  anOutput->SetName(aNewName.c_str());
+
+  return anOutput;
+}
+
+// Templated difference function
+template <class T>
+void vtkTemporalDataDifference(
+  vtkDifferenceTimestepsFilter* theDTF,
+  vtkDataArray*                 theOutput,
+  vtkDataArray**                theArrays,
+  vtkIdType                     theNumComp,
+  T *)
+{
+  T* anOutputData = static_cast<T*>(theOutput->GetVoidPointer(0));
+  T* anInputData0 = static_cast<T*>(theArrays[0]->GetVoidPointer(0));
+  T* anInputData1 = static_cast<T*>(theArrays[1]->GetVoidPointer(0));
+
+  vtkIdType N = theArrays[0]->GetNumberOfTuples();
+  for (vtkIdType t = 0; t < N; ++t)
+  {
+    T* x0 = &anInputData0[t*theNumComp];
+    T* x1 = &anInputData1[t*theNumComp];
+    for (int c = 0; c < theNumComp; ++c)
+    {
+      // Compute the difference
+      *anOutputData++ = static_cast<T>(x1[c]-x0[c]);
+    }
+  }
+  theOutput->SetNumberOfTuples(N);
+}
+
+vtkStandardNewMacro(vtkDifferenceTimestepsFilter);
+
+//--------------------------------------------------------------------------------------------------
+vtkDifferenceTimestepsFilter::vtkDifferenceTimestepsFilter()
+{
+  this->NumberTimeSteps = 0;
+  this->RangeIndicesTimeSteps[0] = 0;
+  this->RangeIndicesTimeSteps[1] = 0;
+  this->FirstTimeStepIndex = 0.0;
+  this->SecondTimeStepIndex = 0.0;
+  this->TimeStepValues.clear();
+  this->ArrayNamePrefix = NULL;
+
+  this->SetNumberOfInputPorts(1);
+  this->SetNumberOfOutputPorts(1);
+
+  // Set the input data array that the algorithm will process
+  this->SetInputArrayToProcess(
+    0,
+    0,
+    0,
+    vtkDataObject::FIELD_ASSOCIATION_POINTS,
+    vtkDataSetAttributes::SCALARS);
+}
+
+//--------------------------------------------------------------------------------------------------
+vtkDifferenceTimestepsFilter::~vtkDifferenceTimestepsFilter()
+{
+  this->TimeStepValues.clear();
+  this->SetArrayNamePrefix(NULL);
+}
+
+//--------------------------------------------------------------------------------------------------
+void vtkDifferenceTimestepsFilter::PrintSelf(ostream& theOS, vtkIndent theIndent)
+{
+  this->Superclass::PrintSelf(theOS, theIndent);
+  theOS << theIndent << "Number of time steps : " << this->NumberTimeSteps << endl;
+  theOS << theIndent << "First time step : " << this->FirstTimeStepIndex << endl;
+  theOS << theIndent << "Second time step : " << this->SecondTimeStepIndex << endl;
+  theOS << theIndent << "Field association : "
+        << vtkDataObject::GetAssociationTypeAsString(this->GetInputFieldAssociation()) << endl;
+}
+
+//--------------------------------------------------------------------------------------------------
+int vtkDifferenceTimestepsFilter::FillInputPortInformation(
+  int thePort, vtkInformation* theInfo)
+{
+  if (thePort == 0)
+    theInfo->Set(vtkAlgorithm::INPUT_REQUIRED_DATA_TYPE(), "vtkDataObject");
+
+  return 1;
+}
+
+//--------------------------------------------------------------------------------------------------
+int vtkDifferenceTimestepsFilter::FillOutputPortInformation(
+  int vtkNotUsed(thePort), vtkInformation* theInfo)
+{
+  theInfo->Set(vtkDataObject::DATA_TYPE_NAME(), "vtkDataObject");
+  return 1;
+}
+
+//--------------------------------------------------------------------------------------------------
+int vtkDifferenceTimestepsFilter::RequestDataObject(
+  vtkInformation*        vtkNotUsed(theRequest),
+  vtkInformationVector** theInputVector,
+  vtkInformationVector*  theOutputVector)
+{
+  if (this->GetNumberOfInputPorts() == 0 || this->GetNumberOfOutputPorts() == 0)
+    return 1;
+
+  vtkInformation* anInputInfo = theInputVector[0]->GetInformationObject(0);
+  if (anInputInfo == NULL)
+  {
+    vtkErrorMacro(<< "Input information vector is missed.");
+    return 0;
+  }
+
+  vtkDataObject *anInputObj = anInputInfo->Get(vtkDataObject::DATA_OBJECT());
+  if (anInputObj != NULL)
+  {
+    // For each output
+    for (int i = 0; i < this->GetNumberOfOutputPorts(); ++i)
+    {
+      vtkInformation* anOutputInfo = theOutputVector->GetInformationObject(i);
+      vtkDataObject *anOutputObj = anOutputInfo->Get(vtkDataObject::DATA_OBJECT());
+      if (!anOutputObj || !anOutputObj->IsA(anInputObj->GetClassName()))
+      {
+        vtkDataObject* aNewOutput = anInputObj->NewInstance();
+        anOutputInfo->Set(vtkDataObject::DATA_OBJECT(), aNewOutput);
+        aNewOutput->Delete();
+      }
+    }
+    return 1;
+  }
+  return 0;
+}
+
+//--------------------------------------------------------------------------------------------------
+int vtkDifferenceTimestepsFilter::RequestInformation(
+  vtkInformation*        vtkNotUsed(theRequest),
+  vtkInformationVector** theInputVector,
+  vtkInformationVector*  theOutputVector)
+{
+  // Get input and output information objects
+  vtkInformation *anInInfo = theInputVector[0]->GetInformationObject(0);
+  vtkInformation *anOutInfo = theOutputVector->GetInformationObject(0);
+
+  // Check for presence more than one time step
+  if (anInInfo->Has(vtkStreamingDemandDrivenPipeline::TIME_STEPS()))
+  {
+    // Find time on input
+    this->NumberTimeSteps = anInInfo->Length(vtkStreamingDemandDrivenPipeline::TIME_STEPS());
+    if (this->NumberTimeSteps < 2)
+    {
+      vtkErrorMacro(<< "Not enough numbers of time steps: " << this->NumberTimeSteps);
+      return 0;
+    }
+    // Get time step values
+    this->TimeStepValues.resize(this->NumberTimeSteps);
+    anInInfo->Get(vtkStreamingDemandDrivenPipeline::TIME_STEPS(), &this->TimeStepValues[0]);
+    if (this->TimeStepValues.size() == 0)
+    {
+      vtkErrorMacro(<<"Array of time steps is empty.");
+      return 0;
+    }
+  }
+  else
+  {
+    vtkErrorMacro(<< "No time steps in input data.");
+    return 0;
+  }
+
+  // Update range of indices of the time steps
+  this->RangeIndicesTimeSteps[0] = 0;
+  this->RangeIndicesTimeSteps[1] = this->NumberTimeSteps - 1;
+
+  // The output data of this filter has no time associated with it.
+  // It is the result of computation difference between two time steps.
+  // Unset the time steps
+  if (anOutInfo->Has(vtkStreamingDemandDrivenPipeline::TIME_STEPS()))
+    anOutInfo->Remove(vtkStreamingDemandDrivenPipeline::TIME_STEPS());
+
+  // Unset the time range
+  if(anOutInfo->Has(vtkStreamingDemandDrivenPipeline::TIME_RANGE()))
+    anOutInfo->Remove(vtkStreamingDemandDrivenPipeline::TIME_RANGE());
+
+  return 1;
+}
+
+//--------------------------------------------------------------------------------------------------
+int vtkDifferenceTimestepsFilter::RequestUpdateExtent(vtkInformation*        theRequest,
+                                                      vtkInformationVector** theInputVector,
+                                                      vtkInformationVector*  theOutputVector)
+{
+  // Get the information objects
+  vtkInformation* anInputInfo  = theInputVector[0]->GetInformationObject(0);
+  vtkInformation* anOutputInfo = theOutputVector->GetInformationObject(0);
+
+  // Indices must not go beyond the range of indices of the time steps
+  if (this->FirstTimeStepIndex >= this->NumberTimeSteps || this->FirstTimeStepIndex < 0)
+  {
+    vtkErrorMacro(<< "Specified index of the first time step ["
+                  << this->FirstTimeStepIndex
+                  << "] is outside the range of indices.");
+    return 0;
+  }
+  if (this->SecondTimeStepIndex >= this->NumberTimeSteps || this->SecondTimeStepIndex < 0)
+  {
+    vtkErrorMacro(<< "Specified index of the second time step ["
+                  << this->SecondTimeStepIndex
+                  << "] is outside the range of indices.");
+    return 0;
+  }
+
+  // Warn if the selected time steps are equal
+  if (this->FirstTimeStepIndex == this->SecondTimeStepIndex)
+  {
+    vtkWarningMacro(<< "First and second indices ["
+                    << this->FirstTimeStepIndex
+                    << " = " << this->SecondTimeStepIndex
+                    << "] are the same.");
+  }
+
+  // Find the required input time steps and request them
+  if (anOutputInfo->Has(vtkStreamingDemandDrivenPipeline::UPDATE_TIME_STEP()))
+  {
+    // Get the available input times
+    double *anInputTimes = anInputInfo->Get(vtkStreamingDemandDrivenPipeline::TIME_STEPS());
+    if (anInputTimes != NULL)
+    {
+      // Compute the requested times
+      double anInputUpdateTimes[2];
+      int aNumberInputUpdateTimes(0);
+
+      // For each the requested time mark the required input times
+      anInputUpdateTimes[aNumberInputUpdateTimes++] = anInputTimes[this->FirstTimeStepIndex];
+      anInputUpdateTimes[aNumberInputUpdateTimes++] = anInputTimes[this->SecondTimeStepIndex];
+
+      // Make the multiple time requests upstream and use set of time-stamped data
+      // objects are stored in time order in a vtkMultiBlockDataSet object
+      anInputInfo->Set(vtkMultiTimeStepAlgorithm::UPDATE_TIME_STEPS(),
+                       anInputUpdateTimes, aNumberInputUpdateTimes);
+    }
+  }
+  return 1;
+}
+
+//--------------------------------------------------------------------------------------------------
+int vtkDifferenceTimestepsFilter::RequestData(vtkInformation*        vtkNotUsed(theRequest),
+                                              vtkInformationVector** theInputVector,
+                                              vtkInformationVector*  theOutputVector)
+{
+  // Get the information objects
+  vtkInformation *anInputInfo  = theInputVector[0]->GetInformationObject(0);
+  vtkInformation *anOutputInfo = theOutputVector->GetInformationObject(0);
+
+  vtkDataObject *anOutputDataObj = NULL;
+
+  vtkMultiBlockDataSet *anInputData =
+    vtkMultiBlockDataSet::SafeDownCast(anInputInfo->Get(vtkDataObject::DATA_OBJECT()));
+
+  int aNumberTimeSteps = anInputData->GetNumberOfBlocks();
+  if (aNumberTimeSteps == 2)
+  {
+    // Get data objects
+    vtkDataObject* aData0 = anInputData->GetBlock(0);
+    vtkDataObject* aData1 = anInputData->GetBlock(1);
+    if (aData0 == NULL && aData1 == NULL)
+    {
+      vtkErrorMacro(<< "Null data set.");
+      return 0;
+    }
+
+    // Compute difference between two objects
+    anOutputDataObj = this->DifferenceDataObject(aData0, aData1);
+    anOutputInfo->Set(vtkDataObject::DATA_OBJECT(), anOutputDataObj);
+    if (anOutputDataObj != NULL)
+      anOutputDataObj->Delete();
+  }
+  else
+  {
+    vtkErrorMacro(<< "The amount of time blocks is not correct: " << aNumberTimeSteps);
+    return 0;
+  }
+
+  return 1;
+}
+
+//--------------------------------------------------------------------------------------------------
+vtkDataObject* vtkDifferenceTimestepsFilter::DifferenceDataObject(vtkDataObject* theInput1,
+                                                                  vtkDataObject* theInput2)
+{
+  // Determine the input object type
+  if (theInput1->IsA("vtkDataSet"))
+  {
+    vtkDataSet *anInDataSet1 = vtkDataSet::SafeDownCast(theInput1);
+    vtkDataSet *anInDataSet2 = vtkDataSet::SafeDownCast(theInput2);
+    return this->DifferenceDataSet(anInDataSet1, anInDataSet2);
+  }
+  else if (theInput1->IsA("vtkCompositeDataSet"))
+  {
+    // It is essential that aMGDataSet[0] an aMGDataSet[1] has the same structure.
+    vtkCompositeDataSet* aMGDataSet[2];
+    aMGDataSet[0] = vtkCompositeDataSet::SafeDownCast(theInput1);
+    aMGDataSet[1] = vtkCompositeDataSet::SafeDownCast(theInput2);
+
+    vtkCompositeDataSet *anOutput = aMGDataSet[0]->NewInstance();
+    anOutput->CopyStructure(aMGDataSet[0]);
+
+    vtkSmartPointer<vtkCompositeDataIterator> anIter;
+    anIter.TakeReference(aMGDataSet[0]->NewIterator());
+    for (anIter->InitTraversal(); !anIter->IsDoneWithTraversal(); anIter->GoToNextItem())
+    {
+      vtkDataObject* aDataObj1 = anIter->GetCurrentDataObject();
+      vtkDataObject* aDataObj2 = aMGDataSet[1]->GetDataSet(anIter);
+      if (aDataObj1 == NULL || aDataObj2 == NULL)
+      {
+        vtkWarningMacro("The composite datasets were not identical in structure.");
+        continue;
+      }
+
+      vtkDataObject *aResultDObj = this->DifferenceDataObject(aDataObj1, aDataObj2);
+      if (aResultDObj != NULL)
+      {
+        anOutput->SetDataSet(anIter, aResultDObj);
+        aResultDObj->Delete();
+      }
+      else
+      {
+        vtkErrorMacro(<< "Unexpected error during computation of the difference.");
+        return NULL;
+      }
+    }
+    return anOutput;
+  }
+  else
+  {
+    vtkErrorMacro("We cannot yet compute difference of this type of dataset.");
+    return NULL;
+  }
+}
+
+//--------------------------------------------------------------------------------------------------
+vtkDataSet* vtkDifferenceTimestepsFilter::DifferenceDataSet(vtkDataSet* theInput1,
+                                                            vtkDataSet* theInput2)
+{
+  vtkDataSet *anInput[2];
+  anInput[0] = theInput1;
+  anInput[1] = theInput2;
+
+  // Copy input structure into output
+  vtkDataSet *anOutput = anInput[0]->NewInstance();
+  anOutput->CopyStructure(anInput[0]);
+
+  vtkstd::vector<vtkDataArray*> anArrays;
+  vtkDataArray *anOutputArray;
+
+  // Compute the difference of the the specified point or cell data array
+  vtkDataArray* aDataArray0 = this->GetInputArrayToProcess(0, anInput[0]);
+  vtkDataArray* aDataArray1 = this->GetInputArrayToProcess(0, anInput[1]);
+  if (aDataArray0 == NULL || aDataArray1 == NULL)
+  {
+    vtkErrorMacro(<< "Input array to process is empty.");
+    return NULL;
+  }
+  anArrays.push_back(aDataArray0);
+  anArrays.push_back(aDataArray1);
+
+  if (anArrays.size() > 1)
+  {
+    if (!this->VerifyArrays(&anArrays[0], 2))
+    {
+      vtkErrorMacro(<< "Verification of data arrays has failed.");
+      return NULL;
+    }
+
+    anOutputArray = this->DifferenceDataArray(&anArrays[0], anArrays[0]->GetNumberOfTuples());
+    // Determine a field association
+    if (this->GetInputFieldAssociation() == vtkDataObject::FIELD_ASSOCIATION_POINTS)
+    {
+      // For point data
+      anOutput->GetPointData()->AddArray(anOutputArray);
+    }
+    else if (this->GetInputFieldAssociation() == vtkDataObject::FIELD_ASSOCIATION_CELLS)
+    {
+      // For cell data
+      anOutput->GetCellData()->AddArray(anOutputArray);
+    }
+    else
+    {
+      vtkErrorMacro(<< "Solution is not implemeted yet.");
+      return NULL;
+    }
+    anOutputArray->Delete();
+    anArrays.clear();
+  }
+
+  return anOutput;
+}
+
+//--------------------------------------------------------------------------------------------------
+vtkDataArray* vtkDifferenceTimestepsFilter::DifferenceDataArray(vtkDataArray** theArrays,
+                                                                vtkIdType      theNumTuple)
+{
+  // Create the output array based on the number of tuple and components
+  // with a new name containing the specified prefix
+  int aNumComp = theArrays[0]->GetNumberOfComponents();
+  vtkDataArray *anOutput =
+    DataTempDiffArray(theArrays[0], aNumComp, theNumTuple, this->ArrayNamePrefix);
+
+  // Now do the computation of the difference
+  switch (theArrays[0]->GetDataType())
+  {
+    vtkTemplateMacro(
+      vtkTemporalDataDifference(this, anOutput, theArrays, aNumComp, static_cast<VTK_TT *>(0)));
+  default:
+    vtkErrorMacro(<< "Execute: unknown scalar type.");
+    return NULL;
+  }
+
+  return anOutput;
+}
+
+//--------------------------------------------------------------------------------------------------
+int vtkDifferenceTimestepsFilter::GetInputFieldAssociation()
+{
+  vtkInformationVector *anInputArrayVec = this->GetInformation()->Get(INPUT_ARRAYS_TO_PROCESS());
+  vtkInformation *anInputArrayInfo = anInputArrayVec->GetInformationObject(0);
+  return anInputArrayInfo->Get(vtkDataObject::FIELD_ASSOCIATION());
+}
+
+//--------------------------------------------------------------------------------------------------
+bool vtkDifferenceTimestepsFilter::VerifyArrays(vtkDataArray **theArrays, int theNumArrays)
+{
+  // Get all required data to compare with other
+  const char* anArrayName  = theArrays[0]->GetName();
+  vtkIdType aNumTuples     = theArrays[0]->GetNumberOfTuples();
+  vtkIdType aNumComponents = theArrays[0]->GetNumberOfComponents();
+
+  for (int i = 1; i < theNumArrays; ++i)
+  {
+    if (strcmp(theArrays[i]->GetName(), anArrayName) != 0)
+    {
+      vtkWarningMacro(<< "Computation of difference aborted for dataset because "
+                      << "the array name in each time step are different.")
+      return false;
+    }
+
+    if (theArrays[i]->GetNumberOfTuples() != aNumTuples)
+    {
+      vtkWarningMacro(<< "Computation of difference aborted for dataset because "
+                      << "the number of tuples in each time step are different.")
+      return false;
+    }
+
+    if (theArrays[i]->GetNumberOfComponents() != aNumComponents)
+    {
+      vtkWarningMacro(<< "Computation of difference aborted for dataset because "
+                      << "the number of components in each time step are different.")
+      return false;
+    }
+  }
+
+  return true;
+}
diff --git a/src/Plugins/DifferenceTimesteps/vtkDifferenceTimestepsFilter.h b/src/Plugins/DifferenceTimesteps/vtkDifferenceTimestepsFilter.h
new file mode 100644 (file)
index 0000000..12bbf63
--- /dev/null
@@ -0,0 +1,148 @@
+// Copyright (C) 2014  CEA/DEN, EDF R&D
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+//
+// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+//
+// Author : Maxim Glibin
+
+#ifndef __DifferenceTimestepsFilter_h_
+#define __DifferenceTimestepsFilter_h_
+
+#include <vtkMultiTimeStepAlgorithm.h>
+
+#include <vector>
+
+class vtkDataSet;
+class vtkStringArray;
+
+/**
+ * Description of class:
+ * Class allows to compute difference between two time steps of one data array (field).
+*/
+class VTK_EXPORT vtkDifferenceTimestepsFilter : public vtkMultiTimeStepAlgorithm
+{
+public:
+  /// Returns pointer on a new instance of the class
+  static vtkDifferenceTimestepsFilter* New();
+
+  vtkTypeMacro(vtkDifferenceTimestepsFilter, vtkMultiTimeStepAlgorithm);
+
+  /// Prints current state of the objects
+  virtual void PrintSelf(ostream &, vtkIndent);
+
+  // Description:
+  // Set/Get methods for first time step.
+  vtkSetMacro(FirstTimeStepIndex, int);
+  vtkGetMacro(FirstTimeStepIndex, int);
+
+  // Description:
+  // Set/Get methods for first time step.
+  vtkSetMacro(SecondTimeStepIndex, int);
+  vtkGetMacro(SecondTimeStepIndex, int);
+
+  // Description:
+  // Get methods for range of indices of time steps.
+  vtkGetVector2Macro(RangeIndicesTimeSteps, int);
+
+  // Description:
+  // Set/Get methods for prefix of array name.
+  vtkSetStringMacro(ArrayNamePrefix);
+  vtkGetStringMacro(ArrayNamePrefix);
+
+protected:
+  /// Constructor & destructor
+  vtkDifferenceTimestepsFilter();
+  virtual ~vtkDifferenceTimestepsFilter();
+
+  /// The methods which is called on filtering data
+  virtual int FillInputPortInformation(int, vtkInformation *);
+
+  virtual int FillOutputPortInformation(int, vtkInformation *);
+
+  virtual int RequestDataObject(vtkInformation *,
+                                vtkInformationVector **,
+                                vtkInformationVector *);
+
+  virtual int RequestInformation(vtkInformation *,
+                                 vtkInformationVector **,
+                                 vtkInformationVector *);
+
+  virtual int RequestUpdateExtent(vtkInformation *,
+                                  vtkInformationVector **,
+                                  vtkInformationVector *);
+
+  virtual int RequestData(vtkInformation *,
+                          vtkInformationVector **,
+                          vtkInformationVector *);
+
+  // Description:
+  // General computation differences routine for any type on input data. This
+  // is called recursively when heirarchical/multiblock data is encountered.
+  vtkDataObject *DifferenceDataObject(vtkDataObject* theInput1,
+                                      vtkDataObject* theInput2);
+
+  // Description:
+  // Root level interpolation for a concrete dataset object.
+  // Point/Cell data and points are different.
+  // Needs improving if connectivity is to be handled.
+  virtual vtkDataSet *DifferenceDataSet(vtkDataSet* theInput1,
+                                        vtkDataSet* theInput2);
+
+  // Description:
+  // Compute difference a single vtkDataArray. Called from computation
+  // of the difference routine on pointdata or celldata.
+  virtual vtkDataArray *DifferenceDataArray(vtkDataArray** theArrays,
+                                            vtkIdType      theN);
+
+  // Description:
+  // Range of indices of the time steps.
+  int RangeIndicesTimeSteps[2];
+  
+  // Description:
+  // First time step index.
+  int FirstTimeStepIndex;
+
+  // Description:
+  // Second time step index.
+  int SecondTimeStepIndex;
+
+  // Description:
+  // Length of time steps array
+  int NumberTimeSteps;
+
+  // Description:
+  // Array of time step values.
+  vtkstd::vector<double> TimeStepValues;
+
+  // Description:
+  // Prefix of array name.
+  char *ArrayNamePrefix;
+
+private:
+  vtkDifferenceTimestepsFilter(const vtkDifferenceTimestepsFilter &); // Not implemented yet
+  void operator=(const vtkDifferenceTimestepsFilter &); // Not implemented yet
+
+  // Description:
+  // Get field association type.
+  int GetInputFieldAssociation();
+
+  // Description:
+  // Called just before computation of the difference of the dataset to ensure that
+  // each data array has the same array name, number of tuples or components and etc.
+  bool VerifyArrays(vtkDataArray **theArrays, int theNumArrays);
+};
+
+#endif // __DifferenceTimestepsFilter_h_