1 /*=========================================================================
2 
3 Program:   Visualization Toolkit
4 Module:    vtkMultiTimeStepAlgorithm.cxx
5 
6 Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
7 All rights reserved.
8 See Copyright.txt or http://www.kitware.com/Copyright.htm for details.
9 
10 This software is distributed WITHOUT ANY WARRANTY; without even
11 the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
12 PURPOSE.  See the above copyright notice for more information.
13 
14 =========================================================================*/
15 // Hide VTK_DEPRECATED_IN_9_1_0() warnings for this class.
16 #define VTK_DEPRECATION_LEVEL 0
17 
18 #include "vtkMultiTimeStepAlgorithm.h"
19 
20 #include "vtkCommand.h"
21 #include "vtkCompositeDataPipeline.h"
22 #include "vtkDataSet.h"
23 #include "vtkInformation.h"
24 #include "vtkInformationDoubleVectorKey.h"
25 #include "vtkInformationKey.h"
26 #include "vtkInformationVector.h"
27 #include "vtkMultiBlockDataSet.h"
28 #include "vtkObjectFactory.h"
29 #include "vtkSmartPointer.h"
30 #include "vtkStreamingDemandDrivenPipeline.h"
31 
32 vtkStandardNewMacro(vtkMultiTimeStepAlgorithm);
33 
34 vtkInformationKeyMacro(vtkMultiTimeStepAlgorithm, UPDATE_TIME_STEPS, DoubleVector);
35 
36 //------------------------------------------------------------------------------
37 // Instantiate object so that cell data is not passed to output.
vtkMultiTimeStepAlgorithm()38 vtkMultiTimeStepAlgorithm::vtkMultiTimeStepAlgorithm()
39 {
40   this->RequestUpdateIndex = 0;
41   this->SetNumberOfInputPorts(1);
42   this->CacheData = false;
43   this->NumberOfCacheEntries = 1;
44 }
45 
46 //------------------------------------------------------------------------------
IsInCache(double time,size_t & idx)47 bool vtkMultiTimeStepAlgorithm::IsInCache(double time, size_t& idx)
48 {
49   std::vector<TimeCache>::iterator it = this->Cache.begin();
50   for (idx = 0; it != this->Cache.end(); ++it, ++idx)
51   {
52     if (time == it->TimeValue)
53     {
54       return true;
55     }
56   }
57   return false;
58 }
59 
60 //------------------------------------------------------------------------------
ProcessRequest(vtkInformation * request,vtkInformationVector ** inputVector,vtkInformationVector * outputVector)61 vtkTypeBool vtkMultiTimeStepAlgorithm::ProcessRequest(
62   vtkInformation* request, vtkInformationVector** inputVector, vtkInformationVector* outputVector)
63 {
64   // create the output
65   if (request->Has(vtkDemandDrivenPipeline::REQUEST_DATA_OBJECT()))
66   {
67     return this->RequestDataObject(request, inputVector, outputVector);
68   }
69 
70   // set update extent
71   if (request->Has(vtkCompositeDataPipeline::REQUEST_UPDATE_EXTENT()))
72   {
73     int retVal(1);
74     vtkInformation* inInfo = inputVector[0]->GetInformationObject(0);
75     if (this->RequestUpdateIndex == 0)
76     {
77       retVal = this->RequestUpdateExtent(request, inputVector, outputVector);
78 
79       double* upTimes = inInfo->Get(UPDATE_TIME_STEPS());
80       int numUpTimes = inInfo->Length(UPDATE_TIME_STEPS());
81       this->UpdateTimeSteps.clear();
82       for (int i = 0; i < numUpTimes; i++)
83       {
84         this->UpdateTimeSteps.push_back(upTimes[i]);
85       }
86       inInfo->Remove(UPDATE_TIME_STEPS());
87     }
88 
89     size_t nTimeSteps = this->UpdateTimeSteps.size();
90     if (nTimeSteps > 0)
91     {
92       bool inCache = true;
93       for (size_t i = 0; i < nTimeSteps; i++)
94       {
95         size_t idx;
96         if (!this->IsInCache(this->UpdateTimeSteps[i], idx))
97         {
98           inCache = false;
99           break;
100         }
101       }
102       if (!inCache)
103       {
104         inInfo->Set(vtkStreamingDemandDrivenPipeline::UPDATE_TIME_STEP(),
105           this->UpdateTimeSteps[this->RequestUpdateIndex]);
106       }
107       else
108       {
109         // Ask for any time step. This should not update unless something else changed.
110         inInfo->Remove(vtkStreamingDemandDrivenPipeline::UPDATE_TIME_STEP());
111       }
112     }
113     return retVal;
114   }
115 
116   // generate the data
117   if (request->Has(vtkCompositeDataPipeline::REQUEST_DATA()))
118   {
119     int retVal = 1;
120     vtkInformation* inInfo = inputVector[0]->GetInformationObject(0);
121     auto inData = vtk::MakeSmartPointer(inInfo->Get(vtkDataObject::DATA_OBJECT()));
122 
123     if (this->UpdateTimeSteps.empty())
124     {
125       vtkErrorMacro("No temporal data has been requested. ");
126       return 0;
127     }
128 
129     size_t idx;
130     if (!this->IsInCache(this->UpdateTimeSteps[this->RequestUpdateIndex], idx))
131     {
132       auto inDataCopy = vtk::TakeSmartPointer(inData->NewInstance());
133       inDataCopy->ShallowCopy(inData);
134       this->Cache.emplace_back(this->UpdateTimeSteps[this->RequestUpdateIndex], inDataCopy);
135     }
136 
137     this->RequestUpdateIndex++;
138 
139     const size_t nTimeSteps = this->UpdateTimeSteps.size();
140     if (this->RequestUpdateIndex == static_cast<int>(nTimeSteps)) // all the time steps are here
141     {
142       // try calling the newer / recommended API first.
143       std::vector<vtkSmartPointer<vtkDataObject>> inputs(nTimeSteps);
144       for (size_t cc = 0; cc < nTimeSteps; ++cc)
145       {
146         if (this->IsInCache(this->UpdateTimeSteps[cc], idx))
147         {
148           inputs[cc] = this->Cache[idx].Data;
149         }
150         else
151         {
152           // This should never happen
153           vtkErrorMacro("exceptional condition reached! Please report.");
154           return 0;
155         }
156       }
157 
158       retVal = this->Execute(request, inputs, outputVector);
159       if (retVal == -1)
160       {
161         vtkWarningMacro("Using legacy `RequestData`. That will not work for all input data-types. "
162                         "Please update code to override `Execute` instead.");
163         vtkNew<vtkMultiBlockDataSet> mb;
164         for (size_t i = 0; i < nTimeSteps; i++)
165         {
166           if (this->IsInCache(this->UpdateTimeSteps[i], idx))
167           {
168             mb->SetBlock(static_cast<unsigned int>(i), this->Cache[idx].Data);
169           }
170         }
171 
172         // change the input to the multiblock data and let child class to do the work
173         // make sure to set the input back to what it was to not break anything upstream
174         inInfo->Set(vtkDataObject::DATA_OBJECT(), mb);
175         retVal = this->RequestData(request, inputVector, outputVector);
176         inInfo->Set(vtkDataObject::DATA_OBJECT(), inData);
177       }
178 
179       this->UpdateTimeSteps.clear();
180       this->RequestUpdateIndex = 0;
181       if (!this->CacheData)
182       {
183         // No caching, remove all
184         this->Cache.clear();
185       }
186       else
187       {
188         // Caching, erase ones outside the cache
189         // Note that this is a first in first out implementation
190         size_t cacheSize = this->Cache.size();
191         if (cacheSize > this->NumberOfCacheEntries)
192         {
193           size_t nToErase = cacheSize - this->NumberOfCacheEntries;
194           this->Cache.erase(this->Cache.begin(), this->Cache.begin() + nToErase);
195         }
196       }
197       request->Remove(vtkStreamingDemandDrivenPipeline::CONTINUE_EXECUTING());
198     }
199     else
200     {
201       request->Set(vtkStreamingDemandDrivenPipeline::CONTINUE_EXECUTING(), 1);
202     }
203 
204     return retVal;
205   }
206 
207   // execute information
208   if (request->Has(vtkDemandDrivenPipeline::REQUEST_INFORMATION()))
209   {
210     // Upstream changed, clear the cache.
211     this->Cache.clear();
212     return this->RequestInformation(request, inputVector, outputVector);
213   }
214 
215   return this->Superclass::ProcessRequest(request, inputVector, outputVector);
216 }
217 
218 //------------------------------------------------------------------------------
PrintSelf(ostream & os,vtkIndent indent)219 void vtkMultiTimeStepAlgorithm::PrintSelf(ostream& os, vtkIndent indent)
220 {
221   this->Superclass::PrintSelf(os, indent);
222 }
223