1 /*=========================================================================
2 
3   Program:   Visualization Toolkit
4   Module:    vtkXdmfWriter.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 "vtkXdmfWriter.h"
17 
18 #include "vtkCellArray.h"
19 #include "vtkCellData.h"
20 #include "vtkCellType.h"
21 #include "vtkCompositeDataPipeline.h"
22 #include "vtkCompositeDataSet.h"
23 #include "vtkDataObject.h"
24 #include "vtkDataObjectTreeIterator.h"
25 #include "vtkDataSet.h"
26 #include "vtkDataSetAttributes.h"
27 #include "vtkFieldData.h"
28 #include "vtkGenericCell.h"
29 #include "vtkIdList.h"
30 #include "vtkImageData.h"
31 #include "vtkInformation.h"
32 #include "vtkInformationVector.h"
33 #include "vtkMultiBlockDataSet.h"
34 #include "vtkObjectFactory.h"
35 #include "vtkPointData.h"
36 #include "vtkPoints.h"
37 #include "vtkPointSet.h"
38 #include "vtkPolyData.h"
39 #include "vtkRectilinearGrid.h"
40 #include "vtkSmartPointer.h"
41 #include "vtkStructuredGrid.h"
42 #include "vtkTypeTraits.h"
43 #include "vtkUnstructuredGrid.h"
44 
45 #include "XdmfArray.h"
46 #include "XdmfAttribute.h"
47 #include "XdmfDataDesc.h"
48 #include "XdmfDOM.h"
49 #include "XdmfDomain.h"
50 #include "XdmfGeometry.h"
51 #include "XdmfGrid.h"
52 #include "XdmfRoot.h"
53 #include "XdmfTime.h"
54 #include "XdmfTopology.h"
55 
56 #include <algorithm>
57 #include <map>
58 #include <stdio.h>
59 #include <vector>
60 
61 #include <libxml/tree.h> // always after std::blah stuff
62 
63 #if defined(_WIN32) && !defined(__CYGWIN__)
64 # define SNPRINTF _snprintf
65 #else
66 # define SNPRINTF snprintf
67 #endif
68 
69 using namespace xdmf2;
70 
71 struct  _xmlNode;
72 typedef _xmlNode *XdmfXmlNode;
73 struct vtkXW2NodeHelp {
74   xdmf2::XdmfDOM     *DOM;
75   XdmfXmlNode  node;
76   bool         staticFlag;
vtkXW2NodeHelpvtkXW2NodeHelp77   vtkXW2NodeHelp(xdmf2::XdmfDOM *d, XdmfXmlNode n, bool f) : DOM(d), node(n), staticFlag(f) {};
78 };
79 
80 class vtkXdmfWriterDomainMemoryHandler
81 {
82   public:
vtkXdmfWriterDomainMemoryHandler()83     vtkXdmfWriterDomainMemoryHandler()
84       {
85         domain = new XdmfDomain();
86       }
~vtkXdmfWriterDomainMemoryHandler()87     ~vtkXdmfWriterDomainMemoryHandler()
88       {
89         for(std::vector<xdmf2::XdmfGrid*>::iterator iter = domainGrids.begin(); iter != domainGrids.end(); ++iter)
90         {
91           delete *iter;
92         }
93         delete domain;
94       }
InsertGrid(xdmf2::XdmfGrid * grid)95   void InsertGrid(xdmf2::XdmfGrid* grid)
96       {
97         domain->Insert(grid);
98         domainGrids.push_back(grid);
99       }
InsertIntoRoot(XdmfRoot & root)100     void InsertIntoRoot(XdmfRoot& root)
101       {
102         root.Insert(domain);
103       }
104   private:
105     XdmfDomain* domain;
106   std::vector<xdmf2::XdmfGrid*> domainGrids;
107 };
108 
109 //==============================================================================
110 
111 struct vtkXdmfWriterInternal
112 {
113   class CellType
114     {
115   public:
CellType()116     CellType() : VTKType(0), NumPoints(0) {}
CellType(const CellType & ct)117     CellType(const CellType& ct) : VTKType(ct.VTKType), NumPoints(ct.NumPoints) {}
118     vtkIdType VTKType;
119     vtkIdType NumPoints;
operator <(const CellType & ct) const120     bool operator<(const CellType& ct) const
121       {
122       return this->VTKType < ct.VTKType || (this->VTKType == ct.VTKType && this->NumPoints < ct.NumPoints);
123       }
operator ==(const CellType & ct) const124     bool operator==(const CellType& ct) const
125       {
126       return this->VTKType == ct.VTKType && this->NumPoints == ct.NumPoints;
127       }
operator =(const CellType & ct)128     CellType& operator=(const CellType& ct)
129       {
130       this->VTKType = ct.VTKType;
131       this->NumPoints = ct.NumPoints;
132       return *this;
133       }
134 
135     };
136   typedef std::map<CellType, vtkSmartPointer<vtkIdList> > MapOfCellTypes;
137   static void DetermineCellTypes(vtkPointSet *t, MapOfCellTypes& vec);
138 };
139 
140 //----------------------------------------------------------------------------
DetermineCellTypes(vtkPointSet * t,vtkXdmfWriterInternal::MapOfCellTypes & vec)141 void vtkXdmfWriterInternal::DetermineCellTypes(vtkPointSet * t, vtkXdmfWriterInternal::MapOfCellTypes& vec)
142 {
143   if ( !t )
144     {
145     return;
146     }
147   vtkIdType cc;
148   vtkGenericCell* cell = vtkGenericCell::New();
149   for ( cc = 0; cc < t->GetNumberOfCells(); cc ++ )
150     {
151     vtkXdmfWriterInternal::CellType ct;
152     t->GetCell(cc, cell);
153     ct.VTKType = cell->GetCellType();
154     ct.NumPoints = cell->GetNumberOfPoints();
155     vtkXdmfWriterInternal::MapOfCellTypes::iterator it = vec.find(ct);
156     if ( it == vec.end() )
157       {
158       vtkIdList *l = vtkIdList::New();
159       it = vec.insert(vtkXdmfWriterInternal::MapOfCellTypes::value_type(ct,
160           vtkSmartPointer<vtkIdList>(l))).first;
161       l->Delete();
162       }
163     // it->second->InsertUniqueId(cc);;
164     it->second->InsertNextId(cc);;
165     }
166   cell->Delete();
167 }
168 
169 //==============================================================================
170 
171 vtkStandardNewMacro(vtkXdmfWriter);
172 
173 //----------------------------------------------------------------------------
vtkXdmfWriter()174 vtkXdmfWriter::vtkXdmfWriter()
175 {
176   this->FileName = NULL;
177   this->HeavyDataFileName = NULL;
178   this->HeavyDataGroupName = NULL;
179   this->DOM = NULL;
180   this->Piece = 0;  //for parallel
181   this->NumberOfPieces = 1;
182   this->LightDataLimit = 100;
183   this->WriteAllTimeSteps = 0;
184   this->NumberOfTimeSteps = 1;
185   this->CurrentTimeIndex = 0;
186   this->TopTemporalGrid = NULL;
187   this->DomainMemoryHandler = NULL;
188   this->SetNumberOfOutputPorts(0);
189 }
190 
191 //----------------------------------------------------------------------------
~vtkXdmfWriter()192 vtkXdmfWriter::~vtkXdmfWriter()
193 {
194   this->SetFileName(NULL);
195   this->SetHeavyDataFileName(NULL);
196   this->SetHeavyDataGroupName(NULL);
197   if (this->DOM)
198     {
199     delete this->DOM;
200     this->DOM = NULL;
201     }
202   if (this->DomainMemoryHandler)
203     {
204     delete this->DomainMemoryHandler;
205     }
206   if (this->TopTemporalGrid)
207     {
208     delete this->TopTemporalGrid;
209     this->TopTemporalGrid = NULL;
210     }
211   delete this->DomainMemoryHandler;
212 
213   //TODO: Verify memory isn't leaking
214 }
215 
216 //-----------------------------------------------------------------------------
CreateDefaultExecutive()217 vtkExecutive* vtkXdmfWriter::CreateDefaultExecutive()
218 {
219   return vtkCompositeDataPipeline::New();
220 }
221 
222 //----------------------------------------------------------------------------
PrintSelf(ostream & os,vtkIndent indent)223 void vtkXdmfWriter::PrintSelf(ostream& os, vtkIndent indent)
224 {
225   this->Superclass::PrintSelf(os,indent);
226   os << indent << "FileName: " <<
227     (this->FileName ? this->FileName : "(none)") << endl;
228   os << indent << "LightDataLimit: " <<
229     this->LightDataLimit << endl;
230   os << indent << "WriteAllTimeSteps: " <<
231     (this->WriteAllTimeSteps?"ON":"OFF") << endl;
232 }
233 
234 //------------------------------------------------------------------------------
SetInputData(vtkDataObject * input)235 void vtkXdmfWriter::SetInputData(vtkDataObject *input)
236 {
237   this->SetInputDataInternal(0,input);
238 }
239 
240 //------------------------------------------------------------------------------
FillInputPortInformation(int,vtkInformation * info)241 int vtkXdmfWriter::FillInputPortInformation(int, vtkInformation *info)
242 {
243   info->Set(vtkAlgorithm::INPUT_REQUIRED_DATA_TYPE(), "vtkDataObject");
244   return 1;
245 }
246 
247 //------------------------------------------------------------------------------
Write()248 int vtkXdmfWriter::Write()
249 {
250   // Make sure we have input.
251   if (this->GetNumberOfInputConnections(0) < 1)
252     {
253     vtkErrorMacro("No input provided!");
254     return 0;
255     }
256 
257   // always write even if the data hasn't changed
258   this->Modified();
259 
260   //TODO: Specify name of heavy data companion file?
261   if (!this->DOM)
262     {
263     this->DOM = new xdmf2::XdmfDOM();
264     }
265   this->DOM->SetOutputFileName(this->FileName);
266 
267   XdmfRoot root;
268   root.SetDOM(this->DOM);
269   root.SetVersion(2.2);
270   root.Build();
271 
272   if (this->DomainMemoryHandler)
273     {
274     delete this->DomainMemoryHandler;
275     }
276   this->DomainMemoryHandler = new vtkXdmfWriterDomainMemoryHandler();
277   this->DomainMemoryHandler->InsertIntoRoot(root);
278 
279   this->Update();
280 
281   root.Build();
282   this->DOM->Write();
283 
284   delete this->DomainMemoryHandler;
285   this->DomainMemoryHandler = NULL;
286 
287   return 1;
288 }
289 
290 //----------------------------------------------------------------------------
RequestInformation(vtkInformation * vtkNotUsed (request),vtkInformationVector ** inputVector,vtkInformationVector * vtkNotUsed (outputVector))291 int vtkXdmfWriter::RequestInformation(
292   vtkInformation* vtkNotUsed(request),
293   vtkInformationVector** inputVector,
294   vtkInformationVector* vtkNotUsed(outputVector))
295 {
296   // Does the input have timesteps?
297   vtkInformation *inInfo = inputVector[0]->GetInformationObject(0);
298   if ( inInfo->Has(vtkStreamingDemandDrivenPipeline::TIME_STEPS()) )
299     {
300     this->NumberOfTimeSteps =
301       inInfo->Length( vtkStreamingDemandDrivenPipeline::TIME_STEPS() );
302     }
303   else
304     {
305     this->NumberOfTimeSteps = 1;
306     }
307 
308   return 1;
309 }
310 
311 //----------------------------------------------------------------------------
RequestUpdateExtent(vtkInformation * vtkNotUsed (request),vtkInformationVector ** inputVector,vtkInformationVector * vtkNotUsed (outputVector))312 int vtkXdmfWriter::RequestUpdateExtent(
313   vtkInformation* vtkNotUsed(request),
314   vtkInformationVector** inputVector,
315   vtkInformationVector* vtkNotUsed(outputVector))
316 {
317   double *inTimes = inputVector[0]->GetInformationObject(0)->Get(
318       vtkStreamingDemandDrivenPipeline::TIME_STEPS());
319   if (inTimes && this->WriteAllTimeSteps)
320     {
321     //TODO:? Add a user ivar to specify a particular time,
322     //which is different from current time. Can do it by updating
323     //to a particular time then writing without writealltimesteps,
324     //but that is annoying.
325     double timeReq = inTimes[this->CurrentTimeIndex];
326     inputVector[0]->GetInformationObject(0)->Set(
327         vtkStreamingDemandDrivenPipeline::UPDATE_TIME_STEP(),
328         timeReq);
329     }
330 
331   return 1;
332 }
333 
334 //----------------------------------------------------------------------------
RequestData(vtkInformation * request,vtkInformationVector ** inputVector,vtkInformationVector * vtkNotUsed (outputVector))335 int vtkXdmfWriter::RequestData(
336   vtkInformation* request,
337   vtkInformationVector** inputVector,
338   vtkInformationVector* vtkNotUsed(outputVector))
339 {
340   if (!this->DomainMemoryHandler)
341     {
342     //call Write instead of this directly. That does setup first, then calls this.
343     return 1;
344     }
345 
346   if (this->CurrentTimeIndex == 0 &&
347       this->WriteAllTimeSteps &&
348       this->NumberOfTimeSteps > 1)
349     {
350     // Tell the pipeline to start looping.
351     request->Set(vtkStreamingDemandDrivenPipeline::CONTINUE_EXECUTING(), 1);
352 
353     // make a top level temporal grid just under domain
354     if (this->TopTemporalGrid)
355       {
356       delete this->TopTemporalGrid;
357       this->TopTemporalGrid = NULL;
358       }
359 
360     xdmf2::XdmfGrid *tgrid = new xdmf2::XdmfGrid();
361     tgrid->SetDeleteOnGridDelete(true);
362     tgrid->SetGridType(XDMF_GRID_COLLECTION);
363     tgrid->SetCollectionType(XDMF_GRID_COLLECTION_TEMPORAL);
364     XdmfTopology *t = tgrid->GetTopology();
365     t->SetTopologyType(XDMF_NOTOPOLOGY);
366     XdmfGeometry *geo = tgrid->GetGeometry();
367     geo->SetGeometryType(XDMF_GEOMETRY_NONE);
368 
369     this->DomainMemoryHandler->InsertGrid(tgrid);
370 
371     this->TopTemporalGrid = tgrid;
372     }
373 
374   xdmf2::XdmfGrid *grid = new xdmf2::XdmfGrid();
375   grid->SetDeleteOnGridDelete(true);
376   if (this->TopTemporalGrid)
377     {
378     this->TopTemporalGrid->Insert(grid);
379     }
380   else
381     {
382     this->DomainMemoryHandler->InsertGrid(grid);
383     }
384 
385   vtkInformation* inInfo = inputVector[0]->GetInformationObject(0);
386   vtkDataObject* input = inInfo->Get(vtkDataObject::DATA_OBJECT());
387   vtkInformation *inDataInfo = input->GetInformation();
388   if (inDataInfo->Has(vtkDataObject::DATA_TIME_STEP()))
389     {
390     //I am assuming we are not given a temporal data object and getting just one time.
391     double dataT = input->GetInformation()->Get(vtkDataObject::DATA_TIME_STEP());
392     //cerr << "Writing " << this->CurrentTimeIndex << " " << *dataT << endl;
393 
394     XdmfTime *xT = grid->GetTime();
395     xT->SetDeleteOnGridDelete(true);
396     xT->SetTimeType(XDMF_TIME_SINGLE);
397     xT->SetValue(dataT);
398     grid->Insert(xT);
399     }
400 
401   this->WriteDataSet(input, grid);
402   //delete grid; //domain takes care of it?
403 
404   this->CurrentTimeIndex++;
405   if (this->CurrentTimeIndex >= this->NumberOfTimeSteps &&
406       this->WriteAllTimeSteps)
407     {
408     // Tell the pipeline to stop looping.
409     request->Remove(vtkStreamingDemandDrivenPipeline::CONTINUE_EXECUTING());
410     this->CurrentTimeIndex = 0;
411     //delete this->TopTemporalGrid; //domain takes care of it?
412     this->TopTemporalGrid = NULL;
413     }
414 
415   return 1;
416 }
417 
418 //------------------------------------------------------------------------------
WriteDataSet(vtkDataObject * dobj,xdmf2::XdmfGrid * grid)419 int vtkXdmfWriter::WriteDataSet(vtkDataObject *dobj, xdmf2::XdmfGrid *grid)
420 {
421   //TODO:
422   // respect parallelism
423   if (!dobj)
424     {
425     //vtkWarningMacro(<< "Null DS, someone else will take care of it");
426     return 0;
427     }
428   if (!grid)
429     {
430     vtkWarningMacro(<< "Something is wrong, grid should have already been created for " << dobj);
431     return 0;
432     }
433 
434   vtkCompositeDataSet *cdobj = vtkCompositeDataSet::SafeDownCast(dobj);
435   if (cdobj)//!dobj->IsTypeOf("vtkCompositeDataSet")) //TODO: Why doesn't IsTypeOf work?
436     {
437     this->WriteCompositeDataSet(cdobj, grid);
438     return 1;
439     }
440 
441   return this->WriteAtomicDataSet(dobj, grid);
442 }
443 
444 //------------------------------------------------------------------------------
WriteCompositeDataSet(vtkCompositeDataSet * dobj,xdmf2::XdmfGrid * grid)445 int vtkXdmfWriter::WriteCompositeDataSet(vtkCompositeDataSet *dobj, xdmf2::XdmfGrid *grid)
446 {
447   //cerr << "internal node " << dobj << " is a " << dobj->GetClassName() << endl;
448   if (dobj->IsA("vtkMultiPieceDataSet"))
449     {
450     grid->SetGridType(XDMF_GRID_COLLECTION);
451     grid->SetCollectionType(XDMF_GRID_COLLECTION_SPATIAL);
452     }
453   else
454     {
455     //fine for vtkMultiBlockDataSet
456     //vtkHierarchicalBoxDataSet would be better served by a different xdmf tree type
457     //vtkTemporalDataSet is internal to the VTK pipeline so I am ingnoring it
458     grid->SetGridType(XDMF_GRID_TREE);
459     }
460 
461   XdmfTopology *t = grid->GetTopology();
462   t->SetTopologyType(XDMF_NOTOPOLOGY);
463   XdmfGeometry *geo = grid->GetGeometry();
464   geo->SetGeometryType(XDMF_GEOMETRY_NONE);
465 
466   vtkCompositeDataIterator* iter = dobj->NewIterator();
467   vtkDataObjectTreeIterator* treeIter =
468     vtkDataObjectTreeIterator::SafeDownCast(iter);
469   if(treeIter)
470     {
471     treeIter->VisitOnlyLeavesOff();
472     treeIter->TraverseSubTreeOff();
473     }
474   vtkMultiBlockDataSet* mbds = vtkMultiBlockDataSet::SafeDownCast(dobj);
475   iter->GoToFirstItem();
476   while (!iter->IsDoneWithTraversal())
477     {
478     xdmf2::XdmfGrid *childsGrid = new xdmf2::XdmfGrid();
479     childsGrid->SetDeleteOnGridDelete(true);
480     grid->Insert(childsGrid);
481     vtkDataObject* ds = iter->GetCurrentDataObject();
482 
483     if (mbds)
484       {
485       vtkInformation* info = mbds->GetMetaData(iter->GetCurrentFlatIndex() - 1);
486       if (info)
487         {
488         childsGrid->SetName(info->Get(vtkCompositeDataSet::NAME()));
489         }
490       }
491 
492     this->WriteDataSet(ds, childsGrid);
493     //delete childsGrid; //parent deletes children in Xdmf
494     iter->GoToNextItem();
495     }
496   iter->Delete();
497 
498   return 1;
499 }
500 //------------------------------------------------------------------------------
CreateTopology(vtkDataSet * ds,xdmf2::XdmfGrid * grid,vtkIdType PDims[3],vtkIdType CDims[3],vtkIdType & PRank,vtkIdType & CRank,void * staticdata)501 int vtkXdmfWriter::CreateTopology(vtkDataSet *ds, xdmf2::XdmfGrid *grid, vtkIdType PDims[3], vtkIdType CDims[3], vtkIdType &PRank, vtkIdType &CRank, void *staticdata)
502 {
503   //cerr << "Writing " << dobj << " a " << dobj->GetClassName() << endl;
504 
505   grid->SetGridType(XDMF_GRID_UNIFORM);
506 
507   const char *heavyName = NULL;
508   std::string heavyDataSetName;
509   if (this->HeavyDataFileName)
510     {
511     heavyDataSetName = std::string(this->HeavyDataFileName) + ":";
512     if (this->HeavyDataGroupName)
513       {
514       heavyDataSetName = heavyDataSetName + HeavyDataGroupName + "/Topology";
515       }
516     heavyName = heavyDataSetName.c_str();
517     }
518 
519   XdmfTopology *t = grid->GetTopology();
520 
521   //
522   // If the topology is unchanged from last grid written, we can reuse the XML
523   // and avoid writing any heavy data. We must still compute dimensions etc
524   // otherwise the attribute arrays don't get initialized properly
525   //
526   bool reusing_topology = false;
527   vtkXW2NodeHelp *staticnode = (vtkXW2NodeHelp*)staticdata;
528   if (staticnode) {
529     if (staticnode->staticFlag) {
530       grid->Set("TopologyConstant", "True");
531     }
532     if (staticnode->DOM && staticnode->node) {
533       XdmfXmlNode       staticTopo = staticnode->DOM->FindElement("Topology", 0, staticnode->node);
534       XdmfConstString      xmltext = staticnode->DOM->Serialize(staticTopo->children);
535       XdmfConstString   dimensions = staticnode->DOM->Get(staticTopo, "Dimensions");
536       XdmfConstString topologyType = staticnode->DOM->Get(staticTopo, "TopologyType");
537       //
538       t->SetTopologyTypeFromString(topologyType);
539       t->SetNumberOfElements(atoi(dimensions));
540       t->SetDataXml(xmltext);
541       reusing_topology = true;
542       // @TODO : t->SetNodesPerElement(ppCell);
543     }
544   }
545 
546   //Topology
547   switch (ds->GetDataObjectType()) {
548   case VTK_STRUCTURED_POINTS:
549   case VTK_IMAGE_DATA:
550   case VTK_UNIFORM_GRID:
551     {
552     t->SetTopologyType(XDMF_3DCORECTMESH);
553     t->SetLightDataLimit(this->LightDataLimit);
554     vtkImageData *id = vtkImageData::SafeDownCast(ds);
555     int wExtent[6];
556     id->GetExtent(wExtent);
557     XdmfInt64 Dims[3];
558     Dims[2] = wExtent[1] - wExtent[0] + 1;
559     Dims[1] = wExtent[3] - wExtent[2] + 1;
560     Dims[0] = wExtent[5] - wExtent[4] + 1;
561     XdmfDataDesc *dd = t->GetShapeDesc();
562     dd->SetShape(3, Dims);
563     //TODO: verify row/column major ordering
564 
565     PDims[0] = Dims[0];
566     PDims[1] = Dims[1];
567     PDims[2] = Dims[2];
568     CDims[0] = Dims[0] - 1;
569     CDims[1] = Dims[1] - 1;
570     CDims[2] = Dims[2] - 1;
571     }
572     break;
573   case VTK_RECTILINEAR_GRID:
574     {
575     t->SetTopologyType(XDMF_3DRECTMESH);
576     vtkRectilinearGrid *rgrid = vtkRectilinearGrid::SafeDownCast(ds);
577     int wExtent[6];
578     rgrid->GetExtent(wExtent);
579     XdmfInt64 Dims[3];
580     Dims[2] = wExtent[1] - wExtent[0] + 1;
581     Dims[1] = wExtent[3] - wExtent[2] + 1;
582     Dims[0] = wExtent[5] - wExtent[4] + 1;
583     XdmfDataDesc *dd = t->GetShapeDesc();
584     dd->SetShape(3, Dims);
585     //TODO: verify row/column major ordering
586 
587     PDims[0] = Dims[0];
588     PDims[1] = Dims[1];
589     PDims[2] = Dims[2];
590     CDims[0] = Dims[0] - 1;
591     CDims[1] = Dims[1] - 1;
592     CDims[2] = Dims[2] - 1;
593     }
594     break;
595   case VTK_STRUCTURED_GRID:
596     {
597     vtkStructuredGrid *sgrid = vtkStructuredGrid::SafeDownCast(ds);
598     int rank = CRank = PRank = sgrid->GetDataDimension();
599     if( rank == 3 ){
600         t->SetTopologyType(XDMF_3DSMESH);
601     }
602     else if( rank == 2){
603         t->SetTopologyType(XDMF_2DSMESH);
604     }
605     else{
606         XdmfErrorMessage("Structured Grid Dimensions can be 2 or 3: "<< rank << " found");
607     }
608 
609     int wExtent[6];
610     sgrid->GetExtent(wExtent);
611     XdmfInt64 Dims[3];
612     Dims[2] = wExtent[1] - wExtent[0] + 1;
613     Dims[1] = wExtent[3] - wExtent[2] + 1;
614     Dims[0] = wExtent[5] - wExtent[4] + 1;
615     XdmfDataDesc *dd = t->GetShapeDesc();
616     dd->SetShape(rank, Dims);
617     //TODO: verify row/column major ordering
618 
619     PDims[0] = Dims[0];
620     PDims[1] = Dims[1];
621     PDims[2] = Dims[2];
622     CDims[0] = Dims[0] - 1;
623     CDims[1] = Dims[1] - 1;
624     CDims[2] = Dims[2] - 1;
625     }
626     break;
627   case VTK_POLY_DATA:
628   case VTK_UNSTRUCTURED_GRID:
629     {
630     PRank = 1;
631     PDims[0] = ds->GetNumberOfPoints();
632     CRank = 1;
633     CDims[0] = ds->GetNumberOfCells();
634     if (reusing_topology)
635       {
636       // don't need to do all this again
637       // @TODO : t->SetNodesPerElement(ppCell);
638       break;
639       }
640     vtkXdmfWriterInternal::MapOfCellTypes cellTypes;
641     vtkXdmfWriterInternal::DetermineCellTypes(vtkPointSet::SafeDownCast(ds), cellTypes);
642 
643     //TODO: When is it beneficial to take advantage of a homogenous topology?
644     //If no compelling reason not to used MIXED, then this should go away.
645     //This special case code requires an in memory copy just to get rid of
646     //each cell's preceeding number of points int.
647     //If don't have to do that, could use pointer sharing,
648     //and the extra code path is bound to cause problems eventually.
649     if ( cellTypes.size() == 1 )
650       {
651       //cerr << "Homogeneous topology" << endl;
652       t->SetNumberOfElements(ds->GetNumberOfCells());
653       const vtkXdmfWriterInternal::CellType* ct = &cellTypes.begin()->first;
654       vtkIdType ppCell = ct->NumPoints;
655       switch(ct->VTKType)
656         {
657         case VTK_VERTEX :
658         case VTK_POLY_VERTEX :
659           t->SetTopologyType(XDMF_POLYVERTEX);
660           break;
661         case VTK_LINE :
662         case VTK_POLY_LINE :
663           t->SetTopologyType(XDMF_POLYLINE);
664           t->SetNodesPerElement(ppCell);
665           break;
666         case VTK_TRIANGLE :
667         case VTK_TRIANGLE_STRIP :
668           t->SetTopologyType(XDMF_TRI);
669           break;
670         case VTK_POLYGON :
671           t->SetTopologyType(XDMF_POLYGON);
672           t->SetNodesPerElement(ppCell);
673           break;
674         case VTK_PIXEL :
675         case VTK_QUAD :
676           t->SetTopologyType(XDMF_QUAD);
677           break;
678         case VTK_TETRA :
679           t->SetTopologyType(XDMF_TET);
680           break;
681         case VTK_VOXEL :
682         case VTK_HEXAHEDRON :
683           t->SetTopologyType(XDMF_HEX);
684           break;
685         case VTK_WEDGE :
686           t->SetTopologyType(XDMF_WEDGE);
687           break;
688         case VTK_PYRAMID :
689           t->SetTopologyType(XDMF_PYRAMID);
690           break;
691         case VTK_EMPTY_CELL :
692         default :
693           t->SetTopologyType(XDMF_NOTOPOLOGY);
694           break;
695         }
696       XdmfArray *di = t->GetConnectivity();
697       di->SetHeavyDataSetName(heavyName);
698       if (VTK_SIZEOF_ID_TYPE==sizeof(XDMF_64_INT))
699         {
700         di->SetNumberType(XDMF_INT64_TYPE);
701         }
702       else
703         {
704         di->SetNumberType(XDMF_INT32_TYPE);
705         }
706       XdmfInt64 hDim[2];
707       hDim[0] = ds->GetNumberOfCells();
708       hDim[1] = ppCell;
709       di->SetShape(2, hDim);
710       vtkIdList* il = cellTypes[*ct].GetPointer();
711       vtkIdList* cellPoints = vtkIdList::New();
712       vtkIdType cvnt=0;
713       for(vtkIdType i = 0 ; i < ds->GetNumberOfCells(); i++ )
714         {
715         ds->GetCellPoints(il->GetId(i), cellPoints);
716         if ( ct->VTKType == VTK_VOXEL )
717           {
718           // Hack for VTK_VOXEL
719           di->SetValue(cvnt++, cellPoints->GetId(0));
720           di->SetValue(cvnt++, cellPoints->GetId(1));
721           di->SetValue(cvnt++, cellPoints->GetId(3));
722           di->SetValue(cvnt++, cellPoints->GetId(2));
723           di->SetValue(cvnt++, cellPoints->GetId(4));
724           di->SetValue(cvnt++, cellPoints->GetId(5));
725           di->SetValue(cvnt++, cellPoints->GetId(7));
726           di->SetValue(cvnt++, cellPoints->GetId(6));
727           }
728         else if ( ct->VTKType == VTK_PIXEL )
729           {
730           // Hack for VTK_PIXEL
731           di->SetValue(cvnt++, cellPoints->GetId(0));
732           di->SetValue(cvnt++, cellPoints->GetId(1));
733           di->SetValue(cvnt++, cellPoints->GetId(3));
734           di->SetValue(cvnt++, cellPoints->GetId(2));
735           }
736         else
737           {
738           for( vtkIdType j = 0 ; j < ppCell ; j++ )
739             {
740             di->SetValue(cvnt++, cellPoints->GetId(j));
741             }
742           }//pd has 4 arrays, so it is rarely homogeoneous
743         }
744       cellPoints->Delete();
745       } //homogenous
746     else
747       {
748       //cerr << "Nonhomogeneous topology" << endl;
749       //Non Homogeneous, used mixed topology type to dump them all
750       t->SetTopologyType(XDMF_MIXED);
751       vtkIdType numCells = ds->GetNumberOfCells();
752       t->SetNumberOfElements(numCells);
753       XdmfArray *di = t->GetConnectivity();
754       di->SetHeavyDataSetName(heavyName);
755       if (VTK_SIZEOF_ID_TYPE==sizeof(XDMF_64_INT))
756         {
757         di->SetNumberType(XDMF_INT64_TYPE);
758         }
759       else
760         {
761         di->SetNumberType(XDMF_INT32_TYPE);
762         }
763       vtkIdTypeArray *da = vtkIdTypeArray::New();
764       da->SetNumberOfComponents(1);
765       vtkUnstructuredGrid *ugrid = vtkUnstructuredGrid::SafeDownCast(ds);
766       const int ESTIMATE=4; /*celltype+numids+id0+id1 or celtype+id0+id1+id2*/
767       if (ugrid)
768         {
769         da->Allocate(ugrid->GetCells()->GetSize()*ESTIMATE);
770         }
771       else
772         {
773         vtkPolyData *pd = vtkPolyData::SafeDownCast(ds);
774         vtkIdType sizev = pd->GetVerts()->GetSize();
775         vtkIdType sizel = pd->GetLines()->GetSize();
776         vtkIdType sizep = pd->GetPolys()->GetSize();
777         vtkIdType sizes = pd->GetStrips()->GetSize();
778         vtkIdType rtotal = sizev+sizel+sizep+sizes;
779         da->Allocate(rtotal*ESTIMATE);
780         }
781 
782       vtkIdType cntr = 0;
783       for (vtkIdType cid=0 ; cid < numCells; cid++)
784         {
785         vtkCell *cell = ds->GetCell(cid);
786         vtkIdType cellType = ds->GetCellType(cid);
787         vtkIdType numPts = cell->GetNumberOfPoints();
788         switch(cellType)
789           {
790           case VTK_VERTEX :
791           case VTK_POLY_VERTEX :
792             da->InsertValue(cntr++, XDMF_POLYVERTEX);
793             da->InsertValue(cntr++, numPts);
794             break;
795           case VTK_LINE :
796           case VTK_POLY_LINE :
797             da->InsertValue(cntr++, XDMF_POLYLINE);
798             da->InsertValue(cntr++, cell->GetNumberOfPoints());
799             break;
800           //case VTK_TRIANGLE_STRIP :
801           //TODO: Split tri strips into triangles
802           //t->SetTopologyType(XDMF_TRI);
803           //break;
804           case VTK_TRIANGLE :
805             da->InsertValue(cntr++, XDMF_TRI);
806             break;
807           case VTK_POLYGON :
808             da->InsertValue(cntr++, XDMF_POLYGON);
809             da->InsertValue(cntr++, cell->GetNumberOfPoints());
810             break;
811           case VTK_PIXEL :
812           case VTK_QUAD :
813             da->InsertValue(cntr++, XDMF_POLYGON);
814             break;
815           case VTK_TETRA :
816             da->InsertValue(cntr++, XDMF_TET);
817             break;
818           case VTK_VOXEL :
819             da->InsertValue(cntr++, XDMF_HEX);
820             break;
821           case VTK_HEXAHEDRON :
822             da->InsertValue(cntr++, XDMF_HEX);
823             break;
824           case VTK_WEDGE :
825             da->InsertValue(cntr++, XDMF_WEDGE);
826           break;
827           case VTK_PYRAMID :
828             da->InsertValue(cntr++, XDMF_PYRAMID);
829           break;
830           default :
831             da->InsertValue(cntr++,XDMF_NOTOPOLOGY);
832             break;
833           }
834         if ( cellType == VTK_VOXEL )
835           {
836           // Hack for VTK_VOXEL
837           da->InsertValue(cntr++, cell->GetPointId(0));
838           da->InsertValue(cntr++, cell->GetPointId(1));
839           da->InsertValue(cntr++, cell->GetPointId(3));
840           da->InsertValue(cntr++, cell->GetPointId(2));
841           da->InsertValue(cntr++, cell->GetPointId(4));
842           da->InsertValue(cntr++, cell->GetPointId(5));
843           da->InsertValue(cntr++, cell->GetPointId(7));
844           da->InsertValue(cntr++, cell->GetPointId(6));
845           }
846         else if ( cellType == VTK_PIXEL )
847           {
848           // Hack for VTK_PIXEL
849           da->InsertValue(cntr++, cell->GetPointId(0));
850           da->InsertValue(cntr++, cell->GetPointId(1));
851           da->InsertValue(cntr++, cell->GetPointId(3));
852           da->InsertValue(cntr++, cell->GetPointId(2));
853           }
854         for (vtkIdType pid=0; pid < numPts; pid++)
855           {
856           da->InsertValue(cntr++, cell->GetPointId(pid));
857           }
858         }
859       this->ConvertVToXArray(da, di, 1, &cntr, 2, heavyName);
860       da->Delete();
861       }
862     }
863     break;
864   default:
865     t->SetTopologyType(XDMF_NOTOPOLOGY);
866     vtkWarningMacro(<< "Unrecognized dataset type");
867   }
868 
869   return 1;
870 }
871 
872 //----------------------------------------------------------------------------
CreateGeometry(vtkDataSet * ds,xdmf2::XdmfGrid * grid,void * staticdata)873 int vtkXdmfWriter::CreateGeometry(vtkDataSet *ds, xdmf2::XdmfGrid *grid, void *staticdata)
874 {
875   //Geometry
876   XdmfGeometry *geo = grid->GetGeometry();
877   geo->SetLightDataLimit(this->LightDataLimit);
878 
879   const char *heavyName = NULL;
880   std::string heavyDataSetName;
881   if (this->HeavyDataFileName)
882     {
883     heavyDataSetName = std::string(this->HeavyDataFileName) + ":";
884     if (this->HeavyDataGroupName)
885       {
886       heavyDataSetName = heavyDataSetName + HeavyDataGroupName + "/Geometry";
887       }
888     heavyName = heavyDataSetName.c_str();
889     }
890 
891   vtkXW2NodeHelp *staticnode = (vtkXW2NodeHelp*)staticdata;
892   if (staticnode) {
893     if (staticnode->staticFlag) {
894       grid->Set("GeometryConstant", "True");
895     }
896     if (staticnode->DOM && staticnode->node) {
897       XdmfXmlNode staticGeom = staticnode->DOM->FindElement("Geometry", 0, staticnode->node);
898       XdmfConstString text = staticnode->DOM->Serialize(staticGeom->children);
899       geo->SetDataXml(text);
900       return 1;
901     }
902   }
903 
904   switch (ds->GetDataObjectType()) {
905   case VTK_STRUCTURED_POINTS:
906   case VTK_IMAGE_DATA:
907   case VTK_UNIFORM_GRID:
908     {
909     geo->SetGeometryType(XDMF_GEOMETRY_ORIGIN_DXDYDZ);
910     vtkImageData *id = vtkImageData::SafeDownCast(ds);
911     double orig[3], spacing[3];
912     id->GetOrigin(orig);
913     double tmp = orig[2];
914     orig[2] = orig[0];
915     orig[0] = tmp;
916     id->GetSpacing(spacing);
917     tmp = spacing[2];
918     spacing[2] = spacing[0];
919     spacing[0] = tmp;
920     geo->SetOrigin(orig);
921     geo->SetDxDyDz(spacing);
922     }
923     break;
924   case VTK_RECTILINEAR_GRID:
925     {
926     vtkIdType len;
927     geo->SetGeometryType(XDMF_GEOMETRY_VXVYVZ);
928     vtkRectilinearGrid *rgrid = vtkRectilinearGrid::SafeDownCast(ds);
929     vtkDataArray *da;
930     da = rgrid->GetXCoordinates();
931     len = da->GetNumberOfTuples();
932     XdmfArray *xdax = new XdmfArray;
933     this->ConvertVToXArray(da, xdax, 1, &len, 0, heavyName);
934     geo->SetVectorX(xdax, 1);
935     da = rgrid->GetYCoordinates();
936     len = da->GetNumberOfTuples();
937     XdmfArray *xday = new XdmfArray;
938     this->ConvertVToXArray(da, xday, 1, &len, 0, heavyName);
939     geo->SetVectorY(xday, 1);
940     da = rgrid->GetZCoordinates();
941     len = da->GetNumberOfTuples();
942     XdmfArray *xdaz = new XdmfArray;
943     this->ConvertVToXArray(da, xdaz, 1, &len, 0, heavyName);
944     geo->SetVectorZ(xdaz, 1);
945     }
946     break;
947   case VTK_STRUCTURED_GRID:
948   case VTK_POLY_DATA:
949   case VTK_UNSTRUCTURED_GRID:
950     {
951     geo->SetGeometryType(XDMF_GEOMETRY_XYZ);
952     vtkPointSet *pset = vtkPointSet::SafeDownCast(ds);
953     vtkPoints *pts = pset->GetPoints();
954     if (!pts)
955       {
956       return 0;
957       }
958     vtkDataArray *da = pts->GetData();
959     XdmfArray *xda = geo->GetPoints();
960     vtkIdType shape[2];
961     shape[0] = da->GetNumberOfTuples();
962     this->ConvertVToXArray(da, xda, 1, shape, 0, heavyName);
963     geo->SetPoints(xda);
964     }
965     break;
966   default:
967     geo->SetGeometryType(XDMF_GEOMETRY_NONE);
968     //TODO: Support non-canonical vtkDataSets (via a callout for extensibility)
969     vtkWarningMacro(<< "Unrecognized dataset type");
970   }
971 
972   return 1;
973 }
974 //------------------------------------------------------------------------------
WriteAtomicDataSet(vtkDataObject * dobj,xdmf2::XdmfGrid * grid)975 int vtkXdmfWriter::WriteAtomicDataSet(vtkDataObject *dobj, xdmf2::XdmfGrid *grid)
976 {
977   //cerr << "Writing " << dobj << " a " << dobj->GetClassName() << endl;
978   vtkDataSet *ds = vtkDataSet::SafeDownCast(dobj);
979   if (!ds)
980     {
981     //TODO: Fill in non Vis data types
982     vtkWarningMacro(<< "Can not convert " << dobj->GetClassName() << " to XDMF yet.");
983     return 0;
984     }
985 
986   //Attributes
987   vtkIdType FRank = 1;
988   vtkIdType FDims[1];
989   vtkIdType CRank = 3;
990   vtkIdType CDims[3];
991   vtkIdType PRank = 3;
992   vtkIdType PDims[3];
993 
994   this->CreateTopology(ds, grid, PDims, CDims, PRank, CRank, NULL);
995   if (!this->CreateGeometry(ds, grid, NULL))
996     {
997     return 0;
998     }
999 
1000   FDims[0] = ds->GetFieldData()->GetNumberOfTuples();
1001   this->WriteArrays(ds->GetFieldData(),grid,XDMF_ATTRIBUTE_CENTER_GRID, FRank, FDims, "Field");
1002   this->WriteArrays(ds->GetCellData(), grid,XDMF_ATTRIBUTE_CENTER_CELL, CRank, CDims, "Cell");
1003   this->WriteArrays(ds->GetPointData(),grid,XDMF_ATTRIBUTE_CENTER_NODE, PRank, PDims, "Node");
1004 
1005   return 1;
1006 }
1007 
1008 //----------------------------------------------------------------------------
WriteArrays(vtkFieldData * fd,xdmf2::XdmfGrid * grid,int association,vtkIdType rank,vtkIdType * dims,const char * name)1009 int vtkXdmfWriter::WriteArrays(vtkFieldData* fd, xdmf2::XdmfGrid *grid, int association,
1010                                vtkIdType rank, vtkIdType *dims, const char *name)
1011 {
1012   if (!fd)
1013     {
1014     return 0;
1015     }
1016   vtkDataSetAttributes *dsa = vtkDataSetAttributes::SafeDownCast(fd);
1017 
1018   const char *heavyName = NULL;
1019   std::string heavyDataSetName;
1020   if (this->HeavyDataFileName)
1021     {
1022     heavyDataSetName = std::string(this->HeavyDataFileName) + ":";
1023     if (this->HeavyDataGroupName)
1024       {
1025       heavyDataSetName = heavyDataSetName + std::string(HeavyDataGroupName) + "/" + name;
1026       }
1027     heavyName = heavyDataSetName.c_str();
1028     }
1029 
1030   //
1031   // Sort alphabetically to avoid potential bad ordering problems
1032   //
1033   int nbOfArrays = fd->GetNumberOfArrays();
1034   std::vector<std::pair<int, std::string> > attributeNames;
1035   attributeNames.reserve(nbOfArrays);
1036   for (int i = 0; i < nbOfArrays; i++)
1037     {
1038     vtkDataArray *scalars = fd->GetArray(i);
1039     attributeNames.push_back(std::pair<int, std::string>(i, scalars->GetName()));
1040     }
1041   std::sort(attributeNames.begin(), attributeNames.end());
1042 
1043   for (int i = 0; i < nbOfArrays; i++)
1044     {
1045     vtkDataArray *da = fd->GetArray(attributeNames[i].second.c_str());
1046     if (!da)
1047       {
1048       //TODO: Dump non numeric arrays too
1049       vtkWarningMacro(<< "xdmfwriter can not convert non-numeric arrays yet.");
1050       continue;
1051       }
1052 
1053     XdmfAttribute *attr = new XdmfAttribute;
1054     attr->SetLightDataLimit(this->LightDataLimit);
1055     attr->SetDeleteOnGridDelete(true);
1056     if (da->GetName())
1057       {
1058       attr->SetName(da->GetName());
1059       }
1060     else
1061       {
1062       attr->SetName("ANONYMOUS");
1063       }
1064     attr->SetAttributeCenter(association);
1065 
1066     int attributeType = 0;
1067     if (dsa)
1068       {
1069       attributeType = dsa->IsArrayAnAttribute(attributeNames[i].first);
1070       switch (attributeType)
1071         {
1072         case vtkDataSetAttributes::SCALARS:
1073           attributeType = XDMF_ATTRIBUTE_TYPE_SCALAR; //TODO: Is XDMF ok with 3 component(RGB) active scalars?
1074           break;
1075         case vtkDataSetAttributes::VECTORS:
1076           attributeType = XDMF_ATTRIBUTE_TYPE_VECTOR;
1077           break;
1078         case vtkDataSetAttributes::GLOBALIDS:
1079           attributeType = XDMF_ATTRIBUTE_TYPE_GLOBALID;
1080           break;
1081         case vtkDataSetAttributes::TENSORS: //TODO: vtk tensors are 9 component, xdmf tensors are 6?
1082         case vtkDataSetAttributes::NORMALS: //TODO: mark as vectors?
1083         case vtkDataSetAttributes::TCOORDS: //TODO: mark as vectors?
1084         case vtkDataSetAttributes::PEDIGREEIDS: //TODO: ? type is variable
1085         default:
1086           break;
1087         }
1088       }
1089 
1090     if (attributeType != 0)
1091       {
1092       attr->SetActive(1);
1093       attr->SetAttributeType(attributeType);
1094       }
1095     else
1096       {
1097       //vtk doesn't mark it as a special array, use width to tell xdmf what to call it
1098       if (da->GetNumberOfComponents() == 1)
1099         {
1100         attr->SetAttributeType(XDMF_ATTRIBUTE_TYPE_SCALAR);
1101         }
1102       else if (da->GetNumberOfComponents() == 3)
1103         {
1104         attr->SetAttributeType(XDMF_ATTRIBUTE_TYPE_VECTOR);
1105         }
1106       else if (da->GetNumberOfComponents() == 6)
1107         {
1108         // TODO: convert VTK 9 components symetric tensors to 6 components
1109         attr->SetAttributeType(XDMF_ATTRIBUTE_TYPE_TENSOR);
1110         }
1111       }
1112 
1113     XdmfArray *xda = attr->GetValues();
1114     this->ConvertVToXArray(da, xda, rank, dims, 0, heavyName);
1115     attr->SetValues(xda);
1116     grid->Insert(attr);
1117     }
1118 
1119   return 1;
1120 }
1121 
1122 //------------------------------------------------------------------------------
ConvertVToXArray(vtkDataArray * vda,XdmfArray * xda,vtkIdType rank,vtkIdType * dims,int allocStrategy,const char * heavyprefix)1123 void vtkXdmfWriter::ConvertVToXArray(vtkDataArray *vda,
1124                                       XdmfArray *xda, vtkIdType rank,
1125                                       vtkIdType *dims, int allocStrategy,
1126                                       const char *heavyprefix)
1127 {
1128   XdmfInt32 lRank = rank;
1129   XdmfInt64 *lDims = new XdmfInt64[rank+1];
1130   for (vtkIdType i = 0; i < rank; i++)
1131     {
1132     lDims[i] = dims[i];
1133     }
1134   vtkIdType nc = vda->GetNumberOfComponents();
1135   //add additional dimension to the xdmf array to match the vtk arrays width,
1136   //ex coordinate arrays have xyz, so add [3]
1137   if (nc != 1)
1138     {
1139     lDims[rank]=nc;
1140     lRank+=1;
1141     }
1142 
1143   switch (vda->GetDataType())
1144     {
1145     case VTK_DOUBLE:
1146       xda->SetNumberType(XDMF_FLOAT64_TYPE);
1147       break;
1148     case VTK_FLOAT:
1149       xda->SetNumberType(XDMF_FLOAT32_TYPE);
1150       break;
1151     case VTK_ID_TYPE:
1152       xda->SetNumberType((VTK_SIZEOF_ID_TYPE==sizeof(XDMF_64_INT)?XDMF_INT64_TYPE:XDMF_INT32_TYPE));
1153       break;
1154     case VTK_LONG:
1155       xda->SetNumberType(XDMF_INT64_TYPE);
1156       break;
1157     case VTK_INT:
1158       xda->SetNumberType(XDMF_INT32_TYPE);
1159       break;
1160     case VTK_UNSIGNED_INT:
1161       xda->SetNumberType(XDMF_UINT32_TYPE);
1162       break;
1163     case VTK_SHORT:
1164       xda->SetNumberType(XDMF_INT16_TYPE);
1165       break;
1166     case VTK_UNSIGNED_SHORT:
1167       xda->SetNumberType(XDMF_INT16_TYPE);
1168       break;
1169     case VTK_CHAR:
1170     case VTK_SIGNED_CHAR:
1171       xda->SetNumberType(XDMF_INT8_TYPE); //TODO: Do we ever want unicode?
1172       break;
1173     case VTK_UNSIGNED_CHAR:
1174       xda->SetNumberType(XDMF_UINT8_TYPE);
1175       break;
1176     case VTK_LONG_LONG:
1177     case VTK_UNSIGNED_LONG_LONG:
1178     case VTK___INT64:
1179     case VTK_UNSIGNED___INT64:
1180     case VTK_UNSIGNED_LONG:
1181     case VTK_STRING:
1182       {
1183       xda->SetNumberType(XDMF_UNKNOWN_TYPE);
1184       break;
1185       }
1186     }
1187 
1188   if (heavyprefix) {
1189     std::string dsname = std::string(heavyprefix) + "/" + std::string(vda->GetName());
1190     xda->SetHeavyDataSetName(dsname.c_str());
1191   }
1192 
1193   //TODO: if we can make xdmf write out immediately, then wouldn't have to keep around
1194   //arrays when working with temporal data
1195   if ((allocStrategy==0 && !this->TopTemporalGrid) || allocStrategy==1)
1196     {
1197     //Do not let xdmf allocate its own buffer. xdmf just borrows vtk's and doesn't double mem size.
1198     xda->SetAllowAllocate(0);
1199     xda->SetShape(lRank, lDims);
1200     xda->SetDataPointer(vda->GetVoidPointer(0));
1201     }
1202   else //(allocStrategy==0 && this->TopTemporalGrid) || allocStrategy==2)
1203     {
1204     //Unfortunately data doesn't stick around with temporal updates, which is exactly when you want it most.
1205     xda->SetAllowAllocate(1);
1206     xda->SetShape(lRank, lDims);
1207     memcpy(xda->GetDataPointer(), vda->GetVoidPointer(0),
1208            vda->GetNumberOfTuples()*
1209            vda->GetNumberOfComponents()*
1210            vda->GetElementComponentSize());
1211     }
1212 
1213   delete[] lDims;
1214 }
1215