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