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