1 /*=========================================================================
2
3 Program: Visualization Toolkit
4 Module: vtkXMLPTableReader.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 "vtkXMLPTableReader.h"
16
17 #include "vtkCallbackCommand.h"
18 #include "vtkCellArray.h"
19 #include "vtkDataArraySelection.h"
20 #include "vtkDataSetAttributes.h"
21 #include "vtkIdTypeArray.h"
22 #include "vtkInformation.h"
23 #include "vtkInformationVector.h"
24 #include "vtkObjectFactory.h"
25 #include "vtkStreamingDemandDrivenPipeline.h"
26 #include "vtkTable.h"
27 #include "vtkXMLDataElement.h"
28 #include "vtkXMLTableReader.h"
29
30 #include <cassert>
31 #include <sstream>
32
33 vtkStandardNewMacro(vtkXMLPTableReader);
34
35 //----------------------------------------------------------------------------
vtkXMLPTableReader()36 vtkXMLPTableReader::vtkXMLPTableReader()
37 {
38 this->PieceReaders = nullptr;
39
40 this->TotalNumberOfRows = 0;
41
42 this->ColumnSelection = vtkDataArraySelection::New();
43 this->ColumnSelection->AddObserver(vtkCommand::ModifiedEvent, this->SelectionObserver);
44 }
45
46 //----------------------------------------------------------------------------
~vtkXMLPTableReader()47 vtkXMLPTableReader::~vtkXMLPTableReader()
48 {
49 if (this->NumberOfPieces)
50 {
51 this->DestroyPieces();
52 }
53
54 this->ColumnSelection->RemoveObserver(this->SelectionObserver);
55 this->ColumnSelection->Delete();
56 }
57
58 //----------------------------------------------------------------------------
CopyOutputInformation(vtkInformation * outInfo,int port)59 void vtkXMLPTableReader::CopyOutputInformation(vtkInformation* outInfo, int port)
60 {
61 vtkInformation* localInfo = this->GetExecutive()->GetOutputInformation(port);
62
63 if (localInfo->Has(CAN_HANDLE_PIECE_REQUEST()))
64 {
65 outInfo->CopyEntry(localInfo, CAN_HANDLE_PIECE_REQUEST());
66 }
67 }
68
69 //----------------------------------------------------------------------------
PrintSelf(ostream & os,vtkIndent indent)70 void vtkXMLPTableReader::PrintSelf(ostream& os, vtkIndent indent)
71 {
72 this->Superclass::PrintSelf(os, indent);
73
74 os << indent << "Column Selection: " << this->ColumnSelection << "\n";
75 os << indent << "Total Number Of Rows: " << this->TotalNumberOfRows << "\n";
76 }
77
78 //----------------------------------------------------------------------------
GetOutput()79 vtkTable* vtkXMLPTableReader::GetOutput()
80 {
81 return this->GetOutput(0);
82 }
83
84 //----------------------------------------------------------------------------
GetOutput(int idx)85 vtkTable* vtkXMLPTableReader::GetOutput(int idx)
86 {
87 return vtkTable::SafeDownCast(this->GetOutputDataObject(idx));
88 }
89
90 //----------------------------------------------------------------------------
GetDataSetName()91 const char* vtkXMLPTableReader::GetDataSetName()
92 {
93 return "PTable";
94 }
95
96 //----------------------------------------------------------------------------
GetOutputUpdateExtent(int & piece,int & numberOfPieces)97 void vtkXMLPTableReader::GetOutputUpdateExtent(int& piece, int& numberOfPieces)
98 {
99 vtkInformation* outInfo = this->GetCurrentOutputInformation();
100 piece = outInfo->Get(vtkStreamingDemandDrivenPipeline::UPDATE_PIECE_NUMBER());
101 numberOfPieces = outInfo->Get(vtkStreamingDemandDrivenPipeline::UPDATE_NUMBER_OF_PIECES());
102 }
103
104 //----------------------------------------------------------------------------
SetupOutputTotals()105 void vtkXMLPTableReader::SetupOutputTotals()
106 {
107 this->TotalNumberOfRows = 0;
108 for (int i = this->StartPiece; i < this->EndPiece; ++i)
109 {
110 if (this->PieceReaders[i])
111 {
112 this->TotalNumberOfRows += this->PieceReaders[i]->GetNumberOfRows();
113 }
114 }
115 this->StartRow = 0;
116 }
117
118 //----------------------------------------------------------------------------
SetupOutputData()119 void vtkXMLPTableReader::SetupOutputData()
120 {
121 this->Superclass::SetupOutputData();
122
123 // Setup the output arrays.
124 vtkTable* output = vtkTable::SafeDownCast(this->GetCurrentOutput());
125 vtkDataSetAttributes* rowData = output->GetRowData();
126
127 // Get the size of the output arrays.
128 unsigned long rowTuples = this->GetNumberOfRows();
129
130 // Allocate data in the arrays.
131 if (this->PRowElement)
132 {
133 for (int i = 0; i < this->PRowElement->GetNumberOfNestedElements(); ++i)
134 {
135 vtkXMLDataElement* eNested = this->PRowElement->GetNestedElement(i);
136 if (this->ColumnIsEnabled(eNested))
137 {
138 vtkAbstractArray* array = this->CreateArray(eNested);
139 if (array)
140 {
141 array->SetNumberOfTuples(rowTuples);
142 rowData->AddArray(array);
143 array->Delete();
144 }
145 else
146 {
147 this->DataError = 1;
148 }
149 }
150 }
151 }
152
153 // Setup attribute indices for the point data and cell data.
154 this->ReadAttributeIndices(this->PRowElement, rowData);
155 }
156
157 //----------------------------------------------------------------------------
ReadPieceData(int index)158 int vtkXMLPTableReader::ReadPieceData(int index)
159 {
160 this->Piece = index;
161
162 // We need data, make sure the piece can be read.
163 if (!this->CanReadPiece(this->Piece))
164 {
165 vtkErrorMacro("File for piece " << this->Piece << " cannot be read.");
166 return 0;
167 }
168
169 // Actually read the data.
170 this->PieceReaders[this->Piece]->SetAbortExecute(0);
171
172 return this->ReadPieceData();
173 }
174
175 //----------------------------------------------------------------------------
CanReadPiece(int index)176 int vtkXMLPTableReader::CanReadPiece(int index)
177 {
178 // If necessary, test whether the piece can be read.
179 vtkXMLTableReader* reader = this->PieceReaders[index];
180 if (reader && !this->CanReadPieceFlag[index])
181 {
182 if (reader->CanReadFile(reader->GetFileName()))
183 {
184 // We can read the piece. Save result to avoid later repeat of
185 // test.
186 this->CanReadPieceFlag[index] = 1;
187 }
188 else
189 {
190 // We cannot read the piece. Destroy the reader to avoid later
191 // repeat of test.
192 this->PieceReaders[index] = nullptr;
193 reader->Delete();
194 }
195 }
196
197 return (this->PieceReaders[index] ? 1 : 0);
198 }
199
200 //----------------------------------------------------------------------------
PieceProgressCallback()201 void vtkXMLPTableReader::PieceProgressCallback()
202 {
203 float width = this->ProgressRange[1] - this->ProgressRange[0];
204 float pieceProgress = this->PieceReaders[this->Piece]->GetProgress();
205 float progress = this->ProgressRange[0] + pieceProgress * width;
206 this->UpdateProgressDiscrete(progress);
207 if (this->AbortExecute)
208 {
209 this->PieceReaders[this->Piece]->SetAbortExecute(1);
210 }
211 }
212
213 //----------------------------------------------------------------------------
SetupNextPiece()214 void vtkXMLPTableReader::SetupNextPiece()
215 {
216 if (this->PieceReaders[this->Piece])
217 {
218 this->StartRow += this->PieceReaders[this->Piece]->GetNumberOfRows();
219 }
220 }
221
222 //----------------------------------------------------------------------------
ReadPieceData()223 int vtkXMLPTableReader::ReadPieceData()
224 {
225 // Use the internal reader to read the piece.
226 this->PieceReaders[this->Piece]->UpdatePiece(0, 1, 0);
227
228 vtkTable* input = this->GetPieceInputAsTable(this->Piece);
229
230 if (!input)
231 {
232 vtkErrorMacro("No input piece found for the current piece index.");
233 return 0;
234 }
235
236 vtkTable* output = vtkTable::SafeDownCast(this->GetCurrentOutput());
237
238 // If there are some rows, but no PRows element, report the
239 // error.
240 if (!this->PRowElement && (this->GetNumberOfRows() > 0))
241 {
242 vtkErrorMacro("Could not find PRows element with 1 array.");
243 return 0;
244 }
245
246 if (!input->GetRowData())
247 {
248 return 0;
249 }
250
251 // copy any row data
252 if (input->GetRowData())
253 {
254 for (int i = 0; i < input->GetRowData()->GetNumberOfArrays(); i++)
255 {
256 if (this->ColumnSelection->ArrayIsEnabled(input->GetRowData()->GetArrayName(i)))
257 {
258 output->GetRowData()->AddArray(input->GetRowData()->GetArray(i));
259 }
260 }
261 }
262
263 // copy any field data
264 if (input->GetFieldData())
265 {
266 for (int i = 0; i < input->GetFieldData()->GetNumberOfArrays(); i++)
267 {
268 output->GetFieldData()->AddArray(input->GetFieldData()->GetArray(i));
269 }
270 }
271
272 return 1;
273 }
274
275 //----------------------------------------------------------------------------
CreatePieceReader()276 vtkXMLTableReader* vtkXMLPTableReader::CreatePieceReader()
277 {
278 return vtkXMLTableReader::New();
279 }
280
281 //----------------------------------------------------------------------------
FillOutputPortInformation(int,vtkInformation * info)282 int vtkXMLPTableReader::FillOutputPortInformation(int, vtkInformation* info)
283 {
284 info->Set(vtkDataObject::DATA_TYPE_NAME(), "vtkTable");
285 return 1;
286 }
287
288 //----------------------------------------------------------------------------
RequestInformation(vtkInformation * request,vtkInformationVector ** inputVector,vtkInformationVector * outputVector)289 int vtkXMLPTableReader::RequestInformation(
290 vtkInformation* request, vtkInformationVector** inputVector, vtkInformationVector* outputVector)
291 {
292 vtkInformation* outInfo = outputVector->GetInformationObject(0);
293 outInfo->Set(CAN_HANDLE_PIECE_REQUEST(), 1);
294 return this->Superclass::RequestInformation(request, inputVector, outputVector);
295 }
296
297 //----------------------------------------------------------------------------
GetOutputAsTable()298 vtkTable* vtkXMLPTableReader::GetOutputAsTable()
299 {
300 return vtkTable::SafeDownCast(this->GetOutputDataObject(0));
301 }
302
303 //----------------------------------------------------------------------------
GetPieceInputAsTable(int piece)304 vtkTable* vtkXMLPTableReader::GetPieceInputAsTable(int piece)
305 {
306 vtkXMLTableReader* reader = this->PieceReaders[piece];
307 if (!reader || reader->GetNumberOfOutputPorts() < 1)
308 {
309 return nullptr;
310 }
311 return static_cast<vtkTable*>(reader->GetExecutive()->GetOutputData(0));
312 }
313
314 //----------------------------------------------------------------------------
GetNumberOfRows()315 vtkIdType vtkXMLPTableReader::GetNumberOfRows()
316 {
317 return this->TotalNumberOfRows;
318 }
319
320 //----------------------------------------------------------------------------
SetupEmptyOutput()321 void vtkXMLPTableReader::SetupEmptyOutput()
322 {
323 this->GetCurrentOutput()->Initialize();
324 }
325
326 //----------------------------------------------------------------------------
SetupOutputInformation(vtkInformation * outInfo)327 void vtkXMLPTableReader::SetupOutputInformation(vtkInformation* outInfo)
328 {
329 if (this->InformationError)
330 {
331 vtkErrorMacro("Should not still be processing output information if have set InformationError");
332 return;
333 };
334
335 // Initialize DataArraySelections to enable all that are present
336 this->SetDataArraySelections(this->PRowElement, this->ColumnSelection);
337
338 // Setup the Field Information for RowData. We only need the
339 // information from one piece because all pieces have the same set of arrays.
340 vtkInformationVector* infoVector = nullptr;
341 if (!this->SetFieldDataInfo(this->PRowElement, vtkDataObject::FIELD_ASSOCIATION_ROWS,
342 this->GetNumberOfRows(), infoVector))
343 {
344 return;
345 }
346 if (infoVector)
347 {
348 infoVector->Delete();
349 }
350
351 outInfo->Set(CAN_HANDLE_PIECE_REQUEST(), 1);
352 }
353
354 //----------------------------------------------------------------------------
ReadXMLData()355 void vtkXMLPTableReader::ReadXMLData()
356 {
357 // Get the update request.
358 vtkInformation* outInfo = this->GetCurrentOutputInformation();
359 int piece = outInfo->Get(vtkStreamingDemandDrivenPipeline::UPDATE_PIECE_NUMBER());
360 int numberOfPieces = outInfo->Get(vtkStreamingDemandDrivenPipeline::UPDATE_NUMBER_OF_PIECES());
361
362 vtkDebugMacro("Updating piece " << piece << " of " << numberOfPieces);
363
364 // Setup the range of pieces that will be read.
365 this->SetupUpdateExtent(piece, numberOfPieces);
366
367 // If there are no data to read, stop now.
368 if (this->StartPiece == this->EndPiece)
369 {
370 return;
371 }
372
373 vtkDebugMacro(
374 "Reading piece range [" << this->StartPiece << ", " << this->EndPiece << ") from file.");
375
376 // Let superclasses read data. This also allocates output data.
377 this->Superclass::ReadXMLData();
378
379 // Split current progress range based on fraction contributed by
380 // each piece.
381 float progressRange[2] = { 0.f, 0.f };
382 this->GetProgressRange(progressRange);
383
384 // Calculate the cumulative fraction of data contributed by each
385 // piece (for progress).
386 std::vector<float> fractions(this->EndPiece - this->StartPiece + 1);
387 fractions[0] = 0;
388 for (int i = this->StartPiece; i < this->EndPiece; ++i)
389 {
390 int index = i - this->StartPiece;
391 fractions[index + 1] = (fractions[index] + this->GetNumberOfRowsInPiece(i));
392 }
393 if (fractions[this->EndPiece - this->StartPiece] == 0)
394 {
395 fractions[this->EndPiece - this->StartPiece] = 1;
396 }
397 for (int i = this->StartPiece; i < this->EndPiece; ++i)
398 {
399 int index = i - this->StartPiece;
400 fractions[index + 1] = fractions[index + 1] / fractions[this->EndPiece - this->StartPiece];
401 }
402
403 // Read the data needed from each piece.
404 for (int i = this->StartPiece; (i < this->EndPiece && !this->AbortExecute && !this->DataError);
405 ++i)
406 {
407 // Set the range of progress for this piece.
408 this->SetProgressRange(progressRange, i - this->StartPiece, fractions.data());
409
410 if (!this->ReadPieceData(i))
411 {
412 // An error occurred while reading the piece.
413 this->DataError = 1;
414 }
415 this->SetupNextPiece();
416 }
417 }
418
419 //----------------------------------------------------------------------------
ReadPrimaryElement(vtkXMLDataElement * ePrimary)420 int vtkXMLPTableReader::ReadPrimaryElement(vtkXMLDataElement* ePrimary)
421 {
422
423 if (!this->Superclass::ReadPrimaryElement(ePrimary))
424 {
425 return 0;
426 }
427
428 // Read information about the pieces.
429 this->PRowElement = nullptr;
430 int numNested = ePrimary->GetNumberOfNestedElements();
431 int numPieces = 0;
432 for (int i = 0; i < numNested; ++i)
433 {
434 vtkXMLDataElement* eNested = ePrimary->GetNestedElement(i);
435 if (strcmp(eNested->GetName(), "Piece") == 0)
436 {
437 ++numPieces;
438 }
439 else if (strcmp(eNested->GetName(), "PRowData") == 0)
440 {
441 this->PRowElement = eNested;
442 }
443 }
444 this->SetupPieces(numPieces);
445 int piece = 0;
446 for (int i = 0; i < numNested; ++i)
447 {
448 vtkXMLDataElement* eNested = ePrimary->GetNestedElement(i);
449 if (strcmp(eNested->GetName(), "Piece") == 0)
450 {
451 if (!this->ReadPiece(eNested, piece++))
452 {
453 return 0;
454 }
455 }
456 }
457
458 return 1;
459 }
460
461 //----------------------------------------------------------------------------
SetupUpdateExtent(int piece,int numberOfPieces)462 void vtkXMLPTableReader::SetupUpdateExtent(int piece, int numberOfPieces)
463 {
464 this->UpdatePiece = piece;
465 this->UpdateNumberOfPieces = numberOfPieces;
466
467 // If more pieces are requested than available, just return empty
468 // pieces for the extra ones
469 if (this->UpdateNumberOfPieces > this->NumberOfPieces)
470 {
471 this->UpdateNumberOfPieces = this->NumberOfPieces;
472 }
473
474 // Find the range of pieces to read.
475 if (this->UpdatePiece < this->UpdateNumberOfPieces)
476 {
477 this->StartPiece = (this->UpdatePiece * this->NumberOfPieces) / this->UpdateNumberOfPieces;
478 this->EndPiece = ((this->UpdatePiece + 1) * this->NumberOfPieces) / this->UpdateNumberOfPieces;
479 }
480 else
481 {
482 this->StartPiece = 0;
483 this->EndPiece = 0;
484 }
485
486 // Update the information of the pieces we need.
487 for (int i = this->StartPiece; i < this->EndPiece; ++i)
488 {
489 if (this->CanReadPiece(i))
490 {
491 this->PieceReaders[i]->UpdateInformation();
492 vtkXMLTableReader* pReader = this->PieceReaders[i];
493 pReader->SetupUpdateExtent(0, 1);
494 }
495 }
496
497 // Find the total size of the output.
498 this->SetupOutputTotals();
499 }
500
501 //----------------------------------------------------------------------------
GetNumberOfRowsInPiece(int piece)502 vtkIdType vtkXMLPTableReader::GetNumberOfRowsInPiece(int piece)
503 {
504 return this->PieceReaders[piece] ? this->PieceReaders[piece]->GetNumberOfRows() : 0;
505 }
506
507 //----------------------------------------------------------------------------
SetupPieces(int numPieces)508 void vtkXMLPTableReader::SetupPieces(int numPieces)
509 {
510 this->Superclass::SetupPieces(numPieces);
511
512 this->PieceReaders = new vtkXMLTableReader*[this->NumberOfPieces];
513
514 for (int i = 0; i < this->NumberOfPieces; ++i)
515 {
516 this->PieceReaders[i] = nullptr;
517 }
518 }
519
520 //----------------------------------------------------------------------------
DestroyPieces()521 void vtkXMLPTableReader::DestroyPieces()
522 {
523 for (int i = 0; i < this->NumberOfPieces; ++i)
524 {
525 if (this->PieceReaders[i])
526 {
527 this->PieceReaders[i]->RemoveObserver(this->PieceProgressObserver);
528 this->PieceReaders[i]->Delete();
529 }
530 }
531
532 delete[] this->PieceReaders;
533 this->PieceReaders = nullptr;
534
535 this->Superclass::DestroyPieces();
536 }
537
538 //----------------------------------------------------------------------------
ReadPiece(vtkXMLDataElement * ePiece)539 int vtkXMLPTableReader::ReadPiece(vtkXMLDataElement* ePiece)
540 {
541 this->PieceElements[this->Piece] = ePiece;
542
543 const char* fileName = ePiece->GetAttribute("Source");
544 if (!fileName)
545 {
546 vtkErrorMacro("Piece " << this->Piece << " has no Source attribute.");
547 return 0;
548 }
549
550 // The file name is relative to the summary file. Convert it to
551 // something we can use.
552 char* pieceFileName = this->CreatePieceFileName(fileName);
553
554 vtkXMLTableReader* reader = this->CreatePieceReader();
555 this->PieceReaders[this->Piece] = reader;
556 this->PieceReaders[this->Piece]->AddObserver(
557 vtkCommand::ProgressEvent, this->PieceProgressObserver);
558 reader->SetFileName(pieceFileName);
559
560 delete[] pieceFileName;
561
562 return 1;
563 }
564
565 //----------------------------------------------------------------------------
ColumnIsEnabled(vtkXMLDataElement * elementRowData)566 int vtkXMLPTableReader::ColumnIsEnabled(vtkXMLDataElement* elementRowData)
567 {
568 const char* name = elementRowData->GetAttribute("Name");
569 return (name && this->ColumnSelection->ArrayIsEnabled(name));
570 }
571
572 //----------------------------------------------------------------------------
GetNumberOfColumnArrays()573 int vtkXMLPTableReader::GetNumberOfColumnArrays()
574 {
575 return this->ColumnSelection->GetNumberOfArrays();
576 }
577
578 //----------------------------------------------------------------------------
GetColumnArrayName(int index)579 const char* vtkXMLPTableReader::GetColumnArrayName(int index)
580 {
581 return this->ColumnSelection->GetArrayName(index);
582 }
583
584 //----------------------------------------------------------------------------
GetColumnArrayStatus(const char * name)585 int vtkXMLPTableReader::GetColumnArrayStatus(const char* name)
586 {
587 return this->ColumnSelection->ArrayIsEnabled(name);
588 }
589
590 //----------------------------------------------------------------------------
SetColumnArrayStatus(const char * name,int status)591 void vtkXMLPTableReader::SetColumnArrayStatus(const char* name, int status)
592 {
593 if (status)
594 {
595 this->ColumnSelection->EnableArray(name);
596 }
597 else
598 {
599 this->ColumnSelection->DisableArray(name);
600 }
601 }
602