1 /*=========================================================================
2
3 Program: Visualization Toolkit
4 Module: vtkXdmf3Writer.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
16 #include "vtkXdmf3Writer.h"
17
18 #include "vtkDataObject.h"
19 #include "vtkDirectedGraph.h"
20 #include "vtkImageData.h"
21 #include "vtkInformation.h"
22 #include "vtkInformationVector.h"
23 #include "vtkMultiBlockDataSet.h"
24 #include "vtkObjectFactory.h"
25 #include "vtkPointSet.h"
26 #include "vtkRectilinearGrid.h"
27 #include "vtkStreamingDemandDrivenPipeline.h"
28 #include "vtkStructuredGrid.h"
29 #include "vtkXdmf3DataSet.h"
30
31 #include "XdmfDomain.hpp"
32 #include "XdmfGridCollection.hpp"
33 #include "XdmfGridCollectionType.hpp"
34 #include "XdmfHeavyDataWriter.hpp"
35 #include "XdmfWriter.hpp"
36 #include <stack>
37
38 //=============================================================================
39 class vtkXdmf3Writer::Internals {
40 public:
Internals()41 Internals()
42 {
43 }
~Internals()44 ~Internals() {};
Init(const char * filename)45 void Init(const char *filename)
46 {
47 this->Domain = XdmfDomain::New();
48 this->Writer = XdmfWriter::New(filename);
49 this->Writer->setLightDataLimit(0);
50 this->Writer->getHeavyDataWriter()->setReleaseData(true);
51 this->NumberOfTimeSteps = 1;
52 this->CurrentTimeIndex = 0;
53 this->DestinationGroups.push(this->Domain);
54 this->Destination = this->DestinationGroups.top();
55
56 }
SwitchToTemporal()57 void SwitchToTemporal()
58 {
59 shared_ptr<XdmfGridCollection> dest = XdmfGridCollection::New();
60 dest->setType(XdmfGridCollectionType::Temporal());
61 this->DestinationGroups.push(dest);
62 this->Destination = this->DestinationGroups.top();
63 this->Domain->insert(dest);
64 }
WriteDataObject(vtkDataObject * dataSet,bool hasTime,double time,const char * name=0)65 void WriteDataObject(vtkDataObject *dataSet, bool hasTime, double time,
66 const char* name = 0)
67 {
68 if (!dataSet)
69 {
70 return;
71 }
72 switch (dataSet->GetDataObjectType())
73 {
74 case VTK_MULTIBLOCK_DATA_SET:
75 {
76 shared_ptr<XdmfGridCollection> group = XdmfGridCollection::New();
77 this->Destination->insert(group);
78 this->DestinationGroups.push(group);
79 this->Destination = this->DestinationGroups.top();
80 vtkMultiBlockDataSet *mbds = vtkMultiBlockDataSet::SafeDownCast(dataSet);
81 for (unsigned int i = 0; i< mbds->GetNumberOfBlocks(); i++)
82 {
83 vtkDataObject *next = mbds->GetBlock(i);
84 const char* blockName = mbds->GetMetaData(i)->Get(vtkCompositeDataSet::NAME());
85 this->WriteDataObject(next, hasTime, time, blockName);
86 }
87 this->DestinationGroups.pop();
88 this->Destination = this->DestinationGroups.top();
89 break;
90 }
91 case VTK_STRUCTURED_POINTS:
92 case VTK_IMAGE_DATA:
93 case VTK_UNIFORM_GRID:
94 {
95 vtkXdmf3DataSet::VTKToXdmf(
96 vtkImageData::SafeDownCast(dataSet),
97 this->Destination.get(),
98 hasTime, time, name);
99 break;
100 }
101 case VTK_RECTILINEAR_GRID:
102 {
103 vtkXdmf3DataSet::VTKToXdmf(
104 vtkRectilinearGrid::SafeDownCast(dataSet),
105 this->Destination.get(),
106 hasTime, time, name);
107 break;
108 }
109 case VTK_STRUCTURED_GRID:
110 {
111 vtkXdmf3DataSet::VTKToXdmf(
112 vtkStructuredGrid::SafeDownCast(dataSet),
113 this->Destination.get(),
114 hasTime, time, name);
115 break;
116 }
117 case VTK_POLY_DATA:
118 case VTK_UNSTRUCTURED_GRID:
119 {
120 vtkXdmf3DataSet::VTKToXdmf(
121 vtkPointSet::SafeDownCast(dataSet),
122 this->Destination.get(),
123 hasTime, time, name);
124 break;
125 }
126 //case VTK_GRAPH:
127 case VTK_DIRECTED_GRAPH:
128 //case VTK_UNDIRECTED_GRAPH:
129 {
130 vtkXdmf3DataSet::VTKToXdmf(
131 vtkDirectedGraph::SafeDownCast(dataSet),
132 this->Destination.get(),
133 hasTime, time, name);
134 break;
135 }
136 default:
137 {
138 }
139 }
140
141 this->Domain->accept(this->Writer);
142 }
143 boost::shared_ptr<XdmfDomain> Domain;
144 boost::shared_ptr<XdmfDomain> Destination;
145 boost::shared_ptr<XdmfWriter> Writer;
146
147 std::stack<boost::shared_ptr<XdmfDomain> > DestinationGroups;
148
149 int NumberOfTimeSteps;
150 int CurrentTimeIndex;
151 };
152
153 //==============================================================================
154
155 vtkStandardNewMacro(vtkXdmf3Writer);
156
157 //----------------------------------------------------------------------------
vtkXdmf3Writer()158 vtkXdmf3Writer::vtkXdmf3Writer()
159 {
160 this->FileName = NULL;
161 this->LightDataLimit = 100;
162 this->WriteAllTimeSteps = false;
163 this->Internal = new Internals();
164 this->SetNumberOfOutputPorts(0);
165 }
166
167 //----------------------------------------------------------------------------
~vtkXdmf3Writer()168 vtkXdmf3Writer::~vtkXdmf3Writer()
169 {
170 this->SetFileName(NULL);
171 }
172
173 //----------------------------------------------------------------------------
PrintSelf(ostream & os,vtkIndent indent)174 void vtkXdmf3Writer::PrintSelf(ostream& os, vtkIndent indent)
175 {
176 this->Superclass::PrintSelf(os,indent);
177 os << indent << "FileName: " <<
178 (this->FileName ? this->FileName : "(none)") << endl;
179 os << indent << "LightDataLimit: " <<
180 this->LightDataLimit << endl;
181 os << indent << "WriteAllTimeSteps: " <<
182 (this->WriteAllTimeSteps?"ON":"OFF") << endl;
183 }
184
185 //------------------------------------------------------------------------------
SetInputData(vtkDataObject * input)186 void vtkXdmf3Writer::SetInputData(vtkDataObject *input)
187 {
188 this->SetInputDataInternal(0,input);
189 }
190
191 //------------------------------------------------------------------------------
Write()192 int vtkXdmf3Writer::Write()
193 {
194 // Make sure we have input.
195 if (this->GetNumberOfInputConnections(0) < 1)
196 {
197 vtkErrorMacro("No input provided!");
198 return 0;
199 }
200
201 // always write even if the data hasn't changed
202 this->Modified();
203
204 if (!this->Internal)
205 {
206 this->Internal = new Internals();
207 }
208 this->Internal->Init(this->FileName);
209
210 this->Update();
211
212 //this->Internal->Domain->accept(this->Internal->Writer);
213
214 delete this->Internal;
215 this->Internal = NULL;
216
217 return 1;
218 }
219
220 //----------------------------------------------------------------------------
RequestInformation(vtkInformation * vtkNotUsed (request),vtkInformationVector ** inputVector,vtkInformationVector * vtkNotUsed (outputVector))221 int vtkXdmf3Writer::RequestInformation(
222 vtkInformation* vtkNotUsed(request),
223 vtkInformationVector** inputVector,
224 vtkInformationVector* vtkNotUsed(outputVector))
225 {
226 // Does the input have timesteps?
227 vtkInformation *inInfo = inputVector[0]->GetInformationObject(0);
228 if ( inInfo->Has(vtkStreamingDemandDrivenPipeline::TIME_STEPS()) )
229 {
230 this->Internal->NumberOfTimeSteps =
231 inInfo->Length( vtkStreamingDemandDrivenPipeline::TIME_STEPS() );
232 }
233 else
234 {
235 this->Internal->NumberOfTimeSteps = 1;
236 }
237 //cerr << "WRITER NUM TS = " << this->Internal->NumberOfTimeSteps << endl;
238
239 return 1;
240 }
241
242 //----------------------------------------------------------------------------
RequestUpdateExtent(vtkInformation * vtkNotUsed (request),vtkInformationVector ** inputVector,vtkInformationVector * vtkNotUsed (outputVector))243 int vtkXdmf3Writer::RequestUpdateExtent(
244 vtkInformation* vtkNotUsed(request),
245 vtkInformationVector** inputVector,
246 vtkInformationVector* vtkNotUsed(outputVector))
247 {
248 double *inTimes = inputVector[0]->GetInformationObject(0)->Get(
249 vtkStreamingDemandDrivenPipeline::TIME_STEPS());
250 if (inTimes && this->WriteAllTimeSteps)
251 {
252 //TODO:? Add a user ivar to specify a particular time,
253 //which is different from current time. Can do it by updating
254 //to a particular time then writing without writealltimesteps,
255 //but that is annoying.
256 double timeReq = inTimes[this->Internal->CurrentTimeIndex];
257 inputVector[0]->GetInformationObject(0)->Set(
258 vtkStreamingDemandDrivenPipeline::UPDATE_TIME_STEP(),
259 timeReq);
260 }
261
262 return 1;
263 }
264
265 //----------------------------------------------------------------------------
RequestData(vtkInformation * request,vtkInformationVector ** inputVector,vtkInformationVector * vtkNotUsed (outputVector))266 int vtkXdmf3Writer::RequestData(
267 vtkInformation* request,
268 vtkInformationVector** inputVector,
269 vtkInformationVector* vtkNotUsed(outputVector))
270 {
271 if (!this->Internal->Domain)
272 {
273 //call Write() instead of RD() directly. Write() does setup first before it calls RD().
274 return 1;
275 }
276
277 this->Internal->Writer->setLightDataLimit(this->LightDataLimit);
278
279 if (this->Internal->CurrentTimeIndex == 0 &&
280 this->WriteAllTimeSteps &&
281 this->Internal->NumberOfTimeSteps > 1)
282 {
283 // Tell the pipeline to start looping.
284 this->Internal->SwitchToTemporal();
285 request->Set(vtkStreamingDemandDrivenPipeline::CONTINUE_EXECUTING(), 1);
286 }
287
288 vtkInformation* inInfo = inputVector[0]->GetInformationObject(0);
289 vtkDataObject* input = inInfo->Get(vtkDataObject::DATA_OBJECT());
290 vtkInformation *inDataInfo = input->GetInformation();
291 double dataT = 0;
292 bool hasTime = false;
293 if (inDataInfo->Has(vtkDataObject::DATA_TIME_STEP()))
294 {
295 dataT = input->GetInformation()->Get(vtkDataObject::DATA_TIME_STEP());
296 hasTime = true;
297 }
298 this->Internal->WriteDataObject(input, hasTime, dataT);
299
300 this->Internal->CurrentTimeIndex++;
301 if (this->Internal->CurrentTimeIndex >= this->Internal->NumberOfTimeSteps &&
302 this->WriteAllTimeSteps)
303 {
304 // Tell the pipeline to stop looping.
305 request->Remove(vtkStreamingDemandDrivenPipeline::CONTINUE_EXECUTING());
306 this->Internal->CurrentTimeIndex = 0;
307 }
308
309 return 1;
310 }
311