1 /*=========================================================================
2 
3   Program:   Visualization Toolkit
4   Module:    vtkPExodusIIReader.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 /*----------------------------------------------------------------------------
17  Copyright (c) Sandia Corporation
18  See Copyright.txt or http://www.paraview.org/HTML/Copyright.html for details.
19 ----------------------------------------------------------------------------*/
20 
21 #include "vtkPExodusIIReader.h"
22 
23 #include "vtkAppendCompositeDataLeaves.h"
24 #include "vtkCellData.h"
25 #include "vtkCommand.h"
26 #include "vtkDoubleArray.h"
27 #include "vtkExodusIIReaderPrivate.h"
28 #include "vtkFloatArray.h"
29 #include "vtkInformation.h"
30 #include "vtkInformationVector.h"
31 #include "vtkIntArray.h"
32 #include "vtkPointData.h"
33 #include "vtkMultiBlockDataSet.h"
34 #include "vtkMultiProcessController.h"
35 #include "vtkObjectFactory.h"
36 #include "vtkSmartPointer.h"
37 #include "vtkStreamingDemandDrivenPipeline.h"
38 #include "vtkUnstructuredGrid.h"
39 
40 #include "vtk_netcdf.h"
41 #include "vtk_exodusII.h"
42 
43 #include "vtksys/SystemTools.hxx"
44 
45 #include <vector>
46 
47 #include <vtksys/RegularExpression.hxx>
48 
49 #include <cctype>
50 
51 #undef DBG_PEXOIIRDR
52 #define vtkPExodusIIReaderMAXPATHLEN 2048
53 
54 static const int objTypes[] = {
55   vtkExodusIIReader::EDGE_BLOCK,
56   vtkExodusIIReader::FACE_BLOCK,
57   vtkExodusIIReader::ELEM_BLOCK,
58   vtkExodusIIReader::NODE_SET,
59   vtkExodusIIReader::EDGE_SET,
60   vtkExodusIIReader::FACE_SET,
61   vtkExodusIIReader::SIDE_SET,
62   vtkExodusIIReader::ELEM_SET,
63   vtkExodusIIReader::NODE_MAP,
64   vtkExodusIIReader::EDGE_MAP,
65   vtkExodusIIReader::FACE_MAP,
66   vtkExodusIIReader::ELEM_MAP
67 };
68 static const int numObjTypes = sizeof(objTypes)/sizeof(objTypes[0]);
69 
70 static const int objResultTypes[] = {
71   vtkExodusIIReader::NODAL,
72   vtkExodusIIReader::EDGE_BLOCK,
73   vtkExodusIIReader::FACE_BLOCK,
74   vtkExodusIIReader::ELEM_BLOCK,
75   vtkExodusIIReader::NODE_SET,
76   vtkExodusIIReader::EDGE_SET,
77   vtkExodusIIReader::FACE_SET,
78   vtkExodusIIReader::SIDE_SET,
79   vtkExodusIIReader::ELEM_SET,
80   vtkExodusIIReader::GLOBAL
81 };
82 static const int numObjResultTypes = sizeof(objResultTypes)/sizeof(objResultTypes[0]);
83 
84 static const int objAttribTypes[] = {
85   vtkExodusIIReader::EDGE_BLOCK,
86   vtkExodusIIReader::FACE_BLOCK,
87   vtkExodusIIReader::ELEM_BLOCK
88 };
89 static const int numObjAttribTypes = sizeof(objAttribTypes)/sizeof(objAttribTypes[0]);
90 
91 
92 vtkStandardNewMacro(vtkPExodusIIReader);
93 
94 class vtkPExodusIIReaderUpdateProgress : public vtkCommand
95 {
96 public:
vtkTypeMacro(vtkPExodusIIReaderUpdateProgress,vtkCommand)97   vtkTypeMacro(vtkPExodusIIReaderUpdateProgress, vtkCommand)
98   static vtkPExodusIIReaderUpdateProgress* New()
99   {
100     return new vtkPExodusIIReaderUpdateProgress;
101   }
SetReader(vtkPExodusIIReader * r)102   void SetReader(vtkPExodusIIReader* r)
103   {
104     Reader = r;
105   }
SetIndex(int i)106   void SetIndex(int i)
107   {
108     Index = i;
109   }
110 protected:
111 
vtkPExodusIIReaderUpdateProgress()112   vtkPExodusIIReaderUpdateProgress()
113   {
114     Reader = nullptr;
115     Index = 0;
116   }
~vtkPExodusIIReaderUpdateProgress()117   ~vtkPExodusIIReaderUpdateProgress() override{}
118 
Execute(vtkObject *,unsigned long event,void * callData)119   void Execute(vtkObject*, unsigned long event, void* callData) override
120   {
121     if(event == vtkCommand::ProgressEvent)
122     {
123       double num = Reader->GetNumberOfFileNames();
124       if (num <= 1)
125       {
126         num = Reader->GetNumberOfFiles();
127       }
128       double* progress = static_cast<double*>(callData);
129       double newProgress = *progress/num + Index/num;
130       Reader->UpdateProgress(newProgress);
131     }
132   }
133 
134   vtkPExodusIIReader* Reader;
135   int Index;
136 };
137 
138 
139 //----------------------------------------------------------------------------
140 // Description:
141 // Instantiate object with nullptr filename.
vtkPExodusIIReader()142 vtkPExodusIIReader::vtkPExodusIIReader()
143 {
144   this->ProcRank = 0;
145   this->ProcSize = 1;
146   // NB. SetController will initialize ProcSize and ProcRank
147   this->Controller = 0;
148   this->SetController( vtkMultiProcessController::GetGlobalController() );
149   this->FilePattern = 0;
150   this->CurrentFilePattern = 0;
151   this->FilePrefix = 0;
152   this->CurrentFilePrefix = 0;
153   this->FileRange[0] = -1;
154   this->FileRange[1] = -1;
155   this->CurrentFileRange[0] = 0;
156   this->CurrentFileRange[1] = 0;
157   this->NumberOfFiles = 1;
158   this->FileNames = nullptr;
159   this->NumberOfFileNames = 0;
160   this->MultiFileName = new char[vtkPExodusIIReaderMAXPATHLEN];
161   this->XMLFileName=nullptr;
162   this->LastCommonTimeStep = -1;
163   this->VariableCacheSize = 100;
164 }
165 
166 //----------------------------------------------------------------------------
~vtkPExodusIIReader()167 vtkPExodusIIReader::~vtkPExodusIIReader()
168 {
169   this->SetController( 0 );
170   this->SetFilePattern( 0 );
171   this->SetFilePrefix( 0 );
172 
173   // If we've allocated filenames then delete them
174   if ( this->FileNames )
175   {
176     for (int i=0; i<this->NumberOfFileNames; i++)
177     {
178       delete [] this->FileNames[i];
179     }
180     delete [] this->FileNames;
181   }
182 
183   // Delete all the readers we may have
184   std::vector<vtkExodusIIReader*>::iterator it;
185   for ( it = this->ReaderList.begin(); it != this->ReaderList.end(); ++ it )
186   {
187     (*it)->Delete();
188   }
189 
190   if ( this->CurrentFilePrefix )
191   {
192     delete [] this->CurrentFilePrefix;
193     delete [] this->CurrentFilePattern;
194   }
195 
196   delete [] this->MultiFileName;
197 }
198 
199 //----------------------------------------------------------------------------
SetController(vtkMultiProcessController * c)200 void vtkPExodusIIReader::SetController( vtkMultiProcessController* c )
201 {
202   if ( this->Controller == c )
203   {
204     return;
205   }
206 
207   this->Modified();
208 
209   if ( this->Controller )
210   {
211     this->Controller->UnRegister( this );
212   }
213 
214   this->Controller = c;
215 
216   if ( this->Controller )
217   {
218     this->Controller->Register( this );
219     this->ProcRank = this->Controller->GetLocalProcessId();
220     this->ProcSize = this->Controller->GetNumberOfProcesses();
221   }
222 
223   if ( ! this->Controller || this->ProcSize <= 0 )
224   {
225     this->ProcRank = 0;
226     this->ProcSize = 1;
227   }
228 }
229 
230 //----------------------------------------------------------------------------
RequestInformation(vtkInformation * request,vtkInformationVector ** inputVector,vtkInformationVector * outputVector)231 int vtkPExodusIIReader::RequestInformation(
232   vtkInformation* request,
233   vtkInformationVector** inputVector,
234   vtkInformationVector* outputVector )
235 {
236   vtkInformation* outInfo = outputVector->GetInformationObject( 0 );
237   outInfo->Set(
238     CAN_HANDLE_PIECE_REQUEST(), 1);
239 
240   int requestInformationRetVal = 0;
241   if ( this->ProcRank == 0 )
242   {
243     bool newName = this->GetMetadataMTime() < this->FileNameMTime;
244     bool newPattern =
245       (
246         ( this->FilePattern &&
247           ( ! this->CurrentFilePattern ||
248             ! vtksys::SystemTools::ComparePath(
249               this->FilePattern, this->CurrentFilePattern ) ||
250             ( ( this->FileRange[0] != this->CurrentFileRange[0] ) ||
251               ( this->FileRange[1] != this->CurrentFileRange[1] ) ) ) ) ||
252         ( this->FilePrefix &&
253           ! vtksys::SystemTools::ComparePath(
254             this->FilePrefix, this->CurrentFilePrefix ) )
255         );
256 
257     // setting filename for the first time builds the prefix/pattern
258     // if one clears the prefix/pattern, but the filename stays the same,
259     // we should rebuild the prefix/pattern
260     bool rebuildPattern =
261       newPattern && this->FilePattern[0] == '\0' && this->FilePrefix[0] == '\0';
262 
263     bool sanity = ( ( this->FilePattern && this->FilePrefix ) || this->FileName );
264 
265     if ( ! sanity )
266     {
267       vtkErrorMacro( << "Must SetFilePattern AND SetFilePrefix, or SetFileName(s)" );
268       this->Broadcast( this->Controller );
269       return 0;
270     }
271 
272     if ( newPattern && ! rebuildPattern )
273     {
274       size_t nmSize = strlen( this->FilePattern ) + strlen( this->FilePrefix ) + 20;
275       char* nm = new char[nmSize];
276       snprintf( nm, nmSize, this->FilePattern, this->FilePrefix, this->FileRange[0] );
277       delete [] this->FileName;
278       this->FileName = nm;
279     }
280     else if ( newName || rebuildPattern )
281     {
282       if ( this->NumberOfFileNames == 1 )
283       {
284         // A singleton file may actually be a hint to look for
285         // a series of files with the same base name.  Must compute
286         // this now for ParaView.
287 
288         this->DeterminePattern( this->FileNames[0] );
289       }
290     }
291 
292     int numFiles = this->NumberOfFileNames;
293     if ( numFiles <= 1 )
294     {
295       numFiles = this->NumberOfFiles;
296     }
297 
298     // Go through the filenames and see if any of them actually have data
299     // in them. It's possible that some of them don't and if they don't
300     // we won't have the proper information generated.
301     int reader_idx=0;
302     for ( int fileIndex = 0; fileIndex < numFiles; ++fileIndex, ++reader_idx )
303     {
304       if ( this->NumberOfFileNames > 1 )
305       {
306         strcpy( this->MultiFileName, this->FileNames[fileIndex] );
307         if ( this->GetGenerateFileIdArray() )
308         {
309           vtkPExodusIIReader::DetermineFileId( this->FileNames[fileIndex] );
310         }
311       }
312       else if ( this->FilePattern )
313       {
314         snprintf( this->MultiFileName, vtkPExodusIIReaderMAXPATHLEN, this->FilePattern, this->FilePrefix, fileIndex );
315       }
316       char* nm = new char[strlen( this->MultiFileName )+1];
317       strcpy(nm, this->MultiFileName);
318       delete [] this->FileName;
319       this->FileName = nm;
320       nm = nullptr;
321 
322       // Read in info based on this->FileName
323       requestInformationRetVal = this->Superclass::RequestInformation( request, inputVector, outputVector );
324 
325       if ( this->Metadata->ArrayInfo.size() )
326       {
327         // We have a file with actual data in it
328         break;
329       }
330     } // loop over file names
331   }
332   this->Controller->Broadcast( &requestInformationRetVal, 1, 0);
333   if (!requestInformationRetVal)
334   {
335     return 0;
336   }
337 
338   if ( this->ProcSize > 1 )
339   {
340     this->Broadcast( this->Controller );
341     if ( this->ProcRank )
342     {
343       // The rank 0 node's RequestInformation annotates the output with the available
344       // time steps. Now that we've received time steps, advertise them on other procs.
345       this->AdvertiseTimeSteps( outInfo );
346     }
347   }
348 
349   // Check whether we have been given a certain timestep to stop at. If so,
350   // override the output time keys with the actual range that ALL readers can read.
351   // If files are still being written to, some files might be on different timesteps
352   // than others.
353   if ( (this->LastCommonTimeStep >= 0) && !this->GetHasModeShapes() )
354   {
355     double* times = outInfo->Get( vtkStreamingDemandDrivenPipeline::TIME_STEPS() );
356     int numTimes = outInfo->Length( vtkStreamingDemandDrivenPipeline::TIME_STEPS() );
357     numTimes = this->LastCommonTimeStep + 1 < numTimes ? this->LastCommonTimeStep + 1 : numTimes;
358     std::vector<double> commonTimes;
359     commonTimes.insert( commonTimes.begin(), times, times + numTimes );
360     double timeRange[2];
361     timeRange[1] = commonTimes[numTimes - 1];
362     timeRange[0] = commonTimes[0];
363 
364     outInfo->Set( vtkStreamingDemandDrivenPipeline::TIME_RANGE(), timeRange, 2 );
365     outInfo->Set( vtkStreamingDemandDrivenPipeline::TIME_STEPS(), &commonTimes[0], numTimes );
366   }
367 
368   if ( this->CurrentFilePrefix )
369   {
370     delete [] this->CurrentFilePrefix;
371     this->CurrentFilePrefix = nullptr;
372     delete [] this->CurrentFilePattern;
373     this->CurrentFilePattern = nullptr;
374     this->CurrentFileRange[0] = 0;
375     this->CurrentFileRange[1] = 0;
376   }
377 
378   if ( this->FilePrefix )
379   {
380     this->CurrentFilePrefix = vtksys::SystemTools::DuplicateString( this->FilePrefix );
381     this->CurrentFilePattern = vtksys::SystemTools::DuplicateString( this->FilePattern );
382     this->CurrentFileRange[0] = this->FileRange[0];
383     this->CurrentFileRange[1] = this->FileRange[1];
384   }
385 
386   return 1;
387 }
388 
389 
390 //----------------------------------------------------------------------------
RequestData(vtkInformation * vtkNotUsed (request),vtkInformationVector ** vtkNotUsed (inputVector),vtkInformationVector * outputVector)391 int vtkPExodusIIReader::RequestData(
392   vtkInformation* vtkNotUsed(request),
393   vtkInformationVector** vtkNotUsed(inputVector),
394   vtkInformationVector* outputVector )
395 {
396   int fileIndex;
397   int processNumber;
398   int numProcessors;
399   int min, max, idx;
400   int reader_idx;
401 
402   vtkInformation* outInfo = outputVector->GetInformationObject( 0 );
403   // get the output
404   vtkMultiBlockDataSet* output = vtkMultiBlockDataSet::SafeDownCast(
405     outInfo->Get( vtkDataObject::DATA_OBJECT() ) );
406 
407   // The whole notion of pieces for this reader is really
408   // just a division of files between processors
409   processNumber =
410     outInfo->Get( vtkStreamingDemandDrivenPipeline::UPDATE_PIECE_NUMBER() );
411   numProcessors =
412     outInfo->Get( vtkStreamingDemandDrivenPipeline::UPDATE_NUMBER_OF_PIECES() );
413 
414   int numFiles = this->NumberOfFileNames;
415   int start = 0;
416 
417   if ( numFiles <= 1 )
418   {
419     start = this->FileRange[0];   // use prefix/pattern/range
420     numFiles = this->NumberOfFiles;
421   }
422 
423 
424   // Someone has requested a file that is above the number
425   // of pieces I have. That may have been caused by having
426   // more processors than files. So I'm going to create an
427   // empty unstructured grid that contains all the meta
428   // information but has 0 cells
429   if ( processNumber >= numFiles )
430   {
431 #ifdef DBG_PEXOIIRDR
432     vtkWarningMacro("Creating empty grid for processor: " << processNumber);
433 #endif
434     this->Metadata->SetUpEmptyGrid( output );
435     return 1;
436   }
437 
438   // Divide the files evenly between processors
439   int num_files_per_process = numFiles / numProcessors;
440 
441   // This if/else logic is for when you don't have a nice even division of files
442   // Each process computes which sequence of files it needs to read in
443   int left_over_files = numFiles - (num_files_per_process*numProcessors);
444   if ( processNumber < left_over_files )
445   {
446     min = (num_files_per_process+1) * processNumber + start;
447     max = min + (num_files_per_process+1) - 1;
448   }
449   else
450   {
451     min = num_files_per_process * processNumber + left_over_files + start;
452     max = min + num_files_per_process - 1;
453   }
454 #ifdef DBG_PEXOIIRDR
455   vtkWarningMacro("Processor: " << processNumber << " reading files: " << min <<" " <<max);
456 #endif
457 
458 #ifdef DBG_PEXOIIRDR
459   vtkWarningMacro("Parallel read for processor: " << processNumber);
460 #endif
461 
462   // We are going to read in the files one by one and then
463   // append them together. So now we make sure that we have
464   // the correct number of serial exodus readers and we create
465   // our append object that puts the 'pieces' together
466   unsigned int numMyFiles = max - min + 1;
467 
468   vtkSmartPointer<vtkAppendCompositeDataLeaves> append =
469     vtkSmartPointer<vtkAppendCompositeDataLeaves>::New();
470   append->AppendFieldDataOn();
471 
472   /*
473   if ( this->ExodusModelMetadata )
474     {
475     this->NewExodusModel();
476     }
477   */
478 
479   if ( this->ReaderList.size() < numMyFiles )
480   {
481     for ( reader_idx = static_cast<int>( this->ReaderList.size() ); reader_idx < static_cast<int>(numMyFiles); ++reader_idx )
482     {
483       vtkExodusIIReader* er = vtkExodusIIReader::New();
484       vtkPExodusIIReaderUpdateProgress* progress = vtkPExodusIIReaderUpdateProgress::New();
485       progress->SetReader( this );
486       progress->SetIndex( reader_idx );
487       er->AddObserver( vtkCommand::ProgressEvent, progress );
488       progress->Delete();
489 
490       this->ReaderList.push_back( er );
491     }
492   }
493   else if ( this->ReaderList.size() > numMyFiles )
494   {
495     for ( reader_idx = static_cast<int>( this->ReaderList.size() ) - 1; reader_idx >= static_cast<int>(numMyFiles); --reader_idx )
496     {
497       this->ReaderList[reader_idx]->Delete();
498       ReaderList.pop_back();
499     }
500   }
501 
502   // If this is the first execution, we need to initialize the arrays
503   // that store the number of points/cells output by each reader
504   if(this->NumberOfCellsPerFile.size()==0)
505   {
506     this->NumberOfCellsPerFile.resize(max-min+1,0);
507   }
508   if(this->NumberOfPointsPerFile.size()==0)
509   {
510     this->NumberOfPointsPerFile.resize(max-min+1,0);
511   }
512 
513 #ifdef DBG_PEXOIIRDR
514   cout << "\n\n ************************************* Parallel master reader dump\n";
515   this->Dump();
516 #endif // DBG_PEXOIIRDR
517 
518   //setup the cache size for each reader
519   double fractionalCacheSize = 0;
520   if (this->VariableCacheSize > 0 )
521   {
522     fractionalCacheSize = this->VariableCacheSize / static_cast<int>( this->ReaderList.size() );
523   }
524 
525   // This constructs the filenames
526   for ( fileIndex = min, reader_idx=0; fileIndex <= max; ++fileIndex, ++reader_idx )
527   {
528     int fileId = -1;
529     if ( this->NumberOfFileNames > 1 )
530     {
531       strcpy( this->MultiFileName, this->FileNames[fileIndex] );
532       if ( this->GetGenerateFileIdArray() )
533       {
534         fileId = vtkPExodusIIReader::DetermineFileId( this->FileNames[fileIndex] );
535       }
536     }
537     else if ( this->FilePattern )
538     {
539       snprintf( this->MultiFileName, vtkPExodusIIReaderMAXPATHLEN, this->FilePattern, this->FilePrefix, fileIndex );
540       if ( this->GetGenerateFileIdArray() )
541       {
542         fileId = fileIndex;
543       }
544     }
545     else
546     {
547       vtkErrorMacro("Some weird problem with filename/filepattern");
548       return 0;
549     }
550 
551     if ( outInfo->Has( vtkStreamingDemandDrivenPipeline::UPDATE_TIME_STEP() ) )
552     { // Get the requested time step. We only support requests of a single time step in this reader right now
553       double requestedTimeStep = outInfo->Get( vtkStreamingDemandDrivenPipeline::UPDATE_TIME_STEP() );
554 
555       // Save the time value in the output data information.
556       int length = outInfo->Length( vtkStreamingDemandDrivenPipeline::TIME_STEPS() );
557       double* steps = outInfo->Get( vtkStreamingDemandDrivenPipeline::TIME_STEPS() );
558 
559       if ( ! this->GetHasModeShapes() )
560       {
561         int cnt = 0;
562         int closestStep = 0;
563         double minDist = -1;
564         for ( cnt = 0; cnt < length; ++ cnt )
565         {
566           double tdist =
567             ( steps[cnt] - requestedTimeStep > requestedTimeStep - steps[cnt] ) ?
568             steps[cnt] - requestedTimeStep : requestedTimeStep - steps[cnt];
569           if ( minDist < 0 || tdist < minDist )
570           {
571             minDist = tdist;
572             closestStep = cnt;
573           }
574         }
575         this->TimeStep = closestStep;
576         this->ReaderList[reader_idx]->SetTimeStep( this->TimeStep );
577         output->GetInformation()->Set( vtkDataObject::DATA_TIME_STEP(), steps[this->TimeStep] );
578       }
579       else
580       {
581         // Let the metadata know the time value so that the
582         // Metadata->RequestData call below will generate the animated mode
583         // shape properly.
584 
585         // Don't use this->SetModeShapeTime because that will cause Modified
586         // to be called.
587         //this->SetModeShapeTime( requestedTimeStep );
588         double phase = requestedTimeStep - floor(requestedTimeStep);
589         this->Metadata->ModeShapeTime = phase;
590 
591         this->ReaderList[reader_idx]->SetTimeStep( this->TimeStep );
592         this->ReaderList[reader_idx]->SetModeShapeTime( requestedTimeStep );
593         output->GetInformation()->Set( vtkDataObject::DATA_TIME_STEP(), requestedTimeStep );
594         //output->GetInformation()->Remove( vtkDataObject::DATA_TIME_STEP() );
595       }
596     }
597     else
598     {
599       this->ReaderList[reader_idx]->SetTimeStep( this->TimeStep );
600     }
601 
602     this->ReaderList[reader_idx]->SetGenerateObjectIdCellArray( this->GetGenerateObjectIdCellArray() );
603     this->ReaderList[reader_idx]->SetGenerateGlobalElementIdArray( this->GetGenerateGlobalElementIdArray() );
604     this->ReaderList[reader_idx]->SetGenerateGlobalNodeIdArray( this->GetGenerateGlobalNodeIdArray() );
605     this->ReaderList[reader_idx]->SetGenerateImplicitElementIdArray( this->GetGenerateImplicitElementIdArray() );
606     this->ReaderList[reader_idx]->SetGenerateImplicitNodeIdArray( this->GetGenerateImplicitNodeIdArray() );
607     this->ReaderList[reader_idx]->SetGenerateFileIdArray( this->GetGenerateFileIdArray() );
608     this->ReaderList[reader_idx]->SetFileId( fileId );
609     this->ReaderList[reader_idx]->SetApplyDisplacements( this->GetApplyDisplacements() );
610     this->ReaderList[reader_idx]->SetDisplacementMagnitude( this->GetDisplacementMagnitude() );
611     this->ReaderList[reader_idx]->SetHasModeShapes( this->GetHasModeShapes() );
612     this->ReaderList[reader_idx]->SetAnimateModeShapes( this->GetAnimateModeShapes() );
613 
614     //this->ReaderList[reader_idx]->SetExodusModelMetadata( this->ExodusModelMetadata );
615     // For now, this *must* come last before the UpdateInformation() call because its MTime is compared to the metadata's MTime,
616     // which is modified by the calls above.
617     this->ReaderList[reader_idx]->SetFileName( this->MultiFileName );
618     this->ReaderList[reader_idx]->SetXMLFileName( this->XMLFileName );
619     //this->ReaderList[reader_idx]->PackExodusModelOntoOutputOff();
620 
621     // BUG #15632: Pass time information from first file to all others.
622     if (reader_idx > 1)
623     {
624       this->ReaderList[reader_idx]->Metadata->SetTimesOverrides(
625         this->ReaderList[0]->Metadata->Times);
626     }
627 
628     this->ReaderList[reader_idx]->UpdateInformation();
629 #ifdef DBG_PEXOIIRDR
630     cout << "\n\n ************************************* Reader " << reader_idx << " dump\n";
631     this->ReaderList[reader_idx]->Dump();
632 #endif // DBG_PEXOIIRDR
633 
634     int typ;
635     for ( typ = 0; typ < numObjTypes; ++typ )
636     {
637       int nObj = this->ReaderList[reader_idx]->GetNumberOfObjects( objTypes[typ] );
638       for ( idx = 0; idx < nObj; ++idx )
639       {
640         this->ReaderList[reader_idx]->SetObjectStatus( objTypes[typ], idx, this->GetObjectStatus( objTypes[typ], idx ) );
641       }
642     }
643 
644     for ( typ = 0; typ < numObjAttribTypes; ++typ )
645     {
646       int nObj = this->ReaderList[reader_idx]->GetNumberOfObjects( objAttribTypes[typ] );
647       for ( idx = 0; idx < nObj; ++idx )
648       {
649         int nObjAtt = this->GetNumberOfObjectAttributes( objAttribTypes[typ], idx );
650         for ( int aidx = 0; aidx < nObjAtt; ++aidx )
651         {
652           this->ReaderList[reader_idx]->SetObjectAttributeStatus( objAttribTypes[typ], idx, aidx,
653             this->GetObjectAttributeStatus( objAttribTypes[typ], idx, aidx ) );
654         }
655       }
656     }
657 
658     for ( typ = 0; typ < numObjResultTypes; ++typ )
659     {
660       int nObjArr = this->GetNumberOfObjectArrays( objResultTypes[typ] );
661       for ( idx = 0; idx < nObjArr; ++idx )
662       {
663         this->ReaderList[reader_idx]->SetObjectArrayStatus(
664           objResultTypes[typ], idx, this->GetObjectArrayStatus( objResultTypes[typ], idx ) );
665       }
666     }
667 
668     //set this reader to use the full amount of the cache
669     this->ReaderList[reader_idx]->SetCacheSize(this->VariableCacheSize);
670 
671     //call the reader
672     this->ReaderList[reader_idx]->Update();
673 
674     //set the reader back to the fractional amount
675     this->ReaderList[reader_idx]->SetCacheSize(fractionalCacheSize);
676 
677 #if 0
678     vtkCompositeDataSet* subgrid = this->ReaderList[reader_idx]->GetOutput();
679     //subgrid->ShallowCopy( this->ReaderList[reader_idx]->GetOutput() );
680 
681     int ncells = subgrid->GetNumberOfCells();
682 
683     if ( ( ncells > 0 ) && this->Metadata->GetGenerateFileIdArray() )
684     {
685       vtkIntArray* ia = vtkIntArray::New();
686       ia->SetNumberOfValues(ncells);
687       for ( idx = 0; idx < ncells; ++ idx )
688       {
689         ia->SetValue( idx, fileId );
690       }
691       ia->SetName( "vtkFileId" );
692       subgrid->GetCellData()->AddArray( ia );
693       ia->Delete();
694     }
695 
696     // Don't append if you don't have any cells
697     if ( ncells != 0 )
698     {
699       if ( this->ExodusModelMetadata )
700       {
701         vtkExodusModel* em = this->ReaderList[reader_idx]->GetExodusModel();
702         if ( em )
703         {
704           this->ExodusModel->MergeExodusModel( em );
705         }
706       }
707 
708       totalCells += ncells;
709       totalPoints += subgrid->GetNumberOfPoints();
710       this->NumberOfCellsPerFile[reader_idx] = ncells;
711       this->NumberOfPointsPerFile[reader_idx] = subgrid->GetNumberOfPoints();
712 
713       append->AddInput( subgrid );
714       subgrid->Delete();
715     }
716 #else // 0
717     append->AddInputConnection( this->ReaderList[reader_idx]->GetOutputPort() );
718 #endif // 0
719   }
720 
721   // Append complains/barfs if you update it without any inputs
722   if (append->GetNumberOfInputConnections(0) != 0)
723   {
724     append->Update();
725     output->ShallowCopy( append->GetOutput() );
726   }
727 
728   // I've copied append's output to the 'output' so delete append
729   append = nullptr;
730 
731 #if 0 // FIXME: Need multiblock version... or not?
732   if ( this->PackExodusModelOntoOutput )
733   {
734     // The metadata is written to field arrays and attached
735     // to the output unstructured grid.
736     if ( this->ExodusModel )
737     {
738       vtkModelMetadata::RemoveMetadata( output );
739       this->ExodusModel->GetModelMetadata()->Pack( output );
740     }
741   }
742 #endif // 0
743 
744   return 1;
745 }
746 
747 //----------------------------------------------------------------------------
SetFileRange(int min,int max)748 void vtkPExodusIIReader::SetFileRange(int min, int max)
749 {
750   if ( min == this->FileRange[0] && max == this->FileRange[1] )
751   {
752     return;
753   }
754   this->FileRange[0] = min;
755   this->FileRange[1] = max;
756   this->NumberOfFiles = max-min+1;
757   this->Modified();
758 }
759 //----------------------------------------------------------------------------
SetFileName(const char * name)760 void vtkPExodusIIReader::SetFileName(const char *name)
761 {
762   this->SetFileNames( 1, &name );
763 }
764 
SetFileNames(int nfiles,const char ** names)765 void vtkPExodusIIReader::SetFileNames( int nfiles, const char** names )
766 {
767   // If I have an old list of filename delete them
768   if ( this->FileNames )
769   {
770     for ( int i = 0; i < this->NumberOfFileNames; ++ i )
771     {
772       delete [] this->FileNames[i];
773     }
774     delete [] this->FileNames;
775     this->FileNames = nullptr;
776   }
777 
778   // Set the number of files
779   this->NumberOfFileNames = nfiles;
780 
781   // Allocate memory for new filenames
782   this->FileNames = new char*[this->NumberOfFileNames];
783 
784   // Copy filenames
785   for (int i = 0; i < nfiles; ++ i )
786   {
787     this->FileNames[i] = vtksys::SystemTools::DuplicateString( names[i] );
788   }
789 
790   this->Superclass::SetFileName( names[0] );
791 }
792 
793 //----------------------------------------------------------------------------
DetermineFileId(const char * file)794 int vtkPExodusIIReader::DetermineFileId( const char* file )
795 {
796   // Assume the file number is the last digits found in the file name.
797   int fileId = 0;
798   const char* start = file;
799   const char* end = file + strlen(file) - 1;
800   const char* numString = end;
801 
802   if ( ! isdigit( *numString ) )
803   {
804     while ( numString > start )
805     {
806       --numString;
807       if ( isdigit( *numString ) ) break;
808     }
809 
810     if ( numString == start )
811     {
812       if ( isdigit( *numString ) )
813       {
814         fileId = atoi( numString );
815       }
816       return fileId;  // no numbers in file name
817     }
818   }
819 
820   while(numString > start)
821   {
822     --numString;
823     if ( ! isdigit( *numString ) ) break;
824   }
825 
826   if ( ( numString == start ) && ( isdigit( *numString ) ) )
827   {
828     fileId = atoi( numString );
829   }
830   else
831   {
832     fileId = atoi( ++ numString );
833   }
834 
835   return fileId;
836 }
837 
DeterminePattern(const char * file)838 int vtkPExodusIIReader::DeterminePattern( const char* file )
839 {
840   char pattern[20] = "%s";
841   int scount = 0;
842   int cc = 0;
843   int min = 0, max = 0;
844 
845   // First check for file names for which we should _not_ look for a numbered
846   // sequence.  If using the extension .ex2 or .ex2v2, then we should not.
847   // Furthermore, if the filename ends in .e-s#, then this number is indicative
848   // of a restart number, not a partition number, so we should not look for
849   // numbered sequences there either.
850   vtksys::RegularExpression ex2RegEx("\\.ex2$");
851   vtksys::RegularExpression ex2v2RegEx("\\.ex2v2$");
852   vtksys::RegularExpression restartRegEx("\\.e-s\\.?[0-9]+(\\.ex2v[0-9]+)?$");
853 
854   // This regular expression finds the number for a numbered sequence.  This
855   // number appears at the end of file (or potentially right before an extension
856   // like .ex2v3 or perhaps a future version of this extension).  The matches
857   // (in parentheses) are as follows:
858   // 1 - The prefix.
859   // 2 - The sequence number.
860   // 3 - The optional extension.
861   vtksys::RegularExpression
862     numberRegEx("^(.*[^0-9])([0-9]+)(\\.ex2v[0-9]+)?$");
863 
864   if (   ex2RegEx.find(file) || ex2v2RegEx.find(file)
865       || restartRegEx.find(file) || !numberRegEx.find(file) )
866   {
867     // Set my info
868     //this->SetFilePattern( pattern ); // XXX Bad set
869     //this->SetFilePrefix( file ); // XXX Bad set
870     //this->SetFileRange( min, max ); // XXX Bad set
871     delete [] this->FilePattern;
872     delete [] this->FilePrefix;
873     this->FilePattern = vtksys::SystemTools::DuplicateString( pattern );
874     this->FilePrefix = vtksys::SystemTools::DuplicateString( file );
875     this->FileRange[0] = min;
876     this->FileRange[1] = max;
877     this->NumberOfFiles = max - min + 1;
878     return VTK_OK;
879   }
880 
881   // If we are here, then numberRegEx matched and we have found the part of
882   // the filename that is the number.  Extract the filename parts.
883   std::string prefix = numberRegEx.match(1);
884   scount = static_cast<int>(numberRegEx.match(2).size());
885   std::string extension = numberRegEx.match(3);
886 
887   // Determine the pattern
888   snprintf(pattern, sizeof(pattern), "%%s%%0%ii%s", scount, extension.c_str());
889 
890   // Count up the files
891   char buffer[1024];
892   vtksys::SystemTools::Stat_t fs;
893 
894   // First go up every 100
895   for ( cc = min + 100; true; cc += 100 )
896   {
897     snprintf( buffer, sizeof(buffer), pattern, prefix.c_str(), cc );
898 
899     if (vtksys::SystemTools::Stat(buffer, &fs) == -1)
900       break;
901 
902   }
903   // Okay if I'm here than stat has failed so -100 on my cc
904   cc = cc - 100;
905   for ( cc = cc + 1; true; ++cc )
906   {
907     snprintf( buffer, sizeof(buffer), pattern, prefix.c_str(), cc );
908 
909     if (vtksys::SystemTools::Stat(buffer, &fs) == -1)
910       break;
911   }
912   // Okay if I'm here than stat has failed so -1 on my cc
913   max = cc - 1;
914 
915   // Second, go down every 100
916   // We can't assume that we're starting at 0 because the file selector
917   // will pick up every file that ends in .ex2v3... not just the first one.
918   for ( cc = min - 100; true; cc -= 100 )
919   {
920     if ( cc < 0 )
921       break;
922 
923     snprintf( buffer, sizeof(buffer), pattern, prefix.c_str(), cc );
924 
925     if (vtksys::SystemTools::Stat(buffer, &fs) == -1)
926       break;
927 
928   }
929 
930   cc += 100;
931   // Okay if I'm here than stat has failed so -100 on my cc
932   for (cc = cc - 1; true; --cc )
933   {
934     if ( cc < 0 )
935       break;
936 
937     snprintf( buffer, sizeof(buffer), pattern, prefix.c_str(), cc );
938 
939     if (vtksys::SystemTools::Stat(buffer, &fs) == -1)
940       break;
941   }
942   min = cc + 1;
943 
944   // If the user did not specify a range before this,
945   // than set the range to the min and max
946   if ( ( this->FileRange[0] == -1 ) && ( this->FileRange[1] == -1 ) )
947   {
948     //this->SetFileRange( min, max ); // XXX Bad set
949     this->FileRange[0] = min;
950     this->FileRange[1] = max;
951     this->NumberOfFiles = max - min + 1;
952   }
953 
954   // Set my info
955   //this->SetFilePattern( pattern ); // XXX Bad set
956   //this->SetFilePrefix( prefix ); // XXX Bad set
957   //delete [] prefix;
958   delete [] this->FilePattern;
959   delete [] this->FilePrefix;
960   this->FilePattern = vtksys::SystemTools::DuplicateString( pattern );
961   this->FilePrefix = vtksys::SystemTools::DuplicateString(prefix.c_str());
962 
963   return VTK_OK;
964 }
965 
966 //----------------------------------------------------------------------------
PrintSelf(ostream & os,vtkIndent indent)967 void vtkPExodusIIReader::PrintSelf( ostream& os, vtkIndent indent )
968 {
969   vtkExodusIIReader::PrintSelf( os, indent );
970 
971   if ( this->FilePattern )
972   {
973     os << indent << "FilePattern: " << this->FilePattern << endl;
974   }
975   else
976   {
977     os << indent << "FilePattern: nullptr\n";
978   }
979 
980   if ( this->FilePattern )
981   {
982     os << indent << "FilePrefix: " << this->FilePrefix << endl;
983   }
984   else
985   {
986     os << indent << "FilePrefix: nullptr\n";
987   }
988 
989   os << indent << "FileRange: "
990      << this->FileRange[0] << " " << this->FileRange[1] << endl;
991 
992   os << indent << "NumberOfFiles: " << this->NumberOfFiles << endl;
993   os << indent << "Controller: " << this->Controller << endl;
994   os << indent << "VariableCacheSize: " << this->VariableCacheSize << endl;
995 }
996 
GetTotalNumberOfElements()997 vtkIdType vtkPExodusIIReader::GetTotalNumberOfElements()
998 {
999   vtkIdType total = 0;
1000   std::vector<vtkExodusIIReader*>::iterator it;
1001   for ( it = this->ReaderList.begin(); it != this->ReaderList.end(); ++ it )
1002   {
1003     total += (*it)->GetTotalNumberOfElements();
1004   }
1005   return total;
1006 }
1007 
GetTotalNumberOfNodes()1008 vtkIdType vtkPExodusIIReader::GetTotalNumberOfNodes()
1009 {
1010   vtkIdType total = 0;
1011   std::vector<vtkExodusIIReader*>::iterator it;
1012   for ( it = this->ReaderList.begin(); it != this->ReaderList.end(); ++ it )
1013   {
1014     total += (*it)->GetTotalNumberOfNodes();
1015   }
1016   return total;
1017 }
1018 
BroadcastXmitString(vtkMultiProcessController * ctrl,char * str)1019 static void BroadcastXmitString( vtkMultiProcessController* ctrl, char* str )
1020 {
1021   int len;
1022   if ( str )
1023   {
1024     len = static_cast<int>( strlen( str ) ) + 1;
1025     ctrl->Broadcast( &len, 1, 0 );
1026     ctrl->Broadcast( str, len, 0 );
1027   }
1028   else
1029   {
1030     len = 0;
1031     ctrl->Broadcast( &len, 1, 0 );
1032   }
1033 }
1034 
BroadcastRecvString(vtkMultiProcessController * ctrl,std::vector<char> & str)1035 static bool BroadcastRecvString( vtkMultiProcessController* ctrl,
1036   std::vector<char>& str )
1037 {
1038   int len;
1039   ctrl->Broadcast( &len, 1, 0 );
1040   if ( len )
1041   {
1042     str.resize( len );
1043     ctrl->Broadcast( &str[0], len, 0 );
1044     return true;
1045   }
1046   return false;
1047 }
1048 
BroadcastDoubleVector(vtkMultiProcessController * controller,std::vector<double> & dvec,int rank)1049 static void BroadcastDoubleVector( vtkMultiProcessController* controller,
1050   std::vector<double>& dvec, int rank )
1051 {
1052   unsigned long len = static_cast<unsigned long>( dvec.size() );
1053   controller->Broadcast( &len, 1, 0 );
1054   if ( rank )
1055   {
1056     dvec.resize( len );
1057   }
1058   if ( len )
1059   {
1060     controller->Broadcast( &dvec[0], len, 0 );
1061   }
1062 }
1063 
BroadcastIntVector(vtkMultiProcessController * controller,std::vector<int> & ivec,int rank)1064 static void BroadcastIntVector( vtkMultiProcessController* controller,
1065   std::vector<int>& ivec, int rank )
1066 {
1067   unsigned long len = static_cast<unsigned long>( ivec.size() );
1068   controller->Broadcast( &len, 1, 0 );
1069   if ( rank )
1070   {
1071     ivec.resize( len );
1072   }
1073   if ( len )
1074   {
1075     controller->Broadcast( &ivec[0], len, 0 );
1076   }
1077 }
1078 
BroadcastString(vtkMultiProcessController * controller,vtkStdString & str,int rank)1079 static void BroadcastString( vtkMultiProcessController* controller,
1080   vtkStdString& str, int rank )
1081 {
1082   unsigned long len = static_cast<unsigned long>( str.size() ) + 1;
1083   controller->Broadcast( &len, 1, 0 );
1084   if ( len )
1085   {
1086     if ( rank )
1087     {
1088       std::vector<char> tmp;
1089       tmp.resize( len );
1090       controller->Broadcast( &(tmp[0]), len, 0 );
1091       str = &tmp[0];
1092     }
1093     else
1094     {
1095       const char* start = str.c_str();
1096       std::vector<char> tmp( start, start + len );
1097       controller->Broadcast( &tmp[0], len, 0 );
1098     }
1099   }
1100 }
1101 
BroadcastStringVector(vtkMultiProcessController * controller,std::vector<vtkStdString> & svec,int rank)1102 static void BroadcastStringVector( vtkMultiProcessController* controller,
1103   std::vector<vtkStdString>& svec, int rank )
1104 {
1105   unsigned long len = static_cast<unsigned long>( svec.size() );
1106   controller->Broadcast( &len, 1, 0 );
1107   if ( rank )
1108     svec.resize( len );
1109   std::vector<vtkStdString>::iterator it;
1110   for ( it = svec.begin(); it != svec.end(); ++ it )
1111   {
1112     BroadcastString( controller, *it, rank );
1113   }
1114 }
1115 
BroadcastObjectInfo(vtkMultiProcessController * controller,vtkExodusIIReaderPrivate::ObjectInfoType * oinfo,int rank)1116 static void BroadcastObjectInfo( vtkMultiProcessController* controller,
1117   vtkExodusIIReaderPrivate::ObjectInfoType* oinfo, int rank )
1118 {
1119   controller->Broadcast( &oinfo->Size, 1, 0 );
1120   controller->Broadcast( &oinfo->Status, 1, 0 );
1121   controller->Broadcast( &oinfo->Id, 1, 0 );
1122   BroadcastString( controller, oinfo->Name, rank );
1123 }
1124 
BroadcastBlockSetInfo(vtkMultiProcessController * controller,vtkExodusIIReaderPrivate::BlockSetInfoType * bsinfo,int rank)1125 static void BroadcastBlockSetInfo( vtkMultiProcessController* controller,
1126   vtkExodusIIReaderPrivate::BlockSetInfoType* bsinfo, int rank )
1127 {
1128   BroadcastObjectInfo( controller, bsinfo, rank );
1129   controller->Broadcast( &bsinfo->FileOffset, 1, 0 );
1130   unsigned long len;
1131   unsigned long i;
1132   std::map<vtkIdType,vtkIdType>::iterator it;
1133   vtkIdType item[2];
1134   if ( rank == 0 )
1135   {
1136     len = static_cast<unsigned long>( bsinfo->PointMap.size() );
1137     controller->Broadcast( &len, 1, 0 );
1138     for ( it = bsinfo->PointMap.begin(); it != bsinfo->PointMap.end(); ++ it )
1139     {
1140       item[0] = it->first;
1141       item[1] = it->second;
1142       controller->Broadcast( item, 2, 0 );
1143     }
1144   }
1145   else
1146   {
1147     if ( bsinfo->CachedConnectivity )
1148     {
1149       bsinfo->CachedConnectivity->Delete();
1150     }
1151     bsinfo->CachedConnectivity = 0;
1152     bsinfo->PointMap.clear();
1153     bsinfo->ReversePointMap.clear();
1154     controller->Broadcast( &len, 1, 0 );
1155     for ( i = 0; i < len; ++ i )
1156     {
1157       controller->Broadcast( item, 2, 0 );
1158       bsinfo->PointMap[item[0]] = item[1];
1159       bsinfo->ReversePointMap[item[1]] = item[0];
1160     }
1161   }
1162   controller->Broadcast( &bsinfo->NextSqueezePoint, 1, 0 );
1163 }
1164 
BroadcastBlockInfo(vtkMultiProcessController * controller,vtkExodusIIReaderPrivate::BlockInfoType * binfo,int rank)1165 static void BroadcastBlockInfo( vtkMultiProcessController* controller,
1166   vtkExodusIIReaderPrivate::BlockInfoType* binfo, int rank )
1167 {
1168   BroadcastBlockSetInfo( controller, binfo, rank );
1169   BroadcastString( controller, binfo->TypeName, rank );
1170   controller->Broadcast( binfo->BdsPerEntry, 3, 0 );
1171   controller->Broadcast( &binfo->AttributesPerEntry, 1, 0 );
1172   BroadcastStringVector( controller, binfo->AttributeNames, rank );
1173   BroadcastIntVector( controller, binfo->AttributeStatus, rank );
1174   controller->Broadcast( &binfo->CellType, 1, 0 );
1175   controller->Broadcast( &binfo->PointsPerCell, 1, 0 );
1176 }
1177 
BroadcastPartInfo(vtkMultiProcessController * controller,vtkExodusIIReaderPrivate::PartInfoType * pinfo,int rank)1178 static void BroadcastPartInfo( vtkMultiProcessController* controller,
1179   vtkExodusIIReaderPrivate::PartInfoType* pinfo, int rank )
1180 {
1181   BroadcastObjectInfo( controller, pinfo, rank );
1182   BroadcastIntVector( controller, pinfo->BlockIndices, rank );
1183 }
1184 
BroadcastAssemblyInfo(vtkMultiProcessController * controller,vtkExodusIIReaderPrivate::AssemblyInfoType * ainfo,int rank)1185 static void BroadcastAssemblyInfo( vtkMultiProcessController* controller,
1186   vtkExodusIIReaderPrivate::AssemblyInfoType* ainfo, int rank )
1187 {
1188   BroadcastObjectInfo( controller, ainfo, rank );
1189   BroadcastIntVector( controller, ainfo->BlockIndices, rank );
1190 }
1191 
BroadcastMaterialInfo(vtkMultiProcessController * controller,vtkExodusIIReaderPrivate::MaterialInfoType * minfo,int rank)1192 static void BroadcastMaterialInfo( vtkMultiProcessController* controller,
1193   vtkExodusIIReaderPrivate::MaterialInfoType* minfo, int rank )
1194 {
1195   BroadcastObjectInfo( controller, minfo, rank );
1196   BroadcastIntVector( controller, minfo->BlockIndices, rank );
1197 }
1198 
BroadcastSetInfo(vtkMultiProcessController * controller,vtkExodusIIReaderPrivate::SetInfoType * sinfo,int rank)1199 static void BroadcastSetInfo( vtkMultiProcessController* controller,
1200   vtkExodusIIReaderPrivate::SetInfoType* sinfo, int rank )
1201 {
1202   BroadcastBlockSetInfo( controller, sinfo, rank );
1203   controller->Broadcast( &sinfo->DistFact, 1, 0 );
1204 }
1205 
BroadcastArrayInfo(vtkMultiProcessController * controller,vtkExodusIIReaderPrivate::ArrayInfoType * ainfo,int rank)1206 static void BroadcastArrayInfo( vtkMultiProcessController* controller,
1207   vtkExodusIIReaderPrivate::ArrayInfoType* ainfo, int rank )
1208 {
1209   if ( rank )
1210     ainfo->Reset();
1211 
1212   BroadcastString( controller, ainfo->Name, rank );
1213   controller->Broadcast( &ainfo->Components, 1, 0 );
1214   controller->Broadcast( &ainfo->GlomType, 1, 0 );
1215   controller->Broadcast( &ainfo->StorageType, 1, 0 );
1216   controller->Broadcast( &ainfo->Source, 1, 0 );
1217   controller->Broadcast( &ainfo->Status, 1, 0 );
1218   BroadcastStringVector( controller, ainfo->OriginalNames, rank );
1219   BroadcastIntVector( controller, ainfo->OriginalIndices, rank );
1220   BroadcastIntVector( controller, ainfo->ObjectTruth, rank );
1221 }
1222 
BroadcastArrayInfoVector(vtkMultiProcessController * controller,std::vector<vtkExodusIIReaderPrivate::ArrayInfoType> & ainfo,int rank)1223 static void BroadcastArrayInfoVector( vtkMultiProcessController* controller,
1224   std::vector<vtkExodusIIReaderPrivate::ArrayInfoType>& ainfo, int rank )
1225 {
1226   unsigned long len = static_cast<unsigned long>( ainfo.size() );
1227   controller->Broadcast( &len, 1, 0 );
1228   if ( rank )
1229     ainfo.resize( len );
1230   unsigned long i;
1231   for ( i = 0; i < len; ++ i )
1232   {
1233     BroadcastArrayInfo( controller, &ainfo[i], rank );
1234   }
1235 }
1236 
BroadcastSortedObjectIndices(vtkMultiProcessController * controller,std::map<int,std::vector<int>> & oidx,int rank)1237 static void BroadcastSortedObjectIndices( vtkMultiProcessController* controller,
1238   std::map<int,std::vector<int> >& oidx, int rank )
1239 {
1240   unsigned long len = static_cast<unsigned long>( oidx.size() );
1241   controller->Broadcast( &len, 1, 0 );
1242   if ( rank == 0 )
1243   {
1244     std::map<int,std::vector<int> >::iterator it;
1245     int tmp;
1246     for ( it = oidx.begin(); it != oidx.end(); ++ it )
1247     {
1248       tmp = it->first;
1249       controller->Broadcast( &tmp, 1, 0 );
1250       BroadcastIntVector( controller, it->second, rank );
1251     }
1252   }
1253   else
1254   {
1255     unsigned long i;
1256     for ( i = 0; i < len; ++ i )
1257     {
1258       std::vector<int> blank;
1259       int key;
1260       controller->Broadcast( &key, 1, 0 );
1261       oidx[key] = blank;
1262       BroadcastIntVector( controller, oidx[key], rank );
1263     }
1264   }
1265 }
1266 
BroadcastArrayInfoMap(vtkMultiProcessController * controller,std::map<int,std::vector<vtkExodusIIReaderPrivate::ArrayInfoType>> & oidx,int rank)1267 static void BroadcastArrayInfoMap(
1268   vtkMultiProcessController* controller,
1269   std::map<int,std::vector<vtkExodusIIReaderPrivate::ArrayInfoType> >& oidx, int rank )
1270 {
1271   unsigned long len = static_cast<unsigned long>( oidx.size() );
1272   controller->Broadcast( &len, 1, 0 );
1273   if ( rank == 0 )
1274   {
1275     int tmp;
1276     std::map<int,std::vector<vtkExodusIIReaderPrivate::ArrayInfoType> >::iterator it;
1277     for ( it = oidx.begin(); it != oidx.end(); ++ it )
1278     {
1279       tmp = it->first;
1280       controller->Broadcast( &tmp, 1, 0 );
1281       BroadcastArrayInfoVector( controller, it->second, rank );
1282     }
1283   }
1284   else
1285   {
1286     unsigned long i;
1287     for ( i = 0; i < len; ++ i )
1288     {
1289       std::vector<vtkExodusIIReaderPrivate::ArrayInfoType> blank;
1290       int key;
1291       controller->Broadcast( &key, 1, 0 );
1292       oidx[key] = blank;
1293       BroadcastArrayInfoVector( controller, oidx[key], rank );
1294     }
1295   }
1296 }
1297 
BroadcastModelParameters(vtkMultiProcessController * controller,ex_init_params & params,int vtkNotUsed (rank))1298 static void BroadcastModelParameters(
1299   vtkMultiProcessController* controller, ex_init_params& params, int vtkNotUsed(rank) )
1300 {
1301   controller->Broadcast( params.title, MAX_LINE_LENGTH + 1, 0 );
1302   controller->Broadcast( &params.num_dim, 1, 0 );
1303   controller->Broadcast( &params.num_nodes, 1, 0 );
1304   controller->Broadcast( &params.num_edge, 1, 0 );
1305   controller->Broadcast( &params.num_edge_blk, 1, 0 );
1306   controller->Broadcast( &params.num_face, 1, 0 );
1307   controller->Broadcast( &params.num_face_blk, 1, 0 );
1308   controller->Broadcast( &params.num_elem, 1, 0 );
1309   controller->Broadcast( &params.num_elem_blk, 1, 0 );
1310   controller->Broadcast( &params.num_node_sets, 1, 0 );
1311   controller->Broadcast( &params.num_edge_sets, 1, 0 );
1312   controller->Broadcast( &params.num_face_sets, 1, 0 );
1313   controller->Broadcast( &params.num_side_sets, 1, 0 );
1314   controller->Broadcast( &params.num_elem_sets, 1, 0 );
1315   controller->Broadcast( &params.num_node_maps, 1, 0 );
1316   controller->Broadcast( &params.num_edge_maps, 1, 0 );
1317   controller->Broadcast( &params.num_face_maps, 1, 0 );
1318   controller->Broadcast( &params.num_elem_maps, 1, 0 );
1319 }
1320 
BroadcastBlockInfoVector(vtkMultiProcessController * controller,std::vector<vtkExodusIIReaderPrivate::BlockInfoType> & binfo,int rank)1321 static void BroadcastBlockInfoVector( vtkMultiProcessController* controller,
1322   std::vector<vtkExodusIIReaderPrivate::BlockInfoType>& binfo, int rank )
1323 {
1324   unsigned long len = static_cast<unsigned long>( binfo.size() );
1325   controller->Broadcast( &len, 1, 0 );
1326   if ( rank )
1327     binfo.resize( len );
1328   std::vector<vtkExodusIIReaderPrivate::BlockInfoType>::iterator it;
1329   for ( it = binfo.begin(); it != binfo.end(); ++ it )
1330   {
1331     BroadcastBlockInfo( controller, &(*it), rank );
1332   }
1333 }
1334 
BroadcastBlockInfoMap(vtkMultiProcessController * controller,std::map<int,std::vector<vtkExodusIIReaderPrivate::BlockInfoType>> & binfo,int rank)1335 static void BroadcastBlockInfoMap( vtkMultiProcessController* controller,
1336   std::map<int,std::vector<vtkExodusIIReaderPrivate::BlockInfoType> >& binfo, int rank )
1337 {
1338   unsigned long len = static_cast<unsigned long>( binfo.size() );
1339   controller->Broadcast( &len, 1, 0 );
1340   int tmp;
1341   if ( rank == 0 )
1342   {
1343     std::map<int,std::vector<vtkExodusIIReaderPrivate::BlockInfoType> >::iterator it;
1344     for ( it = binfo.begin(); it != binfo.end(); ++ it )
1345     {
1346       tmp = it->first;
1347       controller->Broadcast( &tmp, 1, 0 );
1348       BroadcastBlockInfoVector( controller, it->second, rank );
1349     }
1350   }
1351   else
1352   {
1353     unsigned long i;
1354     std::vector<vtkExodusIIReaderPrivate::BlockInfoType> blank;
1355     for ( i = 0; i < len; ++ i )
1356     {
1357       controller->Broadcast( &tmp, 1, 0 );
1358       binfo[tmp] = blank;
1359       BroadcastBlockInfoVector( controller, binfo[tmp], rank );
1360     }
1361   }
1362 }
1363 
BroadcastSetInfoVector(vtkMultiProcessController * controller,std::vector<vtkExodusIIReaderPrivate::SetInfoType> & sinfo,int rank)1364 static void BroadcastSetInfoVector( vtkMultiProcessController* controller,
1365   std::vector<vtkExodusIIReaderPrivate::SetInfoType>& sinfo, int rank )
1366 {
1367   unsigned long len = static_cast<unsigned long>( sinfo.size() );
1368   controller->Broadcast( &len, 1, 0 );
1369   if ( rank )
1370     sinfo.resize( len );
1371   std::vector<vtkExodusIIReaderPrivate::SetInfoType>::iterator it;
1372   for ( it = sinfo.begin(); it != sinfo.end(); ++ it )
1373   {
1374     BroadcastSetInfo( controller, &(*it), rank );
1375   }
1376 }
1377 
BroadcastSetInfoMap(vtkMultiProcessController * controller,std::map<int,std::vector<vtkExodusIIReaderPrivate::SetInfoType>> & sinfo,int rank)1378 static void BroadcastSetInfoMap( vtkMultiProcessController* controller,
1379   std::map<int,std::vector<vtkExodusIIReaderPrivate::SetInfoType> >& sinfo, int rank )
1380 {
1381   unsigned long len = static_cast<unsigned long>( sinfo.size() );
1382   controller->Broadcast( &len, 1, 0 );
1383   int tmp;
1384   if ( rank == 0 )
1385   {
1386     std::map<int,std::vector<vtkExodusIIReaderPrivate::SetInfoType> >::iterator it;
1387     for ( it = sinfo.begin(); it != sinfo.end(); ++ it )
1388     {
1389       tmp = it->first;
1390       controller->Broadcast( &tmp, 1, 0 );
1391       BroadcastSetInfoVector( controller, it->second, rank );
1392     }
1393   }
1394   else
1395   {
1396     unsigned long i;
1397     std::vector<vtkExodusIIReaderPrivate::SetInfoType> blank;
1398     for ( i = 0; i < len; ++ i )
1399     {
1400       controller->Broadcast( &tmp, 1, 0 );
1401       sinfo[tmp] = blank;
1402       BroadcastSetInfoVector( controller, sinfo[tmp], rank );
1403     }
1404   }
1405 }
1406 
BroadcastMapInfoVector(vtkMultiProcessController * controller,std::vector<vtkExodusIIReaderPrivate::MapInfoType> & minfo,int rank)1407 static void BroadcastMapInfoVector( vtkMultiProcessController* controller,
1408   std::vector<vtkExodusIIReaderPrivate::MapInfoType>& minfo, int rank )
1409 {
1410   unsigned long len = static_cast<unsigned long>( minfo.size() );
1411   controller->Broadcast( &len, 1, 0 );
1412   if ( rank )
1413     minfo.resize( len );
1414   std::vector<vtkExodusIIReaderPrivate::MapInfoType>::iterator it;
1415   for ( it = minfo.begin(); it != minfo.end(); ++ it )
1416   {
1417     BroadcastObjectInfo( controller, &(*it), rank );
1418   }
1419 }
1420 
BroadcastMapInfoMap(vtkMultiProcessController * controller,std::map<int,std::vector<vtkExodusIIReaderPrivate::MapInfoType>> & minfo,int rank)1421 static void BroadcastMapInfoMap( vtkMultiProcessController* controller,
1422   std::map<int,std::vector<vtkExodusIIReaderPrivate::MapInfoType> >& minfo, int rank )
1423 {
1424   unsigned long len = static_cast<unsigned long>( minfo.size() );
1425   controller->Broadcast( &len, 1, 0 );
1426   int tmp;
1427   if ( rank == 0 )
1428   {
1429     std::map<int,std::vector<vtkExodusIIReaderPrivate::MapInfoType> >::iterator it;
1430     for ( it = minfo.begin(); it != minfo.end(); ++ it )
1431     {
1432       tmp = it->first;
1433       controller->Broadcast( &tmp, 1, 0 );
1434       BroadcastMapInfoVector( controller, it->second, rank );
1435     }
1436   }
1437   else
1438   {
1439     unsigned long i;
1440     std::vector<vtkExodusIIReaderPrivate::MapInfoType> blank;
1441     for ( i = 0; i < len; ++ i )
1442     {
1443       controller->Broadcast( &tmp, 1, 0 );
1444       minfo[tmp] = blank;
1445       BroadcastMapInfoVector( controller, minfo[tmp], rank );
1446     }
1447   }
1448 }
1449 
BroadcastPartInfoVector(vtkMultiProcessController * controller,std::vector<vtkExodusIIReaderPrivate::PartInfoType> & pinfo,int rank)1450 static void BroadcastPartInfoVector( vtkMultiProcessController* controller,
1451   std::vector<vtkExodusIIReaderPrivate::PartInfoType>& pinfo, int rank )
1452 {
1453   unsigned long len = static_cast<unsigned long>( pinfo.size() );
1454   controller->Broadcast( &len, 1, 0 );
1455   if ( rank )
1456     pinfo.resize( len );
1457   std::vector<vtkExodusIIReaderPrivate::PartInfoType>::iterator it;
1458   for ( it = pinfo.begin(); it != pinfo.end(); ++ it )
1459   {
1460     BroadcastPartInfo( controller, &(*it), rank );
1461   }
1462 }
1463 
BroadcastMaterialInfoVector(vtkMultiProcessController * controller,std::vector<vtkExodusIIReaderPrivate::MaterialInfoType> & minfo,int rank)1464 static void BroadcastMaterialInfoVector( vtkMultiProcessController* controller,
1465   std::vector<vtkExodusIIReaderPrivate::MaterialInfoType>& minfo, int rank )
1466 {
1467   unsigned long len = static_cast<unsigned long>( minfo.size() );
1468   controller->Broadcast( &len, 1, 0 );
1469   if ( rank )
1470     minfo.resize( len );
1471   std::vector<vtkExodusIIReaderPrivate::MaterialInfoType>::iterator it;
1472   for ( it = minfo.begin(); it != minfo.end(); ++ it )
1473   {
1474     BroadcastMaterialInfo( controller, &(*it), rank );
1475   }
1476 }
1477 
BroadcastAssemblyInfoVector(vtkMultiProcessController * controller,std::vector<vtkExodusIIReaderPrivate::AssemblyInfoType> & ainfo,int rank)1478 static void BroadcastAssemblyInfoVector( vtkMultiProcessController* controller,
1479   std::vector<vtkExodusIIReaderPrivate::AssemblyInfoType>& ainfo, int rank )
1480 {
1481   unsigned long len = static_cast<unsigned long>( ainfo.size() );
1482   controller->Broadcast( &len, 1, 0 );
1483   if ( rank )
1484     ainfo.resize( len );
1485   std::vector<vtkExodusIIReaderPrivate::AssemblyInfoType>::iterator it;
1486   for ( it = ainfo.begin(); it != ainfo.end(); ++ it )
1487   {
1488     BroadcastAssemblyInfo( controller, &(*it), rank );
1489   }
1490 }
1491 
Broadcast(vtkMultiProcessController * ctrl)1492 void vtkPExodusIIReader::Broadcast( vtkMultiProcessController* ctrl )
1493 {
1494   if ( ctrl )
1495   {
1496     int rank = ctrl->GetLocalProcessId();
1497     BroadcastBlockInfoMap( ctrl, this->Metadata->BlockInfo, rank );
1498     BroadcastSetInfoMap( ctrl, this->Metadata->SetInfo, rank );
1499     BroadcastMapInfoMap( ctrl, this->Metadata->MapInfo, rank );
1500     BroadcastPartInfoVector( ctrl, this->Metadata->PartInfo, rank );
1501     BroadcastMaterialInfoVector( ctrl, this->Metadata->MaterialInfo, rank );
1502     BroadcastAssemblyInfoVector( ctrl, this->Metadata->AssemblyInfo, rank );
1503     BroadcastSortedObjectIndices( ctrl, this->Metadata->SortedObjectIndices, rank );
1504     BroadcastArrayInfoMap( ctrl, this->Metadata->ArrayInfo, rank );
1505     ctrl->Broadcast( &this->Metadata->AppWordSize, 1, 0 );
1506     ctrl->Broadcast( &this->Metadata->DiskWordSize, 1, 0 );
1507     ctrl->Broadcast( &this->Metadata->ExodusVersion, 1, 0 );
1508     ctrl->Broadcast( &this->Metadata->ExodusVersion, 1, 0 );
1509     BroadcastModelParameters( ctrl, this->Metadata->ModelParameters, rank );
1510     BroadcastDoubleVector( ctrl, this->Metadata->Times, rank );
1511 
1512     ctrl->Broadcast( this->TimeStepRange, 2, 0 );
1513     if ( rank == 0 )
1514     {
1515       BroadcastXmitString( ctrl, this->FilePattern );
1516       BroadcastXmitString( ctrl, this->FilePrefix );
1517     }
1518     else
1519     {
1520       std::vector<char> tmp;
1521       delete [] this->FilePattern;
1522       delete [] this->FilePrefix;
1523       //this->SetFilePattern( BroadcastRecvString( ctrl, tmp ) ? &tmp[0] : 0 ); // XXX Bad set
1524       //this->SetFilePrefix(  BroadcastRecvString( ctrl, tmp ) ? &tmp[0] : 0 ); // XXX Bad set
1525       this->FilePattern = BroadcastRecvString( ctrl, tmp ) ? vtksys::SystemTools::DuplicateString( &tmp[0] ) : 0;
1526       this->FilePrefix =  BroadcastRecvString( ctrl, tmp ) ? vtksys::SystemTools::DuplicateString( &tmp[0] ) : 0;
1527     }
1528     ctrl->Broadcast( this->FileRange, 2, 0 );
1529     ctrl->Broadcast( &this->NumberOfFiles, 1, 0 );
1530   }
1531 }
1532