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