1 /*=========================================================================
2
3 Program: Visualization Toolkit
4 Module: vtkXMLPDataReader.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 #include "vtkXMLPDataReader.h"
16
17 #include "vtkCallbackCommand.h"
18 #include "vtkCellData.h"
19 #include "vtkDataArray.h"
20 #include "vtkDataArraySelection.h"
21 #include "vtkDataSet.h"
22 #include "vtkPointData.h"
23 #include "vtkXMLDataElement.h"
24 #include "vtkXMLDataReader.h"
25 #include "vtkInformationVector.h"
26 #include "vtkInformation.h"
27 #include "vtkStreamingDemandDrivenPipeline.h"
28
29 #include <vtksys/ios/sstream>
30
31
32 //----------------------------------------------------------------------------
vtkXMLPDataReader()33 vtkXMLPDataReader::vtkXMLPDataReader()
34 {
35 this->GhostLevel = 0;
36
37 this->NumberOfPieces = 0;
38
39 this->PieceElements = 0;
40 this->PieceReaders = 0;
41 this->CanReadPieceFlag = 0;
42
43 this->PathName = 0;
44
45 // Setup a callback for the internal serial readers to report
46 // progress.
47 this->PieceProgressObserver = vtkCallbackCommand::New();
48 this->PieceProgressObserver->SetCallback(&vtkXMLPDataReader::PieceProgressCallbackFunction);
49 this->PieceProgressObserver->SetClientData(this);
50 }
51
52 //----------------------------------------------------------------------------
~vtkXMLPDataReader()53 vtkXMLPDataReader::~vtkXMLPDataReader()
54 {
55 if(this->NumberOfPieces)
56 {
57 this->DestroyPieces();
58 }
59 if(this->PathName)
60 {
61 delete [] this->PathName;
62 }
63 this->PieceProgressObserver->Delete();
64 }
65
66 //----------------------------------------------------------------------------
PrintSelf(ostream & os,vtkIndent indent)67 void vtkXMLPDataReader::PrintSelf(ostream& os, vtkIndent indent)
68 {
69 this->Superclass::PrintSelf(os, indent);
70 os << indent << "NumberOfPieces: " << this->NumberOfPieces << "\n";
71 }
72
73 //----------------------------------------------------------------------------
GetPieceInputAsDataSet(int piece)74 vtkDataSet* vtkXMLPDataReader::GetPieceInputAsDataSet(int piece)
75 {
76 vtkXMLDataReader* reader = this->PieceReaders[piece];
77 if(!reader)
78 {
79 return 0;
80 }
81 if(reader->GetNumberOfOutputPorts() < 1)
82 {
83 return 0;
84 }
85 return static_cast<vtkDataSet*>(reader->GetOutputDataObject(0));
86 }
87
88
89 //----------------------------------------------------------------------------
SetupOutputData()90 void vtkXMLPDataReader::SetupOutputData()
91 {
92 this->Superclass::SetupOutputData();
93
94 // Setup the output arrays.
95 vtkXMLDataElement* ePointData = this->PPointDataElement;
96 vtkXMLDataElement* eCellData = this->PCellDataElement;
97 vtkDataSet* output = vtkDataSet::SafeDownCast(this->GetCurrentOutput());
98 vtkPointData* pointData = output->GetPointData();
99 vtkCellData* cellData = output->GetCellData();
100
101 // Get the size of the output arrays.
102 unsigned long pointTuples = this->GetNumberOfPoints();
103 unsigned long cellTuples = this->GetNumberOfCells();
104
105 // Allocate data in the arrays.
106 int i;
107 if(ePointData)
108 {
109 for(i=0;i < ePointData->GetNumberOfNestedElements();++i)
110 {
111 vtkXMLDataElement* eNested = ePointData->GetNestedElement(i);
112 if(this->PointDataArrayIsEnabled(eNested))
113 {
114 vtkAbstractArray* array = this->CreateArray(eNested);
115 if(array)
116 {
117 array->SetNumberOfTuples(pointTuples);
118 pointData->AddArray(array);
119 array->Delete();
120 }
121 else
122 {
123 this->DataError = 1;
124 }
125 }
126 }
127 }
128
129 if(eCellData)
130 {
131 for(i = 0; i < eCellData->GetNumberOfNestedElements(); i++)
132 {
133 vtkXMLDataElement* eNested = eCellData->GetNestedElement(i);
134 if(this->CellDataArrayIsEnabled(eNested))
135 {
136 vtkAbstractArray* array = this->CreateArray(eNested);
137 if(array)
138 {
139 array->SetNumberOfTuples(cellTuples);
140 cellData->AddArray(array);
141 array->Delete();
142 }
143 else
144 {
145 this->DataError = 1;
146 }
147 }
148 }
149 }
150
151 // Setup attribute indices for the point data and cell data.
152 this->ReadAttributeIndices(ePointData, pointData);
153 this->ReadAttributeIndices(eCellData, cellData);
154
155 }
156
157 //----------------------------------------------------------------------------
ReadXMLInformation()158 int vtkXMLPDataReader::ReadXMLInformation()
159 {
160 // First setup the filename components.
161 this->SplitFileName();
162
163 // Now proceed with reading the information.
164 return this->Superclass::ReadXMLInformation();
165 }
166
167
168 //----------------------------------------------------------------------------
169 // Note that any changes (add or removing information) made to this method
170 // should be replicated in CopyOutputInformation
SetupOutputInformation(vtkInformation * outInfo)171 void vtkXMLPDataReader::SetupOutputInformation(vtkInformation *outInfo)
172 {
173 if (this->InformationError)
174 {
175 vtkErrorMacro("Should not still be processing output information if have set InformationError");
176 return;
177 }
178
179 // Initialize DataArraySelections to anable all that are present
180 this->SetDataArraySelections(this->PPointDataElement, this->PointDataArraySelection);
181 this->SetDataArraySelections(this->PCellDataElement, this->CellDataArraySelection);
182
183 // Setup the Field Information for PointData. We only need the
184 // information from one piece because all pieces have the same set of arrays.
185 vtkInformationVector *infoVector = NULL;
186 if (!this->SetFieldDataInfo(this->PPointDataElement,
187 vtkDataObject::FIELD_ASSOCIATION_POINTS, this->GetNumberOfPoints(), infoVector))
188 {
189 return;
190 }
191 if (infoVector)
192 {
193 outInfo->Set(vtkDataObject::POINT_DATA_VECTOR(), infoVector);
194 infoVector->Delete();
195 }
196
197 // now the Cell data
198 infoVector = NULL;
199 if (!this->SetFieldDataInfo(this->PCellDataElement,
200 vtkDataObject::FIELD_ASSOCIATION_CELLS, this->GetNumberOfCells(), infoVector))
201 {
202 return;
203 }
204 if (infoVector)
205 {
206 outInfo->Set(vtkDataObject::CELL_DATA_VECTOR(), infoVector);
207 infoVector->Delete();
208 }
209
210 }
211
212
213 //----------------------------------------------------------------------------
CopyOutputInformation(vtkInformation * outInfo,int port)214 void vtkXMLPDataReader::CopyOutputInformation(vtkInformation *outInfo,
215 int port)
216 {
217 vtkInformation *localInfo =
218 this->GetExecutive()->GetOutputInformation( port );
219 if ( localInfo->Has(vtkDataObject::POINT_DATA_VECTOR()) )
220 {
221 outInfo->CopyEntry( localInfo, vtkDataObject::POINT_DATA_VECTOR() );
222 }
223 if ( localInfo->Has(vtkDataObject::CELL_DATA_VECTOR()) )
224 {
225 outInfo->CopyEntry( localInfo, vtkDataObject::CELL_DATA_VECTOR() );
226 }
227 }
228
229
230 //----------------------------------------------------------------------------
ReadPrimaryElement(vtkXMLDataElement * ePrimary)231 int vtkXMLPDataReader::ReadPrimaryElement(vtkXMLDataElement* ePrimary)
232 {
233 if(!this->Superclass::ReadPrimaryElement(ePrimary))
234 {
235 return 0;
236 }
237 // Read information about the data.
238 if(!ePrimary->GetScalarAttribute("GhostLevel", this->GhostLevel))
239 {
240 this->GhostLevel = 0;
241 }
242
243 // Read information about the pieces.
244 this->PPointDataElement = 0;
245 this->PCellDataElement = 0;
246 int i;
247 int numNested = ePrimary->GetNumberOfNestedElements();
248 int numPieces = 0;
249 for(i=0;i < numNested; ++i)
250 {
251 vtkXMLDataElement* eNested = ePrimary->GetNestedElement(i);
252 if(strcmp(eNested->GetName(), "Piece") == 0)
253 {
254 ++numPieces;
255 }
256 else if(strcmp(eNested->GetName(), "PPointData") == 0)
257 {
258 this->PPointDataElement = eNested;
259 }
260 else if(strcmp(eNested->GetName(), "PCellData") == 0)
261 {
262 this->PCellDataElement = eNested;
263 }
264 }
265 this->SetupPieces(numPieces);
266 int piece = 0;
267 for(i=0;i < numNested; ++i)
268 {
269 vtkXMLDataElement* eNested = ePrimary->GetNestedElement(i);
270 if(strcmp(eNested->GetName(), "Piece") == 0)
271 {
272 if(!this->ReadPiece(eNested, piece++))
273 {
274 return 0;
275 }
276 }
277 }
278
279 return 1;
280 }
281
282 //----------------------------------------------------------------------------
SetupPieces(int numPieces)283 void vtkXMLPDataReader::SetupPieces(int numPieces)
284 {
285 if(this->NumberOfPieces)
286 {
287 this->DestroyPieces();
288 }
289 this->NumberOfPieces = numPieces;
290 this->PieceElements = new vtkXMLDataElement*[this->NumberOfPieces];
291 this->PieceReaders = new vtkXMLDataReader*[this->NumberOfPieces];
292 this->CanReadPieceFlag = new int[this->NumberOfPieces];
293 int i;
294 for(i=0;i < this->NumberOfPieces;++i)
295 {
296 this->PieceElements[i] = 0;
297 this->PieceReaders[i] = 0;
298 this->CanReadPieceFlag[i] = 0;
299 }
300 }
301
302 //----------------------------------------------------------------------------
DestroyPieces()303 void vtkXMLPDataReader::DestroyPieces()
304 {
305 int i;
306 for(i=0;i < this->NumberOfPieces;++i)
307 {
308 if(this->PieceReaders[i])
309 {
310 this->PieceReaders[i]->RemoveObserver(this->PieceProgressObserver);
311 this->PieceReaders[i]->Delete();
312 }
313 }
314 delete [] this->PieceElements;
315 delete [] this->CanReadPieceFlag;
316 delete [] this->PieceReaders;
317 this->PieceElements = 0;
318 this->PieceReaders = 0;
319 this->NumberOfPieces = 0;
320 }
321
322 //----------------------------------------------------------------------------
ReadPiece(vtkXMLDataElement * ePiece,int index)323 int vtkXMLPDataReader::ReadPiece(vtkXMLDataElement* ePiece, int index)
324 {
325 this->Piece = index;
326 return this->ReadPiece(ePiece);
327 }
328
329 //----------------------------------------------------------------------------
ReadPiece(vtkXMLDataElement * ePiece)330 int vtkXMLPDataReader::ReadPiece(vtkXMLDataElement* ePiece)
331 {
332 this->PieceElements[this->Piece] = ePiece;
333
334 const char* fileName = ePiece->GetAttribute("Source");
335 if(!fileName)
336 {
337 vtkErrorMacro("Piece " << this->Piece << " has no Source attribute.");
338 return 0;
339 }
340
341 // The file name is relative to the summary file. Convert it to
342 // something we can use.
343 char *pieceFileName = this->CreatePieceFileName(fileName);
344
345 vtkXMLDataReader* reader = this->CreatePieceReader();
346 this->PieceReaders[this->Piece] = reader;
347 this->PieceReaders[this->Piece]->AddObserver(vtkCommand::ProgressEvent,
348 this->PieceProgressObserver);
349 reader->SetFileName(pieceFileName);
350
351 delete [] pieceFileName;
352
353 return 1;
354 }
355
356 //----------------------------------------------------------------------------
ReadPieceData(int index)357 int vtkXMLPDataReader::ReadPieceData(int index)
358 {
359 this->Piece = index;
360
361 // We need data, make sure the piece can be read.
362 if(!this->CanReadPiece(this->Piece))
363 {
364 vtkErrorMacro("File for piece " << this->Piece << " cannot be read.");
365 return 0;
366 }
367
368 // Actually read the data.
369 this->PieceReaders[this->Piece]->SetAbortExecute(0);
370 vtkDataArraySelection* pds =
371 this->PieceReaders[this->Piece]->GetPointDataArraySelection();
372 vtkDataArraySelection* cds =
373 this->PieceReaders[this->Piece]->GetCellDataArraySelection();
374 pds->CopySelections(this->PointDataArraySelection);
375 cds->CopySelections(this->CellDataArraySelection);
376 return this->ReadPieceData();
377 }
378
379 //----------------------------------------------------------------------------
ReadPieceData()380 int vtkXMLPDataReader::ReadPieceData()
381 {
382 vtkDataSet* input = this->GetPieceInputAsDataSet(this->Piece);
383 vtkDataSet* output = vtkDataSet::SafeDownCast(this->GetCurrentOutput());
384
385 // copy any field data
386 if (input->GetFieldData())
387 {
388 int i;
389 for (i = 0; i < input->GetFieldData()->GetNumberOfArrays(); i++)
390 {
391 output->GetFieldData()->AddArray( input->GetFieldData()->GetArray(i) );
392 }
393 }
394
395 // Copy point data and cell data for this piece.
396 int i;
397 for(i=0;i < output->GetPointData()->GetNumberOfArrays();++i)
398 {
399 this->CopyArrayForPoints(input->GetPointData()->GetArray(i),
400 output->GetPointData()->GetArray(i));
401 }
402 for(i=0;i < output->GetCellData()->GetNumberOfArrays();++i)
403 {
404 this->CopyArrayForCells(input->GetCellData()->GetArray(i),
405 output->GetCellData()->GetArray(i));
406 }
407
408 return 1;
409 }
410
411 //----------------------------------------------------------------------------
CanReadPiece(int index)412 int vtkXMLPDataReader::CanReadPiece(int index)
413 {
414 // If necessary, test whether the piece can be read.
415 vtkXMLDataReader* reader = this->PieceReaders[index];
416 if(reader && !this->CanReadPieceFlag[index])
417 {
418 if(reader->CanReadFile(reader->GetFileName()))
419 {
420 // We can read the piece. Save result to avoid later repeat of
421 // test.
422 this->CanReadPieceFlag[index] = 1;
423 }
424 else
425 {
426 // We cannot read the piece. Destroy the reader to avoid later
427 // repeat of test.
428 this->PieceReaders[index] = 0;
429 reader->Delete();
430 }
431 }
432
433 return (this->PieceReaders[index]? 1:0);
434 }
435
436 //----------------------------------------------------------------------------
CreatePieceFileName(const char * fileName)437 char* vtkXMLPDataReader::CreatePieceFileName(const char* fileName)
438 {
439 vtksys_ios::ostringstream fn_with_warning_C4701;
440
441 // only prepend the path if the given file name is not
442 // absolute (i.e. doesn't start with '/')
443 if(this->PathName && fileName && fileName[0] != '/')
444 {
445 fn_with_warning_C4701 << this->PathName;
446 }
447 fn_with_warning_C4701 << fileName;
448
449 size_t len = fn_with_warning_C4701.str().length();
450 char *buffer = new char[len + 1];
451 strncpy(buffer, fn_with_warning_C4701.str().c_str(), len);
452 buffer[len] = '\0';
453
454 return buffer;
455 }
456
457 //----------------------------------------------------------------------------
SplitFileName()458 void vtkXMLPDataReader::SplitFileName()
459 {
460 if(!this->FileName)
461 {
462 vtkErrorMacro( << "Need to specify a filename" );
463 return;
464 }
465
466 // Pull the PathName component out of the FileName.
467 size_t length = strlen(this->FileName);
468 char* fileName = new char[length+1];
469 strcpy(fileName, this->FileName);
470 char* begin = fileName;
471 char* end = fileName + length;
472 char* s;
473
474 #if defined(_WIN32)
475 // Convert to UNIX-style slashes.
476 for(s=begin;s != end;++s) { if(*s == '\\') { *s = '/'; } }
477 #endif
478
479 // Extract the path name up to the last '/'.
480 if(this->PathName)
481 {
482 delete [] this->PathName;
483 this->PathName = 0;
484 }
485 char* rbegin = end-1;
486 char* rend = begin-1;
487 for(s=rbegin;s != rend;--s)
488 {
489 if(*s == '/')
490 {
491 break;
492 }
493 }
494 if(s >= begin)
495 {
496 length = (s-begin)+1;
497 this->PathName = new char[length+1];
498 strncpy(this->PathName, this->FileName, length);
499 this->PathName[length] = '\0';
500 }
501
502 // Cleanup temporary name.
503 delete [] fileName;
504 }
505
506 //----------------------------------------------------------------------------
PieceProgressCallbackFunction(vtkObject *,unsigned long,void * clientdata,void *)507 void vtkXMLPDataReader::PieceProgressCallbackFunction(vtkObject*, unsigned long,
508 void* clientdata, void*)
509 {
510 reinterpret_cast<vtkXMLPDataReader*>(clientdata)->PieceProgressCallback();
511 }
512
513 //----------------------------------------------------------------------------
PieceProgressCallback()514 void vtkXMLPDataReader::PieceProgressCallback()
515 {
516 float width = this->ProgressRange[1]-this->ProgressRange[0];
517 float pieceProgress = this->PieceReaders[this->Piece]->GetProgress();
518 float progress = this->ProgressRange[0] + pieceProgress*width;
519 this->UpdateProgressDiscrete(progress);
520 if(this->AbortExecute)
521 {
522 this->PieceReaders[this->Piece]->SetAbortExecute(1);
523 }
524 }
525