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