1 // Copyright (C) 2014 CEA/DEN, EDF R&D
3 // This library is free software; you can redistribute it and/or
4 // modify it under the terms of the GNU Lesser General Public
5 // License as published by the Free Software Foundation; either
6 // version 2.1 of the License, or (at your option) any later version.
8 // This library is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 // Lesser General Public License for more details.
13 // You should have received a copy of the GNU Lesser General Public
14 // License along with this library; if not, write to the Free Software
15 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
19 // Author : Maxim Glibin
21 #include "vtkDifferenceTimestepsFilter.h"
23 #include <vtkCellData.h>
24 #include <vtkDataArray.h>
25 #include <vtkDataObjectTreeIterator.h>
26 #include <vtkDataSet.h>
27 #include <vtkDoubleArray.h>
28 #include <vtkInformation.h>
29 #include <vtkInformationVector.h>
30 #include <vtkMultiBlockDataSet.h>
31 #include <vtkObjectFactory.h>
32 #include <vtkPointData.h>
33 #include <vtkStreamingDemandDrivenPipeline.h>
34 #include <vtkStringArray.h>
35 #include <vtkUnstructuredGrid.h>
37 // Temporal difference of data array
38 vtkDataArray* DataTempDiffArray(vtkDataArray* theDataArray,
40 vtkIdType theNumTuple,
41 const char* thePrefix)
43 // Create the new array
44 vtkAbstractArray *anAbstractArray = theDataArray->CreateArray(theDataArray->GetDataType());
45 vtkDataArray *anOutput = vtkDataArray::SafeDownCast(anAbstractArray);
47 // Initialize and appoint a new name
48 anOutput->SetNumberOfComponents(theNumComp);
49 anOutput->SetNumberOfTuples(theNumTuple);
50 vtkstd::string aNewName = vtkstd::string(thePrefix) + theDataArray->GetName();
51 anOutput->SetName(aNewName.c_str());
56 // Templated difference function
58 void vtkTemporalDataDifference(
59 vtkDifferenceTimestepsFilter* theDTF,
60 vtkDataArray* theOutput,
61 vtkDataArray** theArrays,
65 T* anOutputData = static_cast<T*>(theOutput->GetVoidPointer(0));
66 T* anInputData0 = static_cast<T*>(theArrays[0]->GetVoidPointer(0));
67 T* anInputData1 = static_cast<T*>(theArrays[1]->GetVoidPointer(0));
69 vtkIdType N = theArrays[0]->GetNumberOfTuples();
70 for (vtkIdType t = 0; t < N; ++t)
72 T* x0 = &anInputData0[t*theNumComp];
73 T* x1 = &anInputData1[t*theNumComp];
74 for (int c = 0; c < theNumComp; ++c)
76 // Compute the difference
77 *anOutputData++ = static_cast<T>(x1[c]-x0[c]);
80 theOutput->SetNumberOfTuples(N);
83 vtkStandardNewMacro(vtkDifferenceTimestepsFilter);
85 //--------------------------------------------------------------------------------------------------
86 vtkDifferenceTimestepsFilter::vtkDifferenceTimestepsFilter()
88 this->NumberTimeSteps = 0;
89 this->RangeIndicesTimeSteps[0] = 0;
90 this->RangeIndicesTimeSteps[1] = 0;
91 this->FirstTimeStepIndex = 0.0;
92 this->SecondTimeStepIndex = 0.0;
93 this->TimeStepValues.clear();
94 this->ArrayNamePrefix = NULL;
96 this->SetNumberOfInputPorts(1);
97 this->SetNumberOfOutputPorts(1);
99 // Set the input data array that the algorithm will process
100 this->SetInputArrayToProcess(
104 vtkDataObject::FIELD_ASSOCIATION_POINTS,
105 vtkDataSetAttributes::SCALARS);
108 //--------------------------------------------------------------------------------------------------
109 vtkDifferenceTimestepsFilter::~vtkDifferenceTimestepsFilter()
111 this->TimeStepValues.clear();
112 this->SetArrayNamePrefix(NULL);
115 //--------------------------------------------------------------------------------------------------
116 void vtkDifferenceTimestepsFilter::PrintSelf(ostream& theOS, vtkIndent theIndent)
118 this->Superclass::PrintSelf(theOS, theIndent);
119 theOS << theIndent << "Number of time steps : " << this->NumberTimeSteps << endl;
120 theOS << theIndent << "First time step : " << this->FirstTimeStepIndex << endl;
121 theOS << theIndent << "Second time step : " << this->SecondTimeStepIndex << endl;
122 theOS << theIndent << "Field association : "
123 << vtkDataObject::GetAssociationTypeAsString(this->GetInputFieldAssociation()) << endl;
126 //--------------------------------------------------------------------------------------------------
127 int vtkDifferenceTimestepsFilter::FillInputPortInformation(
128 int thePort, vtkInformation* theInfo)
131 theInfo->Set(vtkAlgorithm::INPUT_REQUIRED_DATA_TYPE(), "vtkDataObject");
136 //--------------------------------------------------------------------------------------------------
137 int vtkDifferenceTimestepsFilter::FillOutputPortInformation(
138 int vtkNotUsed(thePort), vtkInformation* theInfo)
140 theInfo->Set(vtkDataObject::DATA_TYPE_NAME(), "vtkDataObject");
144 //--------------------------------------------------------------------------------------------------
145 int vtkDifferenceTimestepsFilter::RequestDataObject(
146 vtkInformation* vtkNotUsed(theRequest),
147 vtkInformationVector** theInputVector,
148 vtkInformationVector* theOutputVector)
150 if (this->GetNumberOfInputPorts() == 0 || this->GetNumberOfOutputPorts() == 0)
153 vtkInformation* anInputInfo = theInputVector[0]->GetInformationObject(0);
154 if (anInputInfo == NULL)
156 vtkErrorMacro(<< "Input information vector is missed.");
160 vtkDataObject *anInputObj = anInputInfo->Get(vtkDataObject::DATA_OBJECT());
161 if (anInputObj != NULL)
164 for (int i = 0; i < this->GetNumberOfOutputPorts(); ++i)
166 vtkInformation* anOutputInfo = theOutputVector->GetInformationObject(i);
167 vtkDataObject *anOutputObj = anOutputInfo->Get(vtkDataObject::DATA_OBJECT());
168 if (!anOutputObj || !anOutputObj->IsA(anInputObj->GetClassName()))
170 vtkDataObject* aNewOutput = anInputObj->NewInstance();
171 anOutputInfo->Set(vtkDataObject::DATA_OBJECT(), aNewOutput);
172 aNewOutput->Delete();
180 //--------------------------------------------------------------------------------------------------
181 int vtkDifferenceTimestepsFilter::RequestInformation(
182 vtkInformation* vtkNotUsed(theRequest),
183 vtkInformationVector** theInputVector,
184 vtkInformationVector* theOutputVector)
186 // Get input and output information objects
187 vtkInformation *anInInfo = theInputVector[0]->GetInformationObject(0);
188 vtkInformation *anOutInfo = theOutputVector->GetInformationObject(0);
190 // Check for presence more than one time step
191 if (anInInfo->Has(vtkStreamingDemandDrivenPipeline::TIME_STEPS()))
193 // Find time on input
194 this->NumberTimeSteps = anInInfo->Length(vtkStreamingDemandDrivenPipeline::TIME_STEPS());
195 if (this->NumberTimeSteps < 2)
197 vtkErrorMacro(<< "Not enough numbers of time steps: " << this->NumberTimeSteps);
200 // Get time step values
201 this->TimeStepValues.resize(this->NumberTimeSteps);
202 anInInfo->Get(vtkStreamingDemandDrivenPipeline::TIME_STEPS(), &this->TimeStepValues[0]);
203 if (this->TimeStepValues.size() == 0)
205 vtkErrorMacro(<<"Array of time steps is empty.");
211 vtkErrorMacro(<< "No time steps in input data.");
215 // Update range of indices of the time steps
216 this->RangeIndicesTimeSteps[0] = 0;
217 this->RangeIndicesTimeSteps[1] = this->NumberTimeSteps - 1;
219 // The output data of this filter has no time associated with it.
220 // It is the result of computation difference between two time steps.
221 // Unset the time steps
222 if (anOutInfo->Has(vtkStreamingDemandDrivenPipeline::TIME_STEPS()))
223 anOutInfo->Remove(vtkStreamingDemandDrivenPipeline::TIME_STEPS());
225 // Unset the time range
226 if(anOutInfo->Has(vtkStreamingDemandDrivenPipeline::TIME_RANGE()))
227 anOutInfo->Remove(vtkStreamingDemandDrivenPipeline::TIME_RANGE());
232 //--------------------------------------------------------------------------------------------------
233 int vtkDifferenceTimestepsFilter::RequestUpdateExtent(vtkInformation* theRequest,
234 vtkInformationVector** theInputVector,
235 vtkInformationVector* theOutputVector)
237 // Get the information objects
238 vtkInformation* anInputInfo = theInputVector[0]->GetInformationObject(0);
239 vtkInformation* anOutputInfo = theOutputVector->GetInformationObject(0);
241 // Indices must not go beyond the range of indices of the time steps
242 if (this->FirstTimeStepIndex >= this->NumberTimeSteps || this->FirstTimeStepIndex < 0)
244 vtkErrorMacro(<< "Specified index of the first time step ["
245 << this->FirstTimeStepIndex
246 << "] is outside the range of indices.");
249 if (this->SecondTimeStepIndex >= this->NumberTimeSteps || this->SecondTimeStepIndex < 0)
251 vtkErrorMacro(<< "Specified index of the second time step ["
252 << this->SecondTimeStepIndex
253 << "] is outside the range of indices.");
257 // Warn if the selected time steps are equal
258 if (this->FirstTimeStepIndex == this->SecondTimeStepIndex)
260 vtkWarningMacro(<< "First and second indices ["
261 << this->FirstTimeStepIndex
262 << " = " << this->SecondTimeStepIndex
263 << "] are the same.");
266 // Find the required input time steps and request them
267 if (anOutputInfo->Has(vtkStreamingDemandDrivenPipeline::UPDATE_TIME_STEP()))
269 // Get the available input times
270 double *anInputTimes = anInputInfo->Get(vtkStreamingDemandDrivenPipeline::TIME_STEPS());
271 if (anInputTimes != NULL)
273 // Compute the requested times
274 double anInputUpdateTimes[2];
275 int aNumberInputUpdateTimes(0);
277 // For each the requested time mark the required input times
278 anInputUpdateTimes[aNumberInputUpdateTimes++] = anInputTimes[this->FirstTimeStepIndex];
279 anInputUpdateTimes[aNumberInputUpdateTimes++] = anInputTimes[this->SecondTimeStepIndex];
281 // Make the multiple time requests upstream and use set of time-stamped data
282 // objects are stored in time order in a vtkMultiBlockDataSet object
283 anInputInfo->Set(vtkMultiTimeStepAlgorithm::UPDATE_TIME_STEPS(),
284 anInputUpdateTimes, aNumberInputUpdateTimes);
290 //--------------------------------------------------------------------------------------------------
291 int vtkDifferenceTimestepsFilter::RequestData(vtkInformation* vtkNotUsed(theRequest),
292 vtkInformationVector** theInputVector,
293 vtkInformationVector* theOutputVector)
295 // Get the information objects
296 vtkInformation *anInputInfo = theInputVector[0]->GetInformationObject(0);
297 vtkInformation *anOutputInfo = theOutputVector->GetInformationObject(0);
299 vtkDataObject *anOutputDataObj = NULL;
301 vtkMultiBlockDataSet *anInputData =
302 vtkMultiBlockDataSet::SafeDownCast(anInputInfo->Get(vtkDataObject::DATA_OBJECT()));
304 int aNumberTimeSteps = anInputData->GetNumberOfBlocks();
305 if (aNumberTimeSteps == 2)
308 vtkDataObject* aData0 = anInputData->GetBlock(0);
309 vtkDataObject* aData1 = anInputData->GetBlock(1);
310 if (aData0 == NULL && aData1 == NULL)
312 vtkErrorMacro(<< "Null data set.");
316 // Compute difference between two objects
317 anOutputDataObj = this->DifferenceDataObject(aData0, aData1);
318 anOutputInfo->Set(vtkDataObject::DATA_OBJECT(), anOutputDataObj);
319 if (anOutputDataObj != NULL)
320 anOutputDataObj->Delete();
324 vtkErrorMacro(<< "The amount of time blocks is not correct: " << aNumberTimeSteps);
331 //--------------------------------------------------------------------------------------------------
332 vtkDataObject* vtkDifferenceTimestepsFilter::DifferenceDataObject(vtkDataObject* theInput1,
333 vtkDataObject* theInput2)
335 // Determine the input object type
336 if (theInput1->IsA("vtkDataSet"))
338 vtkDataSet *anInDataSet1 = vtkDataSet::SafeDownCast(theInput1);
339 vtkDataSet *anInDataSet2 = vtkDataSet::SafeDownCast(theInput2);
340 return this->DifferenceDataSet(anInDataSet1, anInDataSet2);
342 else if (theInput1->IsA("vtkCompositeDataSet"))
344 // It is essential that aMGDataSet[0] an aMGDataSet[1] has the same structure.
345 vtkCompositeDataSet* aMGDataSet[2];
346 aMGDataSet[0] = vtkCompositeDataSet::SafeDownCast(theInput1);
347 aMGDataSet[1] = vtkCompositeDataSet::SafeDownCast(theInput2);
349 vtkCompositeDataSet *anOutput = aMGDataSet[0]->NewInstance();
350 anOutput->CopyStructure(aMGDataSet[0]);
352 vtkSmartPointer<vtkCompositeDataIterator> anIter;
353 anIter.TakeReference(aMGDataSet[0]->NewIterator());
354 for (anIter->InitTraversal(); !anIter->IsDoneWithTraversal(); anIter->GoToNextItem())
356 vtkDataObject* aDataObj1 = anIter->GetCurrentDataObject();
357 vtkDataObject* aDataObj2 = aMGDataSet[1]->GetDataSet(anIter);
358 if (aDataObj1 == NULL || aDataObj2 == NULL)
360 vtkWarningMacro("The composite datasets were not identical in structure.");
364 vtkDataObject *aResultDObj = this->DifferenceDataObject(aDataObj1, aDataObj2);
365 if (aResultDObj != NULL)
367 anOutput->SetDataSet(anIter, aResultDObj);
368 aResultDObj->Delete();
372 vtkErrorMacro(<< "Unexpected error during computation of the difference.");
380 vtkErrorMacro("We cannot yet compute difference of this type of dataset.");
385 //--------------------------------------------------------------------------------------------------
386 vtkDataSet* vtkDifferenceTimestepsFilter::DifferenceDataSet(vtkDataSet* theInput1,
387 vtkDataSet* theInput2)
389 vtkDataSet *anInput[2];
390 anInput[0] = theInput1;
391 anInput[1] = theInput2;
393 // Copy input structure into output
394 vtkDataSet *anOutput = anInput[0]->NewInstance();
395 anOutput->CopyStructure(anInput[0]);
397 vtkstd::vector<vtkDataArray*> anArrays;
398 vtkDataArray *anOutputArray;
400 // Compute the difference of the the specified point or cell data array
401 vtkDataArray* aDataArray0 = this->GetInputArrayToProcess(0, anInput[0]);
402 vtkDataArray* aDataArray1 = this->GetInputArrayToProcess(0, anInput[1]);
403 if (aDataArray0 == NULL || aDataArray1 == NULL)
405 vtkErrorMacro(<< "Input array to process is empty.");
408 anArrays.push_back(aDataArray0);
409 anArrays.push_back(aDataArray1);
411 if (anArrays.size() > 1)
413 if (!this->VerifyArrays(&anArrays[0], 2))
415 vtkErrorMacro(<< "Verification of data arrays has failed.");
419 anOutputArray = this->DifferenceDataArray(&anArrays[0], anArrays[0]->GetNumberOfTuples());
420 // Determine a field association
421 if (this->GetInputFieldAssociation() == vtkDataObject::FIELD_ASSOCIATION_POINTS)
424 anOutput->GetPointData()->AddArray(anOutputArray);
426 else if (this->GetInputFieldAssociation() == vtkDataObject::FIELD_ASSOCIATION_CELLS)
429 anOutput->GetCellData()->AddArray(anOutputArray);
433 vtkErrorMacro(<< "Solution is not implemeted yet.");
436 anOutputArray->Delete();
443 //--------------------------------------------------------------------------------------------------
444 vtkDataArray* vtkDifferenceTimestepsFilter::DifferenceDataArray(vtkDataArray** theArrays,
445 vtkIdType theNumTuple)
447 // Create the output array based on the number of tuple and components
448 // with a new name containing the specified prefix
449 int aNumComp = theArrays[0]->GetNumberOfComponents();
450 vtkDataArray *anOutput =
451 DataTempDiffArray(theArrays[0], aNumComp, theNumTuple, this->ArrayNamePrefix);
453 // Now do the computation of the difference
454 switch (theArrays[0]->GetDataType())
457 vtkTemporalDataDifference(this, anOutput, theArrays, aNumComp, static_cast<VTK_TT *>(0)));
459 vtkErrorMacro(<< "Execute: unknown scalar type.");
466 //--------------------------------------------------------------------------------------------------
467 int vtkDifferenceTimestepsFilter::GetInputFieldAssociation()
469 vtkInformationVector *anInputArrayVec = this->GetInformation()->Get(INPUT_ARRAYS_TO_PROCESS());
470 vtkInformation *anInputArrayInfo = anInputArrayVec->GetInformationObject(0);
471 return anInputArrayInfo->Get(vtkDataObject::FIELD_ASSOCIATION());
474 //--------------------------------------------------------------------------------------------------
475 bool vtkDifferenceTimestepsFilter::VerifyArrays(vtkDataArray **theArrays, int theNumArrays)
477 // Get all required data to compare with other
478 const char* anArrayName = theArrays[0]->GetName();
479 vtkIdType aNumTuples = theArrays[0]->GetNumberOfTuples();
480 vtkIdType aNumComponents = theArrays[0]->GetNumberOfComponents();
482 for (int i = 1; i < theNumArrays; ++i)
484 if (strcmp(theArrays[i]->GetName(), anArrayName) != 0)
486 vtkWarningMacro(<< "Computation of difference aborted for dataset because "
487 << "the array name in each time step are different.")
491 if (theArrays[i]->GetNumberOfTuples() != aNumTuples)
493 vtkWarningMacro(<< "Computation of difference aborted for dataset because "
494 << "the number of tuples in each time step are different.")
498 if (theArrays[i]->GetNumberOfComponents() != aNumComponents)
500 vtkWarningMacro(<< "Computation of difference aborted for dataset because "
501 << "the number of components in each time step are different.")