1 /*=========================================================================
2 
3   Program:   Visualization Toolkit
4   Module:    vtkExodusIIReader.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  Copyright (c) Sandia Corporation
17  See Copyright.txt or http://www.paraview.org/HTML/Copyright.html for details.
18 ----------------------------------------------------------------------------*/
19 #include "vtkExodusIIReader.h"
20 #include "vtkExodusIICache.h"
21 
22 #include "vtkCellArray.h"
23 #include "vtkCellData.h"
24 #include "vtkCellType.h"
25 #include "vtkCharArray.h"
26 #include "vtkDoubleArray.h"
27 #include "vtkFloatArray.h"
28 #include "vtkIdTypeArray.h"
29 #include "vtkInformation.h"
30 #include "vtkInformationVector.h"
31 #include "vtkIntArray.h"
32 #include "vtkMath.h"
33 #include "vtkMultiBlockDataSet.h"
34 #include "vtkMutableDirectedGraph.h"
35 #include "vtkNew.h"
36 #include "vtkObjectFactory.h"
37 #include "vtkPointData.h"
38 #include "vtkPoints.h"
39 #include "vtkPolyData.h"
40 #include "vtkSortDataArray.h"
41 #include "vtkStdString.h"
42 #include "vtkStreamingDemandDrivenPipeline.h"
43 #include "vtkTypeInt64Array.h"
44 #include "vtkUnstructuredGrid.h"
45 #include "vtkXMLParser.h"
46 #include "vtkStringArray.h"
47 #include "vtkUnsignedCharArray.h"
48 #include "vtkVariantArray.h"
49 #include "vtkSmartPointer.h"
50 #include "vtkExodusIIReaderParser.h"
51 
52 #include <algorithm>
53 #include <vector>
54 #include <map>
55 #include <set>
56 #include <deque>
57 #include <string>
58 #include "vtksys/SystemTools.hxx"
59 
60 #include "vtksys/RegularExpression.hxx"
61 
62 #include "vtk_exodusII.h"
63 #include <cstdio>
64 #include <cstdlib> /* for free() */
65 #include <cstring> /* for memset() */
66 #include <cctype> /* for toupper(), isgraph() */
67 #include <cmath> /* for cos() */
68 
69 #ifdef EXODUSII_HAVE_MALLOC_H
70 #  include <malloc.h>
71 #endif /* EXODUSII_HAVE_MALLOC_H */
72 
73 /// Define this to get printouts summarizing array glomming process
74 #undef VTK_DBG_GLOM
75 
76 #define VTK_EXO_FUNC(funcall,errmsg)\
77   if ( (funcall) < 0 ) \
78   { \
79       vtkErrorMacro( errmsg ); \
80       return 1; \
81   }
82 
83 // ------------------------------------------------------------------- CONSTANTS
84 static int obj_types[] = {
85   EX_EDGE_BLOCK,
86   EX_FACE_BLOCK,
87   EX_ELEM_BLOCK,
88   EX_NODE_SET,
89   EX_EDGE_SET,
90   EX_FACE_SET,
91   EX_SIDE_SET,
92   EX_ELEM_SET,
93   EX_NODE_MAP,
94   EX_EDGE_MAP,
95   EX_FACE_MAP,
96   EX_ELEM_MAP,
97   EX_NODAL
98 };
99 
100 static int num_obj_types = (int)(sizeof(obj_types)/sizeof(obj_types[0]));
101 
102 static int obj_sizes[] = {
103   EX_INQ_EDGE_BLK,
104   EX_INQ_FACE_BLK,
105   EX_INQ_ELEM_BLK,
106   EX_INQ_NODE_SETS,
107   EX_INQ_EDGE_SETS,
108   EX_INQ_FACE_SETS,
109   EX_INQ_SIDE_SETS,
110   EX_INQ_ELEM_SETS,
111   EX_INQ_NODE_MAP,
112   EX_INQ_EDGE_MAP,
113   EX_INQ_FACE_MAP,
114   EX_INQ_ELEM_MAP,
115   EX_INQ_NODES
116 };
117 
118 static const char* objtype_names[] = {
119   "Edge block",
120   "Face block",
121   "Element block",
122   "Node set",
123   "Edge set",
124   "Face set",
125   "Side set",
126   "Element set",
127   "Node map",
128   "Edge map",
129   "Face map",
130   "Element map",
131   "Nodal"
132 };
133 
134 static const char* obj_typestr[] = {
135   "L",
136   "F",
137   "E",
138   "M",
139   "D",
140   "A",
141   "S",
142   "T",
143   nullptr, /* maps have no result variables */
144   nullptr,
145   nullptr,
146   nullptr,
147   "N"
148 };
149 
150 #define OBJTYPE_IS_BLOCK(i) (((i)>=0)&&((i)<3))
151 #define OBJTYPE_IS_SET(i) (((i)>2)&&((i)<8))
152 #define OBJTYPE_IS_MAP(i) (((i)>7)&&((i)<12))
153 #define OBJTYPE_IS_NODAL(i) ((i)==12)
154 
155 // Unlike obj* items above:
156 // - conn* arrays only reference objects that generate connectivity information
157 // - conn* arrays are ordered the way users expect the output (*not* the same as above)
158 static int conn_types[] = {
159   vtkExodusIIReader::ELEM_BLOCK_ELEM_CONN,
160   vtkExodusIIReader::FACE_BLOCK_CONN,
161   vtkExodusIIReader::EDGE_BLOCK_CONN,
162   vtkExodusIIReader::ELEM_SET_CONN,
163   vtkExodusIIReader::SIDE_SET_CONN,
164   vtkExodusIIReader::FACE_SET_CONN,
165   vtkExodusIIReader::EDGE_SET_CONN,
166   vtkExodusIIReader::NODE_SET_CONN
167 };
168 
169 static const char* conn_types_names[] = {
170   "Element Blocks",
171   "Face Blocks",
172   "Edge Blocks",
173   "Element Sets",
174   "Side Sets",
175   "Face Sets",
176   "Edge Sets",
177   "Node Sets"
178 };
179 
180 static int num_conn_types = (int)(sizeof(conn_types)/sizeof(conn_types[0]));
181 
182 // Given a conn_type index, what is its matching obj_type index?
183 static int conn_obj_idx_cvt[] = {
184   2, 1, 0, 7, 6, 5, 4, 3
185 };
186 
187 #define CONNTYPE_IS_BLOCK(i) (((i)>=0)&&((i)<3))
188 #define CONNTYPE_IS_SET(i) (((i)>2)&&((i)<8))
189 
190 static const char* glomTypeNames[] = {
191   "Scalar",
192   "Vector2",
193   "Vector3",
194   "Symmetric Tensor",
195   "Integration Point Values"
196 };
197 
198 // used to store pointer to ex_get_node_num_map or ex_get_elem_num_map:
199 extern "C" { typedef int (*vtkExodusIIGetMapFunc)( int, int* ); }
200 
201 // --------------------------------------------------- PRIVATE CLASS DECLARATION
202 #include "vtkExodusIIReaderPrivate.h"
203 #include "vtkExodusIIReaderVariableCheck.h"
204 
205 // --------------------------------------------------- PRIVATE CLASS Implementations
BlockSetInfoType(const vtkExodusIIReaderPrivate::BlockSetInfoType & block)206 vtkExodusIIReaderPrivate::BlockSetInfoType::BlockSetInfoType(
207   const vtkExodusIIReaderPrivate::BlockSetInfoType &block):
208   vtkExodusIIReaderPrivate::ObjectInfoType(block),
209   FileOffset(block.FileOffset),
210   PointMap(block.PointMap),
211   ReversePointMap(block.ReversePointMap),
212   CachedConnectivity(nullptr)
213 {
214   //this is needed to properly manage memory.
215   //when vectors are resized or reserved the container
216   //might be copied to a memory spot, so we need a proper copy constructor
217   //so that the cache remains valid
218   this->CachedConnectivity = block.CachedConnectivity;
219 }
220 
~BlockSetInfoType()221 vtkExodusIIReaderPrivate::BlockSetInfoType::~BlockSetInfoType()
222 {
223   if (this->CachedConnectivity)
224   {
225     this->CachedConnectivity->Delete();
226   }
227 }
228 
operator =(const vtkExodusIIReaderPrivate::BlockSetInfoType & block)229 vtkExodusIIReaderPrivate::BlockSetInfoType& vtkExodusIIReaderPrivate::BlockSetInfoType::operator=(const vtkExodusIIReaderPrivate::BlockSetInfoType& block)
230 {
231   // protect against invalid self-assignment
232   if (this != &block)
233   {
234     // superclass
235     this->ObjectInfoType::operator=(static_cast<ObjectInfoType const&>(block));
236 
237     // delete existing
238     if (this->CachedConnectivity)
239     {
240       this->CachedConnectivity->Delete();
241       this->CachedConnectivity = nullptr;
242     }
243 
244     this->FileOffset = block.FileOffset;
245     this->PointMap = block.PointMap;
246     this->ReversePointMap = block.ReversePointMap;
247     this->NextSqueezePoint = block.NextSqueezePoint;
248     if (block.CachedConnectivity)
249     {
250       this->CachedConnectivity = vtkUnstructuredGrid::New();
251       this->CachedConnectivity->ShallowCopy(block.CachedConnectivity);
252     }
253   }
254 
255   return *this;
256 }
257 
258 // ----------------------------------------------------------- UTILITY ROUTINES
259 
260 // This function exists because FORTRAN ordering sucks.
extractTruthForVar(int num_obj,int num_vars,const int * truth_tab,int var,std::vector<int> & truth)261 static void extractTruthForVar( int num_obj, int num_vars, const int* truth_tab, int var, std::vector<int>& truth )
262 {
263   truth.clear();
264 
265   int obj;
266   int ttObj; // truth table entry for variable var on object obj.
267   for ( obj = 0; obj < num_obj; ++obj )
268   {
269     ttObj = truth_tab[ var + obj * num_vars ];
270     truth.push_back( ttObj );
271   }
272 }
273 
printBlock(ostream & os,vtkIndent indent,int btyp,vtkExodusIIReaderPrivate::BlockInfoType & binfo)274 static void printBlock( ostream& os, vtkIndent indent, int btyp,
275                         vtkExodusIIReaderPrivate::BlockInfoType& binfo )
276 {
277   int b = 0;
278   while ( obj_types[b] >= 0 && obj_types[b] != btyp )
279     ++b;
280   const char* btypnam = objtype_names[b];
281   os << indent << btypnam << " " << binfo.Id << " \"" << binfo.Name.c_str()
282      << "\" (" << binfo.Size << ")\n";
283   os << indent << "    FileOffset: " << binfo.FileOffset << "\n";
284   os << indent << "    CachedConn: " << binfo.CachedConnectivity << " ("
285      << binfo.Status << ")\n";
286   os << indent << "    PointMap: " << binfo.PointMap.size() << " entries, "
287      << "ReversePointMap: " << binfo.ReversePointMap.size() << " entries\n";
288   os << indent << "    Type: " << binfo.TypeName.c_str() << "\n";
289   os << indent << "    Bounds per entry, Node: " << binfo.BdsPerEntry[0]
290      << " Edge: " << binfo.BdsPerEntry[1] << " Face: " << binfo.BdsPerEntry[2]
291      << "\n";
292   os << indent << "    Attributes (" << binfo.AttributesPerEntry << "):";
293   int a;
294   for ( a = 0; a < binfo.AttributesPerEntry; ++a )
295   {
296     os << " \"" << binfo.AttributeNames[a].c_str() << "\"("
297        << binfo.AttributeStatus[a] << ")";
298   }
299   os << "\n";
300 }
301 
printSet(ostream & os,vtkIndent indent,int styp,vtkExodusIIReaderPrivate::SetInfoType & sinfo)302 static void printSet( ostream& os, vtkIndent indent, int styp,
303                       vtkExodusIIReaderPrivate::SetInfoType& sinfo )
304 {
305   int s = 0;
306   while ( obj_types[s] >= 0 && obj_types[s] != styp )
307     ++s;
308   const char* stypnam = objtype_names[s];
309   os << indent << stypnam << " " << sinfo.Id << " \"" << sinfo.Name.c_str()
310      << "\" (" << sinfo.Size << ")\n";
311   os << indent << "    FileOffset: " << sinfo.FileOffset << "\n";
312   os << indent << "    CachedConn: " << sinfo.CachedConnectivity << " ("
313      << sinfo.Status << ")\n";
314   os << indent << "    PointMap: " << sinfo.PointMap.size() << " entries, "
315      << "ReversePointMap: " << sinfo.ReversePointMap.size() << " entries\n";
316   os << indent << "    DistFact: " << sinfo.DistFact << "\n";
317 }
318 
printMap(ostream & os,vtkIndent indent,int mtyp,vtkExodusIIReaderPrivate::MapInfoType & minfo)319 static void printMap( ostream& os,
320                       vtkIndent indent,
321                       int mtyp,
322                       vtkExodusIIReaderPrivate::MapInfoType& minfo )
323 {
324   int m = 0;
325   while ( obj_types[m] >= 0 && obj_types[m] != mtyp )
326     ++m;
327   const char* mtypnam = objtype_names[m];
328   os << indent << mtypnam << " " << minfo.Id << " \"" << minfo.Name.c_str()
329      << "\" (" << minfo.Size << ")\n";
330   os << indent << "    Status: " << minfo.Status << "\n";
331 }
332 
printArray(ostream & os,vtkIndent indent,int atyp,vtkExodusIIReaderPrivate::ArrayInfoType & ainfo)333 static void printArray( ostream& os, vtkIndent indent, int atyp,
334                         vtkExodusIIReaderPrivate::ArrayInfoType& ainfo )
335 {
336   (void)atyp;
337   os << indent << "    " << ainfo.Name.c_str() << " [" << ainfo.Status << "] ( "
338      << ainfo.Components << " = { ";
339   os << ainfo.OriginalIndices[0] << " \"" << ainfo.OriginalNames[0] << "\"";
340   int i;
341   for ( i = 1; i < (int) ainfo.OriginalIndices.size(); ++i )
342   {
343     os << ", " << ainfo.OriginalIndices[i] << " \"" << ainfo.OriginalNames[i]
344        << "\"";
345   }
346   os << " } )\n";
347   os << indent << "    " << glomTypeNames[ ainfo.GlomType ] << " Truth:";
348   for ( i = 0; i < (int)ainfo.ObjectTruth.size(); ++i )
349   {
350     os << " " << ainfo.ObjectTruth[i];
351   }
352   os << "\n";
353 }
354 
355 // --------------------------------------------------- PRIVATE SUBCLASS MEMBERS
Reset()356 void vtkExodusIIReaderPrivate::ArrayInfoType::Reset()
357 {
358   if ( ! this->Name.empty() )
359   {
360     this->Name.erase( this->Name.begin(), this->Name.end() );
361   }
362   this->Components = 0;
363   this->GlomType = -1;
364   this->Status = 0;
365   this->Source = -1;
366   this->OriginalNames.clear();
367   this->OriginalIndices.clear();
368   this->ObjectTruth.clear();
369 }
370 
371 // ------------------------------------------------------- PRIVATE CLASS MEMBERS
372 vtkStandardNewMacro(vtkExodusIIReaderPrivate);
373 
374 //-----------------------------------------------------------------------------
vtkExodusIIReaderPrivate()375 vtkExodusIIReaderPrivate::vtkExodusIIReaderPrivate()
376 {
377   this->Exoid = -1;
378   this->ExodusVersion = -1.;
379 
380   this->AppWordSize = 8;
381   this->DiskWordSize = 8;
382 
383   this->Cache = vtkExodusIICache::New();
384   this->CacheSize = 0;
385 
386   this->HasModeShapes = 0;
387   this->ModeShapeTime = -1.;
388   this->AnimateModeShapes = 1;
389 
390   this->IgnoreFileTime = false;
391 
392   this->GenerateObjectIdArray = 1;
393   this->GenerateGlobalElementIdArray = 0;
394   this->GenerateGlobalNodeIdArray = 0;
395   this->GenerateImplicitElementIdArray = 0;
396   this->GenerateImplicitNodeIdArray = 0;
397   this->GenerateGlobalIdArray = 0;
398   this->GenerateFileIdArray = 0;
399   this->FileId = 0;
400   this->ApplyDisplacements = 1;
401   this->DisplacementMagnitude = 1.;
402 
403   this->SqueezePoints = 1;
404 
405   this->Parser = nullptr;
406 
407   this->SIL = vtkMutableDirectedGraph::New();
408   this->SkipUpdateTimeInformation = false;
409 
410   memset( (void*)&this->ModelParameters, 0, sizeof(this->ModelParameters) );
411 }
412 
413 //-----------------------------------------------------------------------------
~vtkExodusIIReaderPrivate()414 vtkExodusIIReaderPrivate::~vtkExodusIIReaderPrivate()
415 {
416   this->CloseFile();
417   this->Cache->Delete();
418   this->CacheSize = 0;
419   this->ClearConnectivityCaches();
420   if(this->Parser)
421   {
422     this->Parser->Delete();
423     this->Parser = nullptr;
424   }
425   this->SIL->Delete();
426   this->SIL = nullptr;
427 }
428 
429 //-----------------------------------------------------------------------------
GlomArrayNames(int objtyp,int num_obj,int num_vars,char ** var_names,int * truth_tab)430 void vtkExodusIIReaderPrivate::GlomArrayNames( int objtyp,
431                                                int num_obj,
432                                                int num_vars,
433                                                char** var_names,
434                                                int* truth_tab )
435 {
436   // Clear out existing array names since we are re-reading them in.
437   this->ArrayInfo[objtyp].clear();
438 
439   // Create some objects that try to glom names together in different ways.
440   const char endRZ[] = "RZ";
441   const char endV2[] = "xy";
442   const char endV3[] = "xYz";
443   const char endST23[] = "XXYYZZXYXZYZ";
444   const char endST34[] = "XXXYYYZZZWWWXXYXXZXXWXYYXYZXYWXZZXZWXWWYYZYYWYZZYZWYWWZZWZWW";
445 
446   vtkExodusIIReaderScalarCheck* scalar = new vtkExodusIIReaderScalarCheck;
447   //vtkExodusIIReaderVectorCheck* vecx2 = new vtkExodusIIReaderVectorCheck( endV2, 2 );
448   //vtkExodusIIReaderVectorCheck* vecx3 = new vtkExodusIIReaderVectorCheck( endV3, 3 );
449   //vtkExodusIIReaderVectorCheck* vecrz = new vtkExodusIIReaderVectorCheck( endRZ, 2 );
450   vtkExodusIIReaderTensorCheck* vecx2 = new vtkExodusIIReaderTensorCheck( endV2, 2, 1, 2 );
451   vtkExodusIIReaderTensorCheck* vecx3 = new vtkExodusIIReaderTensorCheck( endV3, 3, 1, 3 );
452   vtkExodusIIReaderTensorCheck* vecrz = new vtkExodusIIReaderTensorCheck( endRZ, 2, 1, 2 );
453   vtkExodusIIReaderTensorCheck* ten23 = new vtkExodusIIReaderTensorCheck( endST23, 6, 2, 3 );
454   vtkExodusIIReaderTensorCheck* ten34 = new vtkExodusIIReaderTensorCheck( endST34, 20, 3, 4 );
455   vtkExodusIIReaderIntPointCheck* intpt = new vtkExodusIIReaderIntPointCheck;
456   typedef std::vector<vtkExodusIIReaderVariableCheck*> glomVec;
457   glomVec glommers;
458   glommers.push_back( scalar );
459   glommers.push_back( vecx2 );
460   glommers.push_back( vecx3 );
461   glommers.push_back( vecrz );
462   glommers.push_back( ten23 );
463   glommers.push_back( ten34 );
464   glommers.push_back( intpt );
465   glomVec::iterator glommer;
466   std::vector<int> tmpTruth;
467   // Advance through the variable names.
468   for ( int i = 0; i < num_vars; ++ i )
469   {
470     // Prepare all the glommers with the next unused variable name
471     extractTruthForVar( num_obj, num_vars, truth_tab, i, tmpTruth );
472     bool stop = true;
473     for ( glommer = glommers.begin(); glommer != glommers.end(); ++ glommer )
474     {
475       if ( (*glommer)->Start( var_names[i], &tmpTruth[0], num_obj ) )
476       {
477         stop = false;
478       }
479     }
480     int j = i + 1;
481     // If any glommers can continue accepting names, give them more names until no more can accept names
482     while ( j < num_vars && ! stop )
483     {
484       stop = true;
485       for ( glommer = glommers.begin(); glommer != glommers.end(); ++ glommer )
486       {
487         if ( (*glommer)->Add( var_names[j], &tmpTruth[0] ) )
488         {
489           stop = false;
490         }
491       }
492       ++ j;
493     }
494     // Find longest glom that worked. (The scalar glommer always works with Length() 1.)
495     unsigned int longestGlom = 0;
496     glomVec::iterator longestGlommer = glommers.end();
497     for ( glommer = glommers.begin(); glommer != glommers.end(); ++ glommer )
498     {
499       if ( (*glommer)->Length() > longestGlom )
500       {
501         longestGlom = static_cast<unsigned int>( (*glommer)->Length() );
502         longestGlommer = glommer;
503       }
504     }
505     if ( longestGlommer != glommers.end() )
506     {
507       i += (*longestGlommer)->Accept( this->ArrayInfo[objtyp], i, this, objtyp ) - 1; // the ++i takes care of length 1
508     }
509   }
510 
511   // Now see what the gloms were.
512   /*
513   typedef std::vector<vtkExodusIIReaderPrivate::ArrayInfoType> varVec;
514   for ( varVec::iterator it = this->ArrayInfo[objtyp].begin(); it != this->ArrayInfo[objtyp].end(); ++ it )
515     {
516     cout << "Name: \"" << it->Name.c_str() << "\" (" << it->Components << ")\n";
517     }
518     */
519 
520   delete scalar;
521   delete vecx2;
522   delete vecx3;
523   delete vecrz;
524   delete ten23;
525   delete ten34;
526   delete intpt;
527 }
528 
529 //-----------------------------------------------------------------------------
AssembleOutputConnectivity(vtkIdType timeStep,int otyp,int oidx,int conntypidx,BlockSetInfoType * bsinfop,vtkUnstructuredGrid * output)530 int vtkExodusIIReaderPrivate::AssembleOutputConnectivity(
531   vtkIdType timeStep, int otyp, int oidx, int conntypidx,
532   BlockSetInfoType* bsinfop, vtkUnstructuredGrid* output )
533 {
534   // FIXME: Don't think I need this, since we ShallowCopy over it... right?
535   output->Reset();
536   if ( bsinfop->CachedConnectivity )
537   {
538     output->ShallowCopy( bsinfop->CachedConnectivity );
539     return 1;
540   }
541 
542   // OK, we needed to remake the cache...
543   bsinfop->CachedConnectivity = vtkUnstructuredGrid::New();
544   bsinfop->CachedConnectivity->Allocate( bsinfop->Size );
545   if ( this->SqueezePoints )
546   {
547     bsinfop->NextSqueezePoint = 0;
548     bsinfop->PointMap.clear();
549     bsinfop->ReversePointMap.clear();
550   }
551 
552   // Need to assemble connectivity array from smaller ones.
553   // Call GetCacheOrRead() for each smaller array
554 
555   // Might want to experiment with the effectiveness of caching connectivity...
556   //   set up the ExodusIICache class with the ability to never cache some
557   //   key types.
558   // Might also want to experiment with policies other than LRU, especially
559   //   applied to arrays that are not time-varying. During animations, they
560   //   will most likely get dropped even though that might not be wise.
561 
562   if ( CONNTYPE_IS_BLOCK(conntypidx) )
563   {
564     this->InsertBlockCells( otyp, oidx, conn_types[conntypidx],
565       timeStep, static_cast<BlockInfoType*>( bsinfop ) );
566   }
567   else if ( CONNTYPE_IS_SET(conntypidx) )
568   {
569     this->InsertSetCells( otyp, oidx, conn_types[conntypidx],
570       timeStep, static_cast<SetInfoType*>( bsinfop ) );
571   }
572   else
573   {
574     vtkErrorMacro( "Bad connectivity object type. Harass the responsible programmer." );
575   }
576 
577   // OK, now copy our cache to the output...
578   output->ShallowCopy( bsinfop->CachedConnectivity );
579   //this->CachedConnectivity->ShallowCopy( output );
580   if ( this->SqueezePoints )
581   {
582     vtkDebugMacro( << "Squeezed down to " << bsinfop->NextSqueezePoint << " points\n" );
583   }
584   return 0;
585 }
586 
AssembleOutputPoints(vtkIdType timeStep,BlockSetInfoType * bsinfop,vtkUnstructuredGrid * output)587 int vtkExodusIIReaderPrivate::AssembleOutputPoints(
588   vtkIdType timeStep, BlockSetInfoType* bsinfop, vtkUnstructuredGrid* output )
589 {
590   (void)timeStep;
591   vtkPoints* pts = output->GetPoints();
592   if ( ! pts )
593   {
594     pts = vtkPoints::New();
595     output->SetPoints( pts );
596     pts->FastDelete();
597   }
598   else
599   {
600     pts->Reset();
601   }
602 
603   int ts = -1; // If we don't have displacements, only cache the array under one key.
604   if ( this->ApplyDisplacements && this->FindDisplacementVectors( timeStep ) )
605   { // Otherwise, each time step's array will be different.
606     ts = timeStep;
607   }
608 
609   vtkDataArray* arr = this->GetCacheOrRead( vtkExodusIICacheKey( ts, vtkExodusIIReader::NODAL_COORDS, 0, 0 ) );
610   if ( ! arr )
611   {
612     vtkErrorMacro( "Unable to read points from file." );
613     return 0;
614   }
615 
616   if ( this->SqueezePoints )
617   {
618     pts->SetNumberOfPoints( bsinfop->NextSqueezePoint );
619     std::map<vtkIdType,vtkIdType>::iterator it;
620     for ( it = bsinfop->PointMap.begin(); it != bsinfop->PointMap.end(); ++ it )
621     {
622       pts->SetPoint( it->second, arr->GetTuple( it->first ) );
623     }
624   }
625   else
626   {
627     pts->SetData( arr );
628   }
629   return 1;
630 }
631 
632 //-----------------------------------------------------------------------------
AssembleOutputPointArrays(vtkIdType timeStep,BlockSetInfoType * bsinfop,vtkUnstructuredGrid * output)633 int vtkExodusIIReaderPrivate::AssembleOutputPointArrays(
634   vtkIdType timeStep, BlockSetInfoType* bsinfop, vtkUnstructuredGrid* output )
635 {
636   int status = 1;
637   std::vector<ArrayInfoType>::iterator ai;
638   int aidx = 0;
639 
640   for (
641     ai = this->ArrayInfo[ vtkExodusIIReader::NODAL ].begin();
642     ai != this->ArrayInfo[ vtkExodusIIReader::NODAL ].end();
643     ++ai, ++aidx )
644   {
645     if ( ! ai->Status )
646       continue; // Skip arrays we don't want.
647 
648     vtkExodusIICacheKey key( timeStep, vtkExodusIIReader::NODAL, 0, aidx );
649     vtkDataArray* src = this->GetCacheOrRead( key );
650     if ( !src )
651     {
652       vtkDebugMacro( "Unable to read point array " << ai->Name.c_str() << " at time step " << timeStep );
653       status = 0;
654       continue;
655     }
656 
657     this->AddPointArray( src, bsinfop, output );
658   }
659   return status;
660 }
661 
662 //-----------------------------------------------------------------------------
663 #if 0
664 // Copy tuples from one array to another, possibly with a different number of components per tuple.
665 static void vtkEmbedTuplesInLargerArray(
666   vtkDataSetAttributes* attr, vtkDataArray* dst, vtkDataArray* src, vtkIdType numTuples, vtkIdType offset )
667 {
668   vtkIdType i;
669   int srcNumComp = src->GetNumberOfComponents();
670   int dstNumComp = dst->GetNumberOfComponents();
671   if ( dstNumComp != srcNumComp )
672   { // We've promoted the array from 2-D to 3-D... can't use CopyTuple
673     if ( dst->GetDataType() != src->GetDataType() )
674     {
675       return;
676     }
677     vtkIdType sid = 0;
678     vtkIdType did = offset * dstNumComp;
679     int minNumComp = dstNumComp < srcNumComp ? dstNumComp : srcNumComp;
680     switch( dst->GetDataType() )
681     {
682       vtkTemplateMacro(
683       {
684         VTK_TT* srcTuple = (VTK_TT*) src->GetVoidPointer( sid );
685         VTK_TT* dstTuple = (VTK_TT*) dst->GetVoidPointer( did );
686         for ( i = 0; i < numTuples; ++i, srcTuple += srcNumComp, dstTuple += dstNumComp )
687         {
688           for ( int j = 0; j < minNumComp; ++j )
689           {
690             dstTuple[j] = srcTuple[j];
691           }
692         }
693       }
694       );
695     }
696   }
697   else
698   {
699     for ( i = 0; i < numTuples; ++i )
700     {
701       attr->CopyTuple( src, dst, i, i + offset );
702     }
703   }
704 }
705 #endif // 0
706 
707 //-----------------------------------------------------------------------------
AssembleOutputCellArrays(vtkIdType timeStep,int otyp,int obj,BlockSetInfoType * bsinfop,vtkUnstructuredGrid * output)708 int vtkExodusIIReaderPrivate::AssembleOutputCellArrays(
709   vtkIdType timeStep, int otyp, int obj, BlockSetInfoType* bsinfop,
710   vtkUnstructuredGrid* output )
711 {
712   // Don't create arrays for deselected objects
713   if ( !output || ! bsinfop->Status )
714   {
715     return 1;
716   }
717 
718   vtkCellData* cd = output->GetCellData();
719   // Load (time-constant) attributes first because their status is in the block info.
720   if (
721     otyp == vtkExodusIIReader::ELEM_BLOCK ||
722     otyp == vtkExodusIIReader::EDGE_BLOCK ||
723     otyp == vtkExodusIIReader::FACE_BLOCK)
724   {
725     BlockInfoType* binfop = (BlockInfoType*)bsinfop;
726     std::vector<int>::iterator atit;
727     vtkIdType a = 0;
728     for (atit = binfop->AttributeStatus.begin(); atit != binfop->AttributeStatus.end(); ++atit, ++a)
729     {
730       if (*atit)
731       {
732         vtkDataArray* arr = this->GetCacheOrRead(
733           vtkExodusIICacheKey( timeStep, vtkExodusIIReader::ELEM_BLOCK_ATTRIB, obj, a ) );
734         if ( arr )
735         {
736           cd->AddArray( arr );
737         }
738       }
739     }
740   }
741 
742   // Panic if we're given a bad otyp.
743   std::map<int,std::vector<ArrayInfoType> >::iterator ami = this->ArrayInfo.find( otyp );
744   if ( ami == this->ArrayInfo.end() )
745   {
746 #if 0
747     vtkErrorMacro( "Unknown block or set type \"" << otyp << "\" encountered." );
748     for ( ami = this->ArrayInfo.begin(); ami != this->ArrayInfo.end(); ++ ami )
749     {
750       cerr << "   Have type: \"" << ami->first << "\"\n";
751     }
752     return 0;
753 #else
754     return 1;
755 #endif // 0
756   }
757 
758   // For each array defined on objects of the same type as our output,
759   // look for ones that are turned on (Status != 0) and have a truth
760   // table indicating values are present for object obj in the file.
761   std::vector<ArrayInfoType>::iterator ai;
762   int aidx = 0;
763   for ( ai = ami->second.begin(); ai != ami->second.end(); ++ai, ++aidx )
764   {
765     if ( ! ai->Status )
766       continue;
767 
768     if ( ! ai->ObjectTruth[obj] )
769       continue;
770 
771     vtkDataArray* arr = this->GetCacheOrRead( vtkExodusIICacheKey( timeStep, ami->first, obj, aidx ) );
772     if ( arr )
773     {
774       cd->AddArray( arr );
775     }
776   }
777 
778   return 1;
779 }
780 
781 //-----------------------------------------------------------------------------
AssembleOutputProceduralArrays(vtkIdType timeStep,int otyp,int obj,vtkUnstructuredGrid * output)782 int vtkExodusIIReaderPrivate::AssembleOutputProceduralArrays(
783   vtkIdType timeStep, int otyp, int obj,
784   vtkUnstructuredGrid* output )
785 {
786   (void)timeStep;
787   int status = 7;
788   vtkCellData* cd = output->GetCellData();
789   if ( this->GenerateObjectIdArray )
790   {
791     vtkExodusIICacheKey key( -1, vtkExodusIIReader::OBJECT_ID, otyp, obj );
792     vtkDataArray* arr = this->GetCacheOrRead( key );
793     if ( arr )
794     {
795       cd->AddArray( arr );
796       status -= 1;
797     }
798   }
799 
800   if ( this->GenerateGlobalElementIdArray &&
801        ( otyp == vtkExodusIIReader::SIDE_SET_CONN ||
802          otyp == vtkExodusIIReader::SIDE_SET ) )
803   {
804     vtkExodusIICacheKey ckey( -1, vtkExodusIIReader::ELEMENT_ID, 0, 0 );
805     vtkIdTypeArray* src = nullptr;
806 
807     if ( vtkDataArray* elems = this->GetCacheOrRead( ckey ) )
808     {
809       src = vtkIdTypeArray::New ();
810       src->DeepCopy  (elems);
811     }
812 
813     vtkExodusIICacheKey key( -1, vtkExodusIIReader::SIDE_SET_CONN, obj, 1 );
814     if ( vtkDataArray* arr = this->GetCacheOrRead( key ) )
815     {
816 
817       vtkIdTypeArray* idarray = vtkArrayDownCast<vtkIdTypeArray>(arr);
818       vtkIdTypeArray* elementid = vtkIdTypeArray::New();
819       elementid->SetNumberOfTuples(idarray->GetNumberOfTuples());
820       elementid->SetName(vtkExodusIIReader::GetSideSetSourceElementIdArrayName());
821       vtkIntArray* elementside = vtkIntArray::New();
822       elementside->SetNumberOfTuples(idarray->GetNumberOfTuples());
823       elementside->SetName(vtkExodusIIReader::GetSideSetSourceElementSideArrayName());
824       vtkIdType values[2];
825 
826       for(vtkIdType i=0;i<idarray->GetNumberOfTuples();i++)
827       {
828         idarray->GetTypedTuple(i, values);
829         if (src == nullptr || src->GetValue (values[0] - 1) <= 0)
830         {
831           elementid->SetValue(i, values[0] - 1);
832         }
833         else
834         {
835           elementid->SetValue(i, src->GetValue (values[0] - 1) - 1); // find the global element id
836         }
837         // now we have to worry about mapping from exodus canonical side
838         // ordering to vtk canonical side ordering for wedges and hexes.
839         // Even if the element block isn't loaded that we still know what
840         // types of cells it would have contained since all elements
841         // in a block are of the same type.
842         BlockInfoType* type =
843           this->GetBlockFromFileGlobalId(vtkExodusIIReader::ELEM_BLOCK, values[0]);
844         switch(type->CellType)
845         {
846           case VTK_WEDGE:
847           {
848             int wedgeMapping[5] = {2, 3, 4, 0, 1};
849             elementside->SetValue(i, wedgeMapping[ values[1]-1 ] );
850             break;
851           }
852           case VTK_HEXAHEDRON:
853           {
854             int hexMapping[6] = {2, 1, 3, 0, 4, 5};
855             elementside->SetValue(i,  hexMapping[ values[1]-1 ] );
856             break;
857           }
858           default:
859           { // switch to 0-based indexing
860             elementside->SetValue(i, values[1]-1 );
861           }
862         }
863       }
864       cd->AddArray( elementid );
865       cd->AddArray( elementside );
866       elementid->FastDelete();
867       elementside->FastDelete();
868       status -= 2;
869     }
870 
871     if (src != nullptr)
872     {
873       src->Delete ();
874     }
875   }
876 
877   if ( this->GenerateGlobalElementIdArray && ! OBJTYPE_IS_SET( otyp ) )
878   {
879     // This retrieves the first new-style map, or if that is not present,
880     // the solitary old-style map (which always exists but may be
881     // procedurally generated if it is not stored with the file).
882     vtkExodusIICacheKey key( -1, vtkExodusIIReader::GLOBAL_ELEMENT_ID, otyp, obj );
883     vtkDataArray* arr = this->GetCacheOrRead( key );
884     if ( arr )
885     {
886       vtkDataArray* ped = vtkIdTypeArray::New();
887       ped->DeepCopy( arr );
888       ped->SetName( vtkExodusIIReader::GetPedigreeElementIdArrayName() );
889 
890       cd->SetGlobalIds( arr );
891       cd->SetPedigreeIds( ped );
892       ped->FastDelete();
893 
894       status -= 2;
895     }
896   }
897 
898   if ( this->GenerateGlobalNodeIdArray )
899   {
900     // This retrieves the first new-style map, or if that is not present,
901     // the solitary old-style map (which always exists but may be
902     // procedurally generated if it is not stored with the file).
903     vtkExodusIICacheKey key( -1, vtkExodusIIReader::GLOBAL_NODE_ID, otyp, obj );
904     vtkDataArray* arr = this->GetCacheOrRead( key );
905     vtkPointData* pd = output->GetPointData();
906     if ( arr )
907     {
908       vtkDataArray* ped = vtkIdTypeArray::New();
909       ped->DeepCopy( arr );
910       ped->SetName( vtkExodusIIReader::GetPedigreeNodeIdArrayName() );
911 
912       pd->SetGlobalIds( arr );
913       pd->SetPedigreeIds( ped );
914       ped->FastDelete();
915 
916       status -= 4;
917     }
918   }
919 
920   if ( this->GenerateImplicitElementIdArray )
921   {
922     // This retrieves the old style map if it is a parallel data set.  The old
923     // style map stores the global implicit id if parallel.  Otherwise it
924     // generates the implicit id.
925     vtkExodusIICacheKey key( -1, vtkExodusIIReader::IMPLICIT_ELEMENT_ID, otyp, obj );
926     vtkDataArray* arr = this->GetCacheOrRead( key );
927     if ( arr )
928     {
929       cd->AddArray( arr );
930     }
931 
932   }
933 
934   if ( this->GenerateImplicitNodeIdArray )
935   {
936     // This retrieves the old style map if it is a parallel data set.  The old
937     // style map stores the global implicit id if parallel.  Otherwise it
938     // generates the implicit id.
939     vtkExodusIICacheKey key( -1, vtkExodusIIReader::IMPLICIT_NODE_ID, otyp, obj );
940     vtkDataArray* arr = this->GetCacheOrRead( key );
941     vtkPointData* pd = output->GetPointData();
942     if ( arr )
943     {
944       pd->AddArray( arr );
945     }
946   }
947 
948   if ( this->GenerateFileIdArray )
949   { // Don't cache this... it's not worth it.
950     vtkIdType numCells = output->GetNumberOfCells();
951     vtkIntArray* iarr = vtkIntArray::New();
952     iarr->SetNumberOfComponents( 1 );
953     iarr->SetNumberOfTuples( numCells );
954     iarr->SetName( this->GetFileIdArrayName() );
955     cd->AddArray( iarr );
956     iarr->FastDelete();
957     for ( vtkIdType i = 0; i < numCells; ++ i )
958     {
959       iarr->SetValue( i, this->FileId );
960     }
961   }
962 
963   return status;
964 }
965 
966 //-----------------------------------------------------------------------------
AssembleOutputGlobalArrays(vtkIdType timeStep,int otyp,int obj,BlockSetInfoType * bsinfop,vtkUnstructuredGrid * output)967 int vtkExodusIIReaderPrivate::AssembleOutputGlobalArrays(
968   vtkIdType timeStep, int otyp, int obj, BlockSetInfoType* bsinfop,
969   vtkUnstructuredGrid* output )
970 {
971   (void)obj;
972   vtkFieldData *ofieldData = output->GetFieldData();
973 
974   int status = 1;
975   std::vector<ArrayInfoType>::iterator ai;
976   int aidx = 0;
977 
978   for (
979     ai = this->ArrayInfo[ vtkExodusIIReader::GLOBAL ].begin();
980     ai != this->ArrayInfo[ vtkExodusIIReader::GLOBAL ].end();
981     ++ai, ++aidx )
982   {
983     if ( ! ai->Status )
984     {
985       continue;
986     }
987 
988     // Add time-varying global data
989     vtkExodusIICacheKey tdKey( -1, vtkExodusIIReader::GLOBAL_TEMPORAL, -1, aidx );
990     vtkDataArray* temporalData = this->GetCacheOrRead( tdKey );
991     if ( ! temporalData )
992     {
993       vtkDebugMacro( "Unable to read array " << ai->Name.c_str() );
994       status = 0;
995       continue;
996     }
997 
998     ofieldData->AddArray(temporalData);
999   }
1000 
1001   // Add block id information for the exodus writer (if we're an element block)
1002   if ( otyp == vtkExodusIIReader::ELEM_BLOCK )
1003   {
1004     vtkIntArray *elemBlockIdArray = vtkIntArray::New();
1005     elemBlockIdArray->SetNumberOfComponents( 1 );
1006     elemBlockIdArray->SetNumberOfValues( 1 ); // one elem block per unstructured grid
1007     elemBlockIdArray->SetName( "ElementBlockIds" );
1008     elemBlockIdArray->SetValue( 0, bsinfop->Id );
1009     ofieldData->AddArray( elemBlockIdArray );
1010     elemBlockIdArray->Delete();
1011   }
1012 
1013   // Add QA record, title, and INFO record metadata from the Exodus II file
1014   vtkExodusIICacheKey qakey( -1, vtkExodusIIReader::QA_RECORDS, 0, 0 );
1015   vtkDataArray* arr = this->GetCacheOrRead( qakey );
1016   if ( arr )
1017   {
1018     ofieldData->AddArray(arr);
1019   }
1020 
1021   // Add the title
1022   {
1023     vtkStringArray* sarr = vtkStringArray::New();
1024     sarr->SetName( "Title" );
1025     sarr->SetNumberOfComponents( 1 );
1026     sarr->SetNumberOfTuples(1);
1027     sarr->SetValue(0, this->ModelParameters.title);
1028     ofieldData->AddArray(sarr);
1029     sarr->Delete();
1030   }
1031 
1032   // Add mode_shape/time_step
1033   if (this->HasModeShapes)
1034   {
1035     vtkNew<vtkIntArray> dataIndexArray;
1036     dataIndexArray->SetName("mode_shape");
1037     dataIndexArray->SetNumberOfComponents(1);
1038     dataIndexArray->SetNumberOfTuples(1);
1039     // mode-shape == (timestep + 1). See vtkExodusIIReader::SetModeShape().
1040     dataIndexArray->SetValue(0, (timeStep + 1));
1041     ofieldData->AddArray(dataIndexArray);
1042 
1043     vtkNew<vtkIntArray> modeShapeRange;
1044     modeShapeRange->SetName("mode_shape_range");
1045     modeShapeRange->SetNumberOfComponents(2);
1046     modeShapeRange->SetNumberOfTuples(1);
1047     modeShapeRange->SetValue(0, this->Parent->GetModeShapesRange()[0]);
1048     modeShapeRange->SetValue(1, this->Parent->GetModeShapesRange()[1]);
1049     ofieldData->AddArray(modeShapeRange);
1050   }
1051 
1052   vtkExodusIICacheKey infokey( -1, vtkExodusIIReader::INFO_RECORDS, 0, 0 );
1053   arr = this->GetCacheOrRead( infokey );
1054   if ( arr )
1055   {
1056     ofieldData->AddArray(arr);
1057   }
1058 
1059   return status;
1060 }
1061 
1062 //-----------------------------------------------------------------------------
AssembleOutputPointMaps(vtkIdType timeStep,BlockSetInfoType * bsinfop,vtkUnstructuredGrid * output)1063 int vtkExodusIIReaderPrivate::AssembleOutputPointMaps( vtkIdType timeStep,
1064   BlockSetInfoType* bsinfop, vtkUnstructuredGrid* output )
1065 {
1066   (void)timeStep;
1067   int status = 1;
1068   std::vector<MapInfoType>::iterator mi;
1069   int midx = 0;
1070 
1071   for (
1072     mi = this->MapInfo[ vtkExodusIIReader::NODE_MAP ].begin();
1073     mi != this->MapInfo[ vtkExodusIIReader::NODE_MAP ].end();
1074     ++mi, ++midx )
1075   {
1076     if ( ! mi->Status )
1077       continue; // Skip arrays we don't want.
1078 
1079     vtkIdTypeArray* src = vtkArrayDownCast<vtkIdTypeArray>( this->GetCacheOrRead(
1080         vtkExodusIICacheKey( -1, vtkExodusIIReader::NODE_MAP, 0, midx ) ) );
1081     if ( !src )
1082     {
1083       vtkDebugMacro(
1084         "Unable to read point map array \""
1085         << mi->Name.c_str() << "\" (" << midx << ")" );
1086       status = 0;
1087       continue;
1088     }
1089 
1090     this->AddPointArray( src, bsinfop, output );
1091   }
1092   return status;
1093 }
1094 
1095 //-----------------------------------------------------------------------------
AssembleOutputCellMaps(vtkIdType vtkNotUsed (timeStep),int otyp,int obj,BlockSetInfoType * bsinfop,vtkUnstructuredGrid * output)1096 int vtkExodusIIReaderPrivate::AssembleOutputCellMaps(
1097   vtkIdType vtkNotUsed(timeStep), int otyp, int obj, BlockSetInfoType* bsinfop,
1098   vtkUnstructuredGrid* output )
1099 {
1100   (void)obj;
1101   // Don't create arrays for deselected objects
1102   if ( ! output || ! bsinfop->Status )
1103   {
1104     return 1;
1105   }
1106 
1107   // Ignore invalid otyp values (sets cannot have maps, only blocks).
1108   int mtyp = this->GetMapTypeFromObjectType( otyp );
1109   std::map<int,std::vector<MapInfoType> >::iterator mmi =
1110     this->MapInfo.find( mtyp );
1111   if ( mmi == this->MapInfo.end() )
1112   {
1113     return 1;
1114   }
1115 
1116   vtkCellData* cd = output->GetCellData();
1117   // For each map defined on objects of the same type as our output,
1118   // look for ones that are turned on (Status != 0).
1119   std::vector<MapInfoType>::iterator mi;
1120   int midx = 0;
1121   for ( mi = mmi->second.begin(); mi != mmi->second.end(); ++mi, ++midx )
1122   {
1123     if ( ! mi->Status )
1124       continue;
1125 
1126     vtkDataArray* src = this->GetCacheOrRead(
1127       vtkExodusIICacheKey( -1, mmi->first, 0, midx ) );
1128     if ( ! src )
1129       continue;
1130 
1131     if ( otyp == vtkExodusIIReader::ELEM_BLOCK )
1132     {
1133       if (
1134         bsinfop->Size == src->GetNumberOfTuples() &&
1135         bsinfop->FileOffset == 1 &&
1136         this->BlockInfo[otyp].size() == 1 )
1137       {
1138         cd->AddArray( src );
1139       }
1140       else
1141       {
1142         // Create the array and copy the applicable subset from the map
1143         vtkIdTypeArray* arr = vtkIdTypeArray::New();
1144         arr->SetName( mi->Name.c_str() );
1145         arr->SetNumberOfComponents( 1 );
1146         arr->SetNumberOfTuples( bsinfop->Size );
1147         memcpy( arr->GetVoidPointer(0), src->GetVoidPointer( bsinfop->FileOffset - 1 ),
1148           bsinfop->Size * sizeof(vtkIdType) );
1149         cd->AddArray( arr );
1150         arr->FastDelete();
1151       }
1152     }
1153     else
1154     {
1155       // FIXME: We have a set (no maps are defined on sets but we could determine
1156       //        map values given the set generators) or an edge/face block (unclear
1157       //        whether maps are useful/possible on these block types).
1158     }
1159   }
1160   return 1;
1161 }
1162 
1163 //-----------------------------------------------------------------------------
GetPolyhedronFaceConnectivity(vtkIdType fileLocalFaceId,vtkIdType * & facePtIds)1164 vtkIdType vtkExodusIIReaderPrivate::GetPolyhedronFaceConnectivity(
1165   vtkIdType fileLocalFaceId,
1166   vtkIdType*& facePtIds)
1167 {
1168   // I. Find the face block containing \a fileLocalFaceId.
1169   //    An element may refer to faces anywhere in the file, not just in
1170   //    a corresponding face block, so each face of an element may be
1171   //    in a different face block.
1172   if (this->BlockInfo.find(EX_FACE_BLOCK) == this->BlockInfo.end())
1173   {
1174     vtkWarningMacro("No face blocks in exodus file, but polyhedral cell requires at least 1");
1175     return -1;
1176   }
1177   std::vector<BlockInfoType>& faceBlocks(this->BlockInfo[EX_FACE_BLOCK]);
1178   std::vector<BlockInfoType>::const_iterator fbit;
1179   int fbidx = 0;
1180   vtkIdType blockLocalFaceId = -1;
1181   for (
1182     fbit = faceBlocks.begin();
1183     fbit != faceBlocks.end() && (blockLocalFaceId = fileLocalFaceId + 1 - fbit->FileOffset) > fbit->Size;
1184     ++fbit)
1185   {
1186     ++fbidx;
1187     //std::cout << "Skipping block " << fbit->Id << " (" << fbit->Name << ") offset " << fbit->FileOffset << "\n";
1188   }
1189   if (fbit == faceBlocks.end() || blockLocalFaceId < 0)
1190   {
1191     vtkWarningMacro(
1192       "Could not find a face block containing face " << fileLocalFaceId <<
1193       " (block-relative " << blockLocalFaceId << ").");
1194     return -1;
1195   }
1196   std::map<int, std::vector< std::vector< vtkIdType > > >::iterator fcit =
1197     this->PolyhedralFaceConnArrays.find(fbidx);
1198   if (fcit == this->PolyhedralFaceConnArrays.end())
1199   {
1200     // Add faces for the entire face-block to the cache (because
1201     // the connectivity is run-length encoded). Hopefully each
1202     // polyhedral element block will use many faces from each
1203     // face block so the cost is amortized.
1204     vtkSmartPointer<vtkIdTypeArray> fconn =
1205       vtkArrayDownCast<vtkIdTypeArray>(
1206         this->GetCacheOrRead(
1207           vtkExodusIICacheKey(
1208             -1, vtkExodusIIReader::FACE_BLOCK_CONN, fbidx, 0 )));
1209     if (!fconn)
1210     {
1211       vtkWarningMacro(
1212         "Face block " << fbidx
1213         << " (id " << fbit->Id << ") missing its connectivity array.");
1214       return -1;
1215     }
1216     vtkSmartPointer<vtkIntArray> ptsPerFace =
1217       vtkArrayDownCast<vtkIntArray>(
1218         this->GetCacheOrRead(
1219           vtkExodusIICacheKey(
1220             -1, vtkExodusIIReader::ENTITY_COUNTS, fbidx,
1221             /* get counts for face-block as opposed to element-block: */ 1)));
1222     if (!ptsPerFace)
1223     {
1224       vtkWarningMacro(
1225         "Face block " << fbidx
1226         << " (id " << fbit->Id << ") missing its points-per-face array.");
1227       return -1;
1228     }
1229     // Decompose the whole face block into a ragged
1230     // array (vector of vectors) to future lookups
1231     // are fast:
1232     static std::vector<std::vector<vtkIdType> > blank;
1233     this->PolyhedralFaceConnArrays[fbidx] = blank;
1234     fcit = this->PolyhedralFaceConnArrays.find(fbidx);
1235     vtkIdType numFaces = ptsPerFace->GetNumberOfTuples();
1236     fcit->second.resize(numFaces);
1237     vtkIdType cc = 0;
1238     for (vtkIdType ii = 0; ii < numFaces; ++ii)
1239     {
1240       int numPts = ptsPerFace->GetValue(ii);
1241       std::vector<vtkIdType>& facePts(fcit->second[ii]);
1242       facePts.resize(numPts);
1243       for (int jj = 0; jj < numPts; ++jj)
1244       {
1245         facePts[jj] = fconn->GetValue(cc++);
1246       }
1247     }
1248   }
1249   // II. Now that we have a cache for the face block, look up the
1250   //     one face in the block we currently need:
1251   vtkIdType numPoints =
1252     static_cast<vtkIdType>(fcit->second[blockLocalFaceId].size());
1253   facePtIds = &fcit->second[blockLocalFaceId][0];
1254   return numPoints;
1255 }
1256 
1257 //-----------------------------------------------------------------------------
FreePolyhedronFaceArrays()1258 void vtkExodusIIReaderPrivate::FreePolyhedronFaceArrays()
1259 {
1260   this->PolyhedralFaceConnArrays.clear();
1261 }
1262 
1263 //-----------------------------------------------------------------------------
InsertBlockPolyhedra(BlockInfoType * binfo,vtkIntArray * facesPerCell,vtkIdTypeArray * exoCellConn)1264 void vtkExodusIIReaderPrivate::InsertBlockPolyhedra(
1265   BlockInfoType* binfo,
1266   vtkIntArray* facesPerCell,
1267   vtkIdTypeArray* exoCellConn)
1268 {
1269   vtkIdType numCells = facesPerCell->GetMaxId() + 1;
1270 
1271   // The Exodus file format is more compact than VTK's; it
1272   // allows multiple elements(cells) to refer to the same face so
1273   // that no face->point connectivity needs to be repeated.
1274   // VTK's polyhedral cells unpacks each element's faces
1275   // into a contiguous list for fast access to each element's
1276   // face->point connectivity.
1277   // So, we cannot use the arrays we are given as-is.
1278   // Also, VTK requires a list, without duplicates, of all the
1279   // points per cell (across all its faces), which Exodus does
1280   // not provide.
1281 
1282   // II. Insert cells using face-point connectivity.
1283   vtkIdType curCell = 0;
1284   vtkIdType curCellCurFace = 0;
1285   std::vector<vtkIdType> vtkCellPts;
1286   for (vtkIdType i = 0; i < numCells; ++i)
1287   {
1288     vtkCellPts.clear();
1289     int numFacesThisCell = facesPerCell->GetValue(curCell++);
1290     for (vtkIdType j = 0; j < numFacesThisCell; ++j)
1291     {
1292       vtkIdType curFace = exoCellConn->GetValue(curCellCurFace++);
1293       //std::vector<vtkIdType>& curFacePts(facePointLists[curFace]);
1294       vtkIdType* facePtsRaw;
1295       vtkIdType numFacePts = this->GetPolyhedronFaceConnectivity(curFace, facePtsRaw);
1296       // Copy face connectivity, optionally (and usually) mapping to squeezed-points for the block
1297       vtkCellPts.push_back(numFacePts);
1298       for (vtkIdType pp = 0; pp < numFacePts; ++pp)
1299       {
1300         vtkCellPts.push_back(this->SqueezePoints ?
1301           this->GetSqueezePointId(binfo, facePtsRaw[pp]) :
1302           facePtsRaw[pp]);
1303       }
1304     }
1305     binfo->CachedConnectivity->InsertNextCell(
1306       VTK_POLYHEDRON, numFacesThisCell, &vtkCellPts[0]);
1307   }
1308   this->FreePolyhedronFaceArrays();
1309 }
1310 
1311 //-----------------------------------------------------------------------------
InsertBlockCells(int otyp,int obj,int conn_type,int timeStep,BlockInfoType * binfo)1312 void vtkExodusIIReaderPrivate::InsertBlockCells(
1313   int otyp, int obj, int conn_type, int timeStep, BlockInfoType* binfo )
1314 {
1315   (void)timeStep;
1316   (void)otyp;
1317   if ( binfo->Size == 0 )
1318   {
1319     // No entries in this block.
1320     // This happens in parallel filesets when all
1321     // elements are distributed to other files.
1322     // Silently ignore.
1323     return;
1324   }
1325 
1326   vtkIntArray* ent = nullptr;
1327   if ( binfo->PointsPerCell == 0 )
1328   {
1329     int arrId = (conn_type == vtkExodusIIReader::ELEM_BLOCK_ELEM_CONN ? 0 : 1);
1330     ent = vtkArrayDownCast<vtkIntArray>(
1331       this->GetCacheOrRead(
1332         vtkExodusIICacheKey( -1, vtkExodusIIReader::ENTITY_COUNTS, obj, arrId
1333           )));
1334     if ( ! ent )
1335     {
1336       vtkErrorMacro(
1337         "Entity used 0 points per cell, "
1338         "but didn't return polyhedra correctly" );
1339       binfo->Status = 0;
1340       return;
1341     }
1342     ent->Register(this);
1343   }
1344 
1345   // Handle 3-D polyhedra (not 2-D polygons) separately
1346   // from other cell types for simplicity.
1347   // In addition to the element block connectivity (which
1348   // lists faces bounding the polyhedra, we must load face
1349   // block connectivity (which lists corner nodes for each
1350   // face).
1351   if (binfo->CellType == VTK_POLYHEDRON)
1352   {
1353     vtkIdTypeArray* efconn = vtkArrayDownCast<vtkIdTypeArray>(
1354       this->GetCacheOrRead(
1355         vtkExodusIICacheKey( -1, vtkExodusIIReader::ELEM_BLOCK_FACE_CONN, obj, 0 )));
1356     if (efconn)
1357       efconn->Register(this);
1358     if (!efconn || !ent)
1359     {
1360       vtkWarningMacro(
1361         << "Element block (" << efconn << ") and "
1362         << "number of faces per poly (" << ent << ") arrays are both required. "
1363         << "Skipping block id " << binfo->Id << "; expect trouble." );
1364       binfo->Status = 0;
1365       if (ent) ent->UnRegister(this);
1366       if (efconn) efconn->UnRegister(this);
1367       return;
1368     }
1369     this->InsertBlockPolyhedra(binfo, ent, efconn);
1370     efconn->UnRegister(this);
1371     ent->UnRegister(this);
1372     return;
1373   }
1374 
1375   vtkIdTypeArray* arr = vtkArrayDownCast<vtkIdTypeArray>(
1376     this->GetCacheOrRead(
1377       vtkExodusIICacheKey( -1, conn_type, obj, 0 )));
1378   if ( ! arr )
1379   {
1380     vtkWarningMacro(
1381       "Block wasn't present in file? Working around it. Expect trouble." );
1382     binfo->Status = 0;
1383     if (ent)
1384     {
1385       ent->UnRegister(this);
1386     }
1387     return;
1388   }
1389 
1390   if (this->SqueezePoints)
1391   {
1392     std::vector<vtkIdType> cellIds;
1393     cellIds.resize( binfo->PointsPerCell );
1394     auto srcIds = arr->GetPointer( 0 );
1395 
1396     for ( int i = 0; i < binfo->Size; ++i )
1397     {
1398       int entitiesPerCell;
1399       if (ent)
1400       {
1401         entitiesPerCell = ent->GetValue (i);
1402         cellIds.resize( entitiesPerCell );
1403       }
1404       else
1405       {
1406         entitiesPerCell = binfo->PointsPerCell;
1407       }
1408 
1409       for ( int p = 0; p < entitiesPerCell; ++p )
1410       {
1411         cellIds[p] = this->GetSqueezePointId( binfo, srcIds[p] );
1412         //cout << " " << srcIds[p] << "(" << cellIds[p] << ")";
1413       }
1414       //cout << "\n";
1415       //cout << " " <<
1416       binfo->CachedConnectivity->InsertNextCell( binfo->CellType, entitiesPerCell, &cellIds[0] );
1417       srcIds += entitiesPerCell;
1418     }
1419       //cout << "\n";
1420   }
1421   else
1422   {
1423     // The id type size used by exodus should match VTK_USE_64BIT_IDS length
1424     vtkIdType* srcIds = (vtkIdType*) arr->GetPointer( 0 );
1425 
1426     for ( int i = 0; i < binfo->Size; ++i )
1427     {
1428       int entitiesPerCell = binfo->PointsPerCell;
1429       if ( ent != nullptr)
1430       {
1431         entitiesPerCell = ent->GetValue (i);
1432       }
1433       binfo->CachedConnectivity->InsertNextCell( binfo->CellType, entitiesPerCell, srcIds );
1434       srcIds += entitiesPerCell;
1435       //for ( int k = 0; k < binfo->PointsPerCell; ++k )
1436         //cout << " " << srcIds[k];
1437       //cout << "\n";
1438     }
1439   }
1440   if (ent)
1441   {
1442     ent->UnRegister (this);
1443   }
1444 }
1445 
1446 //-----------------------------------------------------------------------------
InsertSetCells(int otyp,int obj,int conn_type,int timeStep,SetInfoType * sinfo)1447 void vtkExodusIIReaderPrivate::InsertSetCells(
1448   int otyp, int obj, int conn_type, int timeStep,
1449   SetInfoType* sinfo )
1450 {
1451   (void)timeStep;
1452   if ( sinfo->Size == 0 )
1453   {
1454     // No entries in this set.
1455     // This happens in parallel filesets when all elements are distributed to other files.
1456     // Silently ignore.
1457     return;
1458   }
1459 
1460   auto* arr = vtkArrayDownCast<vtkIdTypeArray>(
1461     this->GetCacheOrRead( vtkExodusIICacheKey( -1, conn_type, obj, 0 ) ) );
1462   if ( ! arr )
1463   {
1464     vtkWarningMacro( "Set wasn't present in file? Working around it. Expect trouble." );
1465     sinfo->Status = 0;
1466     return;
1467   }
1468 
1469   switch ( otyp )
1470   {
1471   case vtkExodusIIReader::NODE_SET:
1472     // Easy
1473     this->InsertSetNodeCopies( arr, otyp, obj, sinfo );
1474     break;
1475   case vtkExodusIIReader::EDGE_SET:
1476     // Not so fun. We must copy cells from possibly many edge blocks.
1477     this->InsertSetCellCopies( arr, vtkExodusIIReader::EDGE_BLOCK, obj, sinfo );
1478     break;
1479   case vtkExodusIIReader::FACE_SET:
1480     // Not so fun. We must copy cells from possibly many face blocks.
1481     this->InsertSetCellCopies( arr, vtkExodusIIReader::FACE_BLOCK, obj, sinfo );
1482     break;
1483   case vtkExodusIIReader::SIDE_SET:
1484     // Way hard even when we let Exodus do a lot for us.
1485     this->InsertSetSides( arr, otyp, obj, sinfo );
1486     break;
1487   case vtkExodusIIReader::ELEM_SET:
1488     // Not so fun. We must copy cells from possibly many element blocks.
1489     this->InsertSetCellCopies( arr, vtkExodusIIReader::ELEM_BLOCK, obj, sinfo );
1490     break;
1491   }
1492 }
1493 
1494 //-----------------------------------------------------------------------------
AddPointArray(vtkDataArray * src,BlockSetInfoType * bsinfop,vtkUnstructuredGrid * output)1495 void vtkExodusIIReaderPrivate::AddPointArray(
1496   vtkDataArray* src, BlockSetInfoType* bsinfop, vtkUnstructuredGrid* output )
1497 {
1498   vtkPointData* pd = output->GetPointData();
1499   if ( this->SqueezePoints )
1500   {
1501     // subset the array using PointMap
1502     vtkDataArray* dest = vtkDataArray::CreateDataArray( src->GetDataType() );
1503     dest->SetName( src->GetName() );
1504     dest->SetNumberOfComponents( src->GetNumberOfComponents() );
1505     dest->SetNumberOfTuples( bsinfop->NextSqueezePoint );
1506     std::map<vtkIdType,vtkIdType>::iterator it, itEnd;
1507     //
1508     // I moved the end condition of the loop out of the for(;;) loop.
1509     //   Assuming it doesn't change within the loop itself!
1510     //   The reason is that the code was making the call every loop.
1511     //
1512     itEnd = bsinfop->PointMap.end();
1513     for ( it = bsinfop->PointMap.begin(); it != itEnd; ++ it )
1514     {
1515       pd->CopyTuple( src, dest, it->first, it->second );
1516     }
1517     pd->AddArray( dest );
1518     dest->FastDelete();
1519   }
1520   else
1521   {
1522     pd->AddArray( src );
1523   }
1524 }
1525 
1526 //-----------------------------------------------------------------------------
InsertSetNodeCopies(vtkIdTypeArray * refs,int otyp,int obj,SetInfoType * sinfo)1527 void vtkExodusIIReaderPrivate::InsertSetNodeCopies( vtkIdTypeArray* refs, int otyp, int obj, SetInfoType* sinfo )
1528 {
1529   (void)otyp;
1530   (void)obj;
1531   // Insert a "VERTEX" cell for each node in the set.
1532   vtkIdType ref;
1533   vtkIdType tmp;
1534   auto* iptr = refs->GetPointer( 0 );
1535 
1536   if ( this->SqueezePoints )
1537   { // this loop is separated out to handle case (stride > 1 && pref[1] < 0 && this->SqueezePoints)
1538     for ( ref = 0; ref < refs->GetNumberOfTuples(); ++ref, ++iptr )
1539     {
1540       tmp = *iptr;
1541       vtkIdType x = this->GetSqueezePointId( sinfo, tmp );
1542       sinfo->CachedConnectivity->InsertNextCell( VTK_VERTEX, 1, &x );
1543     }
1544   }
1545   else
1546   {
1547     for ( ref = 0; ref < refs->GetNumberOfTuples(); ++ref, ++iptr )
1548     {
1549       tmp = *iptr;
1550       sinfo->CachedConnectivity->InsertNextCell( VTK_VERTEX, 1, &tmp );
1551     }
1552   }
1553 }
1554 
1555 //-----------------------------------------------------------------------------
InsertSetCellCopies(vtkIdTypeArray * refs,int otyp,int obj,SetInfoType * sinfo)1556 void vtkExodusIIReaderPrivate::InsertSetCellCopies(
1557   vtkIdTypeArray* refs, int otyp, int obj, SetInfoType* sinfo )
1558 {
1559   (void)obj;
1560   // First, sort the set by entry number (element, face, or edge ID)
1561   // so that we can refer to each block just once as we process cells.
1562   vtkSortDataArray::SortArrayByComponent( refs, 0 );
1563   refs->Register( this ); // Don't let the cache delete this array when we fetch others...
1564 
1565   vtkIdType nrefs = refs->GetNumberOfTuples();
1566   vtkIdType ref = 0;
1567   vtkIdType bnum = -1;
1568   vtkIdType lastBlockEntry = -1;
1569   auto* pref = refs->GetPointer( 0 );
1570   int stride = refs->GetNumberOfComponents();
1571   BlockInfoType* binfop = nullptr; //&this->BlockInfo[otyp][bnum];
1572   int* nodeconn = nullptr;
1573   vtkIdType* cellConn;
1574   int nnpe = 0;
1575   vtkIntArray* nconn;
1576   std::vector<vtkIdType> tmpTuple;
1577   while ( ref < nrefs )
1578   {
1579     int loadNewBlk = 0;
1580     while ( pref[0] >= lastBlockEntry )
1581     { // advance to the next block (always true first time through parent loop)
1582       ++bnum;
1583       if ( bnum >= (int) this->BlockInfo[otyp].size() )
1584         return;
1585       binfop = &this->BlockInfo[otyp][bnum];
1586       lastBlockEntry = binfop->FileOffset + binfop->Size - 1;
1587       loadNewBlk = 1;
1588     }
1589     if ( loadNewBlk )
1590     {
1591       nconn = vtkArrayDownCast<vtkIntArray>(
1592         this->GetCacheOrRead( vtkExodusIICacheKey( -1, this->GetBlockConnTypeFromBlockType( otyp ), bnum, 0 ) )
1593         );
1594       if ( ! nconn )
1595       {
1596         vtkErrorMacro( "Unable to read block \"" << binfop->Name.c_str() << "\" (" << binfop->Id << ")" );
1597         break;
1598       }
1599       nodeconn = nconn->GetPointer( 0 );
1600       nnpe = nconn->GetNumberOfComponents();
1601       if ( stride > 1 || this->SqueezePoints )
1602       {
1603         tmpTuple.resize( nnpe );
1604       }
1605     }
1606 
1607     if ( stride > 1 && pref[1] < 0 )
1608     { // negative orientation => reverse cell connectivity
1609       vtkIdType off = (pref[0] + 2 - binfop->FileOffset) * nnpe - 1;
1610       for ( int k = 0; k < nnpe; ++k )
1611         tmpTuple[k] = nodeconn[off-k];
1612       cellConn = &tmpTuple[0];
1613     }
1614     else
1615 #ifndef VTK_USE_64BIT_IDS
1616       if ( this->SqueezePoints )
1617 #endif // VTK_USE_64BIT_IDS
1618       {
1619       vtkIdType off = (pref[0] + 1 - binfop->FileOffset) * nnpe;
1620       for ( int k = 0; k < nnpe; ++k )
1621         tmpTuple[k] = nodeconn[off+k];
1622       cellConn = &tmpTuple[0];
1623       }
1624 #ifndef VTK_USE_64BIT_IDS
1625     else
1626     {
1627       cellConn = (int*)nodeconn + (pref[0] + 1 - binfop->FileOffset) * nnpe;
1628     }
1629 #endif // VTK_USE_64BIT_IDS
1630 
1631     if ( this->SqueezePoints )
1632     { // this loop is separated out to handle case (stride > 1 && pref[1] < 0 && this->SqueezePoints)
1633       for ( int k = 0; k < nnpe; ++k )
1634       { // FIXME: Double-check that cellConn[k] should be in-place re-assigned.
1635         cellConn[k] = this->GetSqueezePointId( sinfo, cellConn[k] );
1636       }
1637     }
1638 
1639     sinfo->CachedConnectivity->InsertNextCell( binfop->CellType, nnpe, cellConn );
1640 
1641     pref += stride;
1642     ++ref;
1643   }
1644 
1645   refs->UnRegister( this );
1646 }
1647 
1648 //-----------------------------------------------------------------------------
InsertSetSides(vtkIdTypeArray * refs,int otyp,int obj,SetInfoType * sinfo)1649 void vtkExodusIIReaderPrivate::InsertSetSides(
1650   vtkIdTypeArray* refs, int otyp, int obj, SetInfoType* sinfo )
1651 {
1652   static const int sideCellTypes[] =
1653     {
1654     VTK_EMPTY_CELL, // don't support any cells with 0 nodes per side
1655     VTK_VERTEX,
1656     VTK_LINE,
1657     VTK_TRIANGLE,
1658     VTK_QUAD,
1659     VTK_EMPTY_CELL, // don't support any cells with 5 nodes per side
1660     VTK_QUADRATIC_TRIANGLE,
1661     VTK_EMPTY_CELL, // don't support any cells with 7 nodes per side
1662     VTK_QUADRATIC_QUAD,
1663     VTK_BIQUADRATIC_QUAD
1664     };
1665 
1666   int numSides = this->SetInfo[otyp][obj].Size;
1667   auto* nodesPerSide = refs->GetPointer( 0 );
1668   auto* sideNodes = nodesPerSide + numSides;
1669   std::vector<vtkIdType> cellConn;
1670   cellConn.resize( 9 );
1671 
1672   if ( this->SqueezePoints )
1673   {
1674     int nnpe;
1675     for ( int side = 0; side < numSides; ++side )
1676     {
1677       nnpe = nodesPerSide[side];
1678       for ( int k = 0; k < nnpe; ++k )
1679       {
1680         cellConn[k] = this->GetSqueezePointId( sinfo, sideNodes[k] );
1681       }
1682       sinfo->CachedConnectivity->InsertNextCell( sideCellTypes[nnpe], nnpe, &cellConn[0] );
1683       sideNodes += nnpe;
1684     }
1685   }
1686   else
1687   {
1688     int nnpe;
1689     for ( int side = 0; side < numSides; ++side )
1690     {
1691       nnpe = nodesPerSide[side];
1692 #ifdef VTK_USE_64BIT_IDS
1693       for ( int k = 0; k < nnpe; ++k )
1694       {
1695         cellConn[k] = sideNodes[k];
1696       }
1697       sinfo->CachedConnectivity->InsertNextCell( sideCellTypes[nnpe], nnpe, &cellConn[0] );
1698 #else // VTK_USE_64BIT_IDS
1699       sinfo->CachedConnectivity->InsertNextCell( sideCellTypes[nnpe], nnpe, sideNodes );
1700 #endif // VTK_USE_64BIT_IDS
1701       sideNodes += nnpe;
1702     }
1703   }
1704 }
1705 
1706 //-----------------------------------------------------------------------------
GetCacheOrRead(vtkExodusIICacheKey key)1707 vtkDataArray* vtkExodusIIReaderPrivate::GetCacheOrRead( vtkExodusIICacheKey key )
1708 {
1709   vtkDataArray* arr;
1710   // Never cache points deflected for a mode shape animation... doubles don't make good keys.
1711   if ( this->HasModeShapes && key.ObjectType == vtkExodusIIReader::NODAL_COORDS )
1712   {
1713     arr = nullptr;
1714   }
1715   else
1716   {
1717     arr = this->Cache->Find( key );
1718   }
1719 
1720   if ( arr )
1721   {
1722     //
1723     return arr;
1724   }
1725 
1726   int exoid = this->Exoid;
1727   int maxNameLength = this->Parent->GetMaxNameLength();
1728 
1729   // If array is nullptr, try reading it from file.
1730   if ( key.ObjectType == vtkExodusIIReader::GLOBAL )
1731   {
1732     // need to assemble result array from smaller ones.
1733     // call GetCacheOrRead() for each smaller array
1734     // pay attention to SqueezePoints
1735 
1736     //ArrayInfoType* ainfop = &this->ArrayInfo[vtkExodusIIReader::GLOBAL][key.ArrayId];
1737     arr = vtkDataArray::CreateDataArray( VTK_DOUBLE );
1738     arr->SetName( this->GetGlobalVariableValuesArrayName() );
1739     arr->SetNumberOfComponents( 1 );
1740     arr->SetNumberOfTuples(
1741       static_cast<vtkIdType>(
1742         this->ArrayInfo[ vtkExodusIIReader::GLOBAL ].size()));
1743 
1744     if ( ex_get_glob_vars( exoid, key.Time + 1, arr->GetNumberOfTuples(),
1745         arr->GetVoidPointer( 0 ) ) < 0 )
1746     {
1747       vtkErrorMacro( "Could not read global variable " << this->GetGlobalVariableValuesArrayName() << "." );
1748       arr->Delete();
1749       arr = nullptr;
1750     }
1751   }
1752   else if ( key.ObjectType == vtkExodusIIReader::NODAL )
1753   {
1754     // read nodal array
1755     ArrayInfoType* ainfop = &this->ArrayInfo[vtkExodusIIReader::NODAL][key.ArrayId];
1756     int ncomps = ( this->ModelParameters.num_dim == 2 && ainfop->Components == 2 ) ? 3 : ainfop->Components;
1757     arr = vtkDataArray::CreateDataArray( ainfop->StorageType );
1758     arr->SetName( ainfop->Name.c_str() );
1759     arr->SetNumberOfComponents( ncomps );
1760     arr->SetNumberOfTuples( this->ModelParameters.num_nodes );
1761     if ( ncomps != ainfop->Components )
1762     {
1763       arr->FillComponent( 2, 0. );
1764     }
1765     if ( ncomps == 1 )
1766     {
1767       if ( ex_get_var( exoid, key.Time + 1, static_cast<ex_entity_type>( key.ObjectType ),
1768           ainfop->OriginalIndices[0], 0, arr->GetNumberOfTuples(),
1769           arr->GetVoidPointer( 0 ) ) < 0 )
1770       {
1771         vtkErrorMacro( "Could not read nodal result variable " << ainfop->Name.c_str() << "." );
1772         arr->Delete();
1773         arr = nullptr;
1774       }
1775     }
1776     else
1777     {
1778       // Exodus doesn't support reading with a stride, so we have to manually interleave the arrays. Bleh.
1779       std::vector<std::vector<double> > tmpVal;
1780       tmpVal.resize( ainfop->Components );
1781       int c;
1782       for ( c = 0; c < ainfop->Components; ++c )
1783       {
1784         vtkIdType N = this->ModelParameters.num_nodes;
1785         tmpVal[c].resize( N );
1786         if ( ex_get_var( exoid, key.Time + 1, static_cast<ex_entity_type>( key.ObjectType ),
1787             ainfop->OriginalIndices[c], 0, arr->GetNumberOfTuples(),
1788             &tmpVal[c][0] ) < 0)
1789         {
1790           vtkErrorMacro( "Could not read nodal result variable " << ainfop->OriginalNames[c].c_str() << "." );
1791           arr->Delete();
1792           arr = nullptr;
1793           return nullptr;
1794         }
1795       }
1796       int t;
1797       std::vector<double> tmpTuple;
1798       tmpTuple.resize( ncomps );
1799       tmpTuple[ncomps - 1] = 0.; // In case we're embedding a 2-D vector in 3-D
1800 
1801       //
1802       // Lets unroll the most common case - components == 3.
1803       //
1804       if ( ainfop->Components == 3)
1805       {
1806         int maxTuples =  arr->GetNumberOfTuples();
1807         for ( t = 0; t < maxTuples; ++t )
1808         {
1809           tmpTuple[0] = tmpVal[0][t];
1810           tmpTuple[1] = tmpVal[1][t];
1811           tmpTuple[2] = tmpVal[2][t];
1812           arr->SetTuple( t, &tmpTuple[0] );
1813         }
1814       }
1815       else
1816       {
1817         for ( t = 0; t < arr->GetNumberOfTuples(); ++t )
1818         {
1819           for ( c = 0; c < ainfop->Components; ++c )
1820           {
1821             tmpTuple[c] = tmpVal[c][t];
1822           }
1823           arr->SetTuple( t, &tmpTuple[0] );
1824         }
1825       }
1826     }
1827   }
1828   else if ( key.ObjectType == vtkExodusIIReader::GLOBAL_TEMPORAL )
1829   {
1830     // read temporal nodal array
1831     ArrayInfoType* ainfop = &this->ArrayInfo[vtkExodusIIReader::GLOBAL][key.ArrayId];
1832     arr = vtkDataArray::CreateDataArray( ainfop->StorageType );
1833     //vtkStdString newArrayName = ainfop->Name + "OverTime";
1834     arr->SetName( ainfop->Name );
1835     arr->SetNumberOfComponents( ainfop->Components );
1836     arr->SetNumberOfTuples( this->GetNumberOfTimeSteps() );
1837     if ( ainfop->Components != 1 )
1838     {
1839       // Exodus doesn't support reading with a stride, so we have to manually interleave the arrays. Bleh.
1840       std::vector<std::vector<double> > tmpVal;
1841       tmpVal.resize( ainfop->Components );
1842       int c;
1843       for ( c = 0; c < ainfop->Components; ++c )
1844       {
1845         vtkIdType N = this->GetNumberOfTimeSteps();
1846         tmpVal[c].resize( N );
1847         if ( ex_get_var_time( exoid, EX_GLOBAL,
1848             ainfop->OriginalIndices[c], key.ObjectId,
1849             1, this->GetNumberOfTimeSteps(), &tmpVal[c][0] ) < 0 )
1850         {
1851           vtkErrorMacro(
1852             "Could not read temporal global result variable "
1853             << ainfop->OriginalNames[c].c_str() << "." );
1854           arr->Delete();
1855           arr = nullptr;
1856           return nullptr;
1857         }
1858       }
1859       int t;
1860       std::vector<double> tmpTuple;
1861       tmpTuple.resize( ainfop->Components );
1862       for ( t = 0; t < arr->GetNumberOfTuples(); ++t )
1863       {
1864         for ( c = 0; c < ainfop->Components; ++c )
1865         {
1866           tmpTuple[c] = tmpVal[c][t];
1867         }
1868         arr->SetTuple( t, &tmpTuple[0] );
1869       }
1870     }
1871     else if ( ex_get_var_time( exoid, EX_GLOBAL,
1872         ainfop->OriginalIndices[0], key.ObjectId,
1873         1, this->GetNumberOfTimeSteps(), arr->GetVoidPointer( 0 ) ) < 0 )
1874     {
1875       vtkErrorMacro(
1876         "Could not read global result variable "
1877         << ainfop->Name.c_str() << "." );
1878       arr->Delete();
1879       arr = nullptr;
1880     }
1881   }
1882   else if ( key.ObjectType == vtkExodusIIReader::NODAL_TEMPORAL )
1883   {
1884     // read temporal nodal array
1885     ArrayInfoType* ainfop = &this->ArrayInfo[vtkExodusIIReader::NODAL][key.ArrayId];
1886     arr = vtkDataArray::CreateDataArray( ainfop->StorageType );
1887     vtkStdString newArrayName = ainfop->Name + "OverTime";
1888     arr->SetName( newArrayName.c_str() );
1889     arr->SetNumberOfComponents( ainfop->Components );
1890     arr->SetNumberOfTuples( this->GetNumberOfTimeSteps() );
1891     if ( ainfop->Components == 1 )
1892     {
1893       if ( ex_get_var_time( exoid, EX_NODAL,
1894           ainfop->OriginalIndices[0], key.ObjectId,
1895           1, this->GetNumberOfTimeSteps(), arr->GetVoidPointer( 0 ) ) < 0 )
1896       {
1897         vtkErrorMacro( "Could not read nodal result variable " << ainfop->Name.c_str() << "." );
1898         arr->Delete();
1899         arr = nullptr;
1900       }
1901     }
1902     else
1903     {
1904       // Exodus doesn't support reading with a stride, so we have to manually interleave the arrays. Bleh.
1905       std::vector<std::vector<double> > tmpVal;
1906       tmpVal.resize( ainfop->Components );
1907       int c;
1908       for ( c = 0; c < ainfop->Components; ++c )
1909       {
1910         vtkIdType N = this->GetNumberOfTimeSteps();
1911         tmpVal[c].resize( N );
1912         if ( ex_get_var_time( exoid, EX_NODAL,
1913             ainfop->OriginalIndices[c], key.ObjectId,
1914             1, this->GetNumberOfTimeSteps(), &tmpVal[c][0] ) < 0 )
1915         {
1916           vtkErrorMacro( "Could not read temporal nodal result variable " << ainfop->OriginalNames[c].c_str() << "." );
1917           arr->Delete();
1918           arr = nullptr;
1919           return nullptr;
1920         }
1921       }
1922       int t;
1923       std::vector<double> tmpTuple;
1924       tmpTuple.resize( ainfop->Components );
1925       for ( t = 0; t < arr->GetNumberOfTuples(); ++t )
1926       {
1927         for ( c = 0; c < ainfop->Components; ++c )
1928         {
1929           tmpTuple[c] = tmpVal[c][t];
1930         }
1931         arr->SetTuple( t, &tmpTuple[0] );
1932       }
1933     }
1934   }
1935   else if ( key.ObjectType == vtkExodusIIReader::ELEM_BLOCK_TEMPORAL )
1936   {
1937     // read temporal element array
1938     ArrayInfoType* ainfop = &this->ArrayInfo[vtkExodusIIReader::ELEM_BLOCK][key.ArrayId];
1939     arr = vtkDataArray::CreateDataArray( ainfop->StorageType );
1940     vtkStdString newArrayName = ainfop->Name + "OverTime";
1941     arr->SetName( newArrayName.c_str() );
1942     arr->SetNumberOfComponents( ainfop->Components );
1943     arr->SetNumberOfTuples( this->GetNumberOfTimeSteps() );
1944     if ( ainfop->Components == 1 )
1945     {
1946       if ( ex_get_var_time( exoid, EX_ELEM_BLOCK,
1947           ainfop->OriginalIndices[0], key.ObjectId,
1948           1, this->GetNumberOfTimeSteps(), arr->GetVoidPointer( 0 ) ) < 0 )
1949       {
1950         vtkErrorMacro( "Could not read element result variable " << ainfop->Name.c_str() << "." );
1951         arr->Delete();
1952         arr = nullptr;
1953       }
1954     }
1955     else
1956     {
1957       // Exodus doesn't support reading with a stride, so we have to manually interleave the arrays. Bleh.
1958       std::vector<std::vector<double> > tmpVal;
1959       tmpVal.resize( ainfop->Components );
1960       int c;
1961       for ( c = 0; c < ainfop->Components; ++c )
1962       {
1963         vtkIdType N = this->GetNumberOfTimeSteps();
1964         tmpVal[c].resize( N );
1965         if ( ex_get_var_time( exoid, EX_ELEM_BLOCK,
1966             ainfop->OriginalIndices[c], key.ObjectId,
1967             1, this->GetNumberOfTimeSteps(), &tmpVal[c][0] ) < 0 )
1968         {
1969           vtkErrorMacro( "Could not read temporal element result variable " << ainfop->OriginalNames[c].c_str() << "." );
1970           arr->Delete();
1971           arr = nullptr;
1972           return nullptr;
1973         }
1974       }
1975       int t;
1976       std::vector<double> tmpTuple;
1977       tmpTuple.resize( ainfop->Components );
1978       for ( t = 0; t < arr->GetNumberOfTuples(); ++t )
1979       {
1980         for ( c = 0; c < ainfop->Components; ++c )
1981         {
1982           tmpTuple[c] = tmpVal[c][t];
1983         }
1984         arr->SetTuple( t, &tmpTuple[0] );
1985       }
1986     }
1987   }
1988   else if (
1989     key.ObjectType == vtkExodusIIReader::EDGE_BLOCK ||
1990     key.ObjectType == vtkExodusIIReader::FACE_BLOCK ||
1991     key.ObjectType == vtkExodusIIReader::ELEM_BLOCK ||
1992     key.ObjectType == vtkExodusIIReader::NODE_SET ||
1993     key.ObjectType == vtkExodusIIReader::EDGE_SET ||
1994     key.ObjectType == vtkExodusIIReader::FACE_SET ||
1995     key.ObjectType == vtkExodusIIReader::SIDE_SET ||
1996     key.ObjectType == vtkExodusIIReader::ELEM_SET
1997     )
1998   {
1999     int otypidx = this->GetObjectTypeIndexFromObjectType( key.ObjectType );
2000     ArrayInfoType* ainfop = &this->ArrayInfo[key.ObjectType][key.ArrayId];
2001     ObjectInfoType* oinfop = this->GetObjectInfo( otypidx, key.ObjectId );
2002 
2003     arr = vtkDataArray::CreateDataArray( ainfop->StorageType );
2004     arr->SetName( ainfop->Name.c_str() );
2005     if ( ainfop->Components == 2 && this->ModelParameters.num_dim == 2 )
2006     {
2007       // Promote 2-component arrays to 3-component arrays when we have 2-D coordinates
2008       arr->SetNumberOfComponents( 3 );
2009     }
2010     else
2011     {
2012       arr->SetNumberOfComponents( ainfop->Components );
2013     }
2014     arr->SetNumberOfTuples( oinfop->Size );
2015     if ( ainfop->Components == 1 )
2016     {
2017       if ( ex_get_var( exoid, key.Time + 1, static_cast<ex_entity_type>( key.ObjectType ),
2018           ainfop->OriginalIndices[0], oinfop->Id, arr->GetNumberOfTuples(),
2019           arr->GetVoidPointer( 0 ) ) < 0)
2020       {
2021         vtkErrorMacro( "Could not read result variable " << ainfop->Name.c_str() <<
2022           " for " << objtype_names[otypidx] << " " << oinfop->Id << "." );
2023         arr->Delete();
2024         arr = nullptr;
2025       }
2026     }
2027     else
2028     {
2029       // Exodus doesn't support reading with a stride, so we have to manually interleave the arrays. Bleh.
2030       std::vector<std::vector<double> > tmpVal;
2031       tmpVal.resize( ainfop->Components );
2032       int c;
2033       for ( c = 0; c < ainfop->Components; ++c )
2034       {
2035         vtkIdType N = arr->GetNumberOfTuples();
2036         tmpVal[c].resize( N+1 ); // + 1 to avoid errors when N == 0.
2037                                  // BUG #8746.
2038         if ( ex_get_var( exoid, key.Time + 1, static_cast<ex_entity_type>( key.ObjectType ),
2039             ainfop->OriginalIndices[c], oinfop->Id, arr->GetNumberOfTuples(),
2040             &tmpVal[c][0] ) < 0)
2041         {
2042           vtkErrorMacro( "Could not read result variable " << ainfop->OriginalNames[c].c_str() <<
2043             " for " << objtype_names[otypidx] << " " << oinfop->Id << "." );
2044           arr->Delete();
2045           arr = nullptr;
2046         }
2047       }
2048       // Carefully use arr->GetNumberOfComponents() when sizing
2049       // output as we may have promoted 2-D arrays to 3-D.
2050       int t = arr->GetNumberOfComponents();
2051       std::vector<double> tmpTuple;
2052       tmpTuple.resize( t );
2053       tmpTuple[t - 1] = 0.;
2054       for ( t = 0; t < arr->GetNumberOfTuples(); ++t )
2055       {
2056         for ( c = 0; c < ainfop->Components; ++c )
2057         {
2058           tmpTuple[c] = tmpVal[c][t];
2059         }
2060         arr->SetTuple( t, &tmpTuple[0] );
2061       }
2062     }
2063   }
2064   else if (
2065     key.ObjectType == vtkExodusIIReader::NODE_MAP ||
2066     key.ObjectType == vtkExodusIIReader::EDGE_MAP ||
2067     key.ObjectType == vtkExodusIIReader::FACE_MAP ||
2068     key.ObjectType == vtkExodusIIReader::ELEM_MAP
2069     )
2070   {
2071     MapInfoType* minfop = &this->MapInfo[key.ObjectType][key.ArrayId];
2072     vtkIdTypeArray* iarr = vtkIdTypeArray::New();
2073     arr = iarr;
2074     arr->SetName( minfop->Name.c_str() );
2075     arr->SetNumberOfComponents( 1 );
2076     switch ( key.ObjectType )
2077     {
2078     case vtkExodusIIReader::NODE_MAP:
2079       arr->SetNumberOfTuples( this->ModelParameters.num_nodes );
2080       break;
2081     case vtkExodusIIReader::EDGE_MAP:
2082       arr->SetNumberOfTuples( this->ModelParameters.num_edge );
2083       break;
2084     case vtkExodusIIReader::FACE_MAP:
2085       arr->SetNumberOfTuples( this->ModelParameters.num_face );
2086       break;
2087     case vtkExodusIIReader::ELEM_MAP:
2088       arr->SetNumberOfTuples( this->ModelParameters.num_elem );
2089       break;
2090     }
2091     if ( ex_get_num_map( exoid, static_cast<ex_entity_type>( key.ObjectType ), minfop->Id, (vtkIdType*)arr->GetVoidPointer( 0 ) ) < 0 )
2092     {
2093       vtkErrorMacro( "Could not read nodal map variable " << minfop->Name.c_str() << "." );
2094       arr->Delete();
2095       arr = nullptr;
2096     }
2097   }
2098   else if ( key.ObjectType == vtkExodusIIReader::GLOBAL_ELEMENT_ID )
2099   {
2100     // Yes, the next 2 statements are an intentional misuse of key
2101     // fields reserved for the ObjectId and ArrayId (since ObjectType
2102     // is used to signal that we want IDs instead of a field value).
2103     int otypidx = this->GetObjectTypeIndexFromObjectType( key.ObjectId );
2104     int obj = key.ArrayId;
2105     BlockSetInfoType* bsinfop = (BlockSetInfoType*) this->GetObjectInfo( otypidx, obj );
2106 
2107     vtkExodusIICacheKey ckey( -1, -1, 0, 0 );
2108     switch ( key.ObjectId )
2109     {
2110     case vtkExodusIIReader::EDGE_BLOCK:
2111       ckey.ObjectType = vtkExodusIIReader::EDGE_ID;
2112       break;
2113     case vtkExodusIIReader::FACE_BLOCK:
2114       ckey.ObjectType = vtkExodusIIReader::FACE_ID;
2115       break;
2116     case vtkExodusIIReader::ELEM_BLOCK:
2117     default:
2118       ckey.ObjectType = vtkExodusIIReader::ELEMENT_ID;
2119       break;
2120     }
2121     vtkIdTypeArray* src = vtkArrayDownCast<vtkIdTypeArray>( this->GetCacheOrRead( ckey ) );
2122     if ( ! src )
2123     {
2124       arr = nullptr;
2125       return nullptr;
2126     }
2127     vtkIdTypeArray* iarr = vtkIdTypeArray::New();
2128     iarr->SetName( vtkExodusIIReader::GetGlobalElementIdArrayName() );
2129     iarr->SetNumberOfComponents( 1 );
2130     iarr->SetNumberOfTuples( bsinfop->Size );
2131     vtkIdType* gloIds = iarr->GetPointer( 0 );
2132     vtkIdType* srcIds = src->GetPointer( bsinfop->FileOffset - 1 );
2133     memcpy( gloIds, srcIds, sizeof(vtkIdType) * bsinfop->Size );
2134     arr = iarr;
2135   }
2136   else if ( key.ObjectType == vtkExodusIIReader::IMPLICIT_ELEMENT_ID )
2137   {
2138     // Yes, the next 2 statements are an intentional misuse of key
2139     // fields reserved for the ObjectId and ArrayId (since ObjectType
2140     // is used to signal that we want IDs instead of a field value).
2141     int otypidx = this->GetObjectTypeIndexFromObjectType( key.ObjectId );
2142     int obj = key.ArrayId;
2143     BlockSetInfoType* bsinfop = (BlockSetInfoType*) this->GetObjectInfo( otypidx, obj );
2144 
2145     vtkExodusIICacheKey ckey( -1, -1, 0, 0 );
2146     vtkIdType mapSize;
2147     int nMaps;
2148     switch ( key.ObjectId )
2149     {
2150     case vtkExodusIIReader::EDGE_BLOCK:
2151       ckey.ObjectType = vtkExodusIIReader::EDGE_ID;
2152       mapSize = this->ModelParameters.num_edge;
2153       nMaps = this->ModelParameters.num_edge_maps;
2154       break;
2155     case vtkExodusIIReader::FACE_BLOCK:
2156       ckey.ObjectType = vtkExodusIIReader::FACE_ID;
2157       mapSize = this->ModelParameters.num_face;
2158       nMaps = this->ModelParameters.num_face_maps;
2159       break;
2160     case vtkExodusIIReader::ELEM_BLOCK:
2161     default:
2162       ckey.ObjectType = vtkExodusIIReader::ELEMENT_ID;
2163       mapSize = this->ModelParameters.num_elem;
2164       nMaps = this->ModelParameters.num_elem_maps;
2165       break;
2166     }
2167     vtkIdTypeArray* src = vtkIdTypeArray::New ();
2168     src->SetNumberOfComponents( 1 );
2169     src->SetNumberOfTuples( mapSize );
2170     if (nMaps > 0) // FIXME correctly detect parallel
2171     {
2172         if ( ex_get_id_map( exoid, static_cast<ex_entity_type>( ckey.ObjectType ), (vtkIdType*)src->GetPointer( 0 ) ) < 0 )
2173         {
2174           vtkErrorMacro( "Could not read elem num map for global implicit id" );
2175           src->Delete();
2176           return nullptr;
2177         }
2178     }
2179     else // single file, just make the implicit index explicit
2180     {
2181       for (vtkIdType i = 0; i < src->GetNumberOfTuples (); i ++)
2182       {
2183         src->SetValue (i, i + 1);
2184       }
2185     }
2186     vtkIdTypeArray* iarr = vtkIdTypeArray::New();
2187     iarr->SetName( vtkExodusIIReader::GetImplicitElementIdArrayName() );
2188     iarr->SetNumberOfComponents( 1 );
2189     iarr->SetNumberOfTuples( bsinfop->Size );
2190     vtkIdType* gloIds = iarr->GetPointer( 0 );
2191     vtkIdType* srcIds = src->GetPointer( bsinfop->FileOffset - 1 );
2192     memcpy( gloIds, srcIds, sizeof(vtkIdType) * bsinfop->Size );
2193     arr = iarr;
2194     src->Delete ();
2195   }
2196   else if ( key.ObjectType == vtkExodusIIReader::GLOBAL_NODE_ID )
2197   { // subset the NODE_ID array choosing only entries for nodes in output grid (using PointMap)
2198     // Yes, the next 2 statements are an intentional misuse of key
2199     // fields reserved for the ObjectId and ArrayId (since ObjectType
2200     // is used to signal that we want IDs instead of a field value).
2201     int otypidx = this->GetObjectTypeIndexFromObjectType( key.ObjectId );
2202     int obj = key.ArrayId;
2203     BlockSetInfoType* bsinfop = (BlockSetInfoType*) this->GetObjectInfo( otypidx, obj );
2204     vtkIdTypeArray* src = vtkArrayDownCast<vtkIdTypeArray>(
2205       this->GetCacheOrRead( vtkExodusIICacheKey( -1, vtkExodusIIReader::NODE_ID, 0, 0 ) ) );
2206     if ( this->SqueezePoints && src )
2207     {
2208       vtkIdTypeArray* iarr = vtkIdTypeArray::New();
2209       iarr->SetName( vtkExodusIIReader::GetGlobalNodeIdArrayName() );
2210       iarr->SetNumberOfComponents( 1 );
2211       iarr->SetNumberOfTuples( bsinfop->NextSqueezePoint );
2212       vtkIdType* gloIds = iarr->GetPointer( 0 );
2213       vtkIdType* srcIds = src->GetPointer( 0 );
2214       std::map<vtkIdType,vtkIdType>::iterator it;
2215       for ( it = bsinfop->PointMap.begin(); it != bsinfop->PointMap.end(); ++ it )
2216       {
2217         gloIds[it->second] = srcIds[it->first];
2218       }
2219       arr = iarr;
2220     }
2221     else
2222     {
2223       arr = src;
2224     }
2225   }
2226   else if ( key.ObjectType == vtkExodusIIReader::IMPLICIT_NODE_ID )
2227   { // subset the NODE_ID array choosing only entries for nodes in output grid (using PointMap)
2228     // Yes, the next 2 statements are an intentional misuse of key
2229     // fields reserved for the ObjectId and ArrayId (since ObjectType
2230     // is used to signal that we want IDs instead of a field value).
2231     int otypidx = this->GetObjectTypeIndexFromObjectType( key.ObjectId );
2232     int obj = key.ArrayId;
2233     BlockSetInfoType* bsinfop = (BlockSetInfoType*) this->GetObjectInfo( otypidx, obj );
2234     vtkIdTypeArray* src = vtkIdTypeArray::New ();
2235     src->SetNumberOfComponents( 1 );
2236     src->SetNumberOfTuples( this->ModelParameters.num_nodes );
2237     if (this->ModelParameters.num_node_maps > 0) // FIXME correctly detect parallel
2238     {
2239         if ( ex_get_id_map( exoid, (ex_entity_type)( vtkExodusIIReader::NODE_MAP ), (vtkIdType*)src->GetPointer( 0 ) ) < 0 )
2240         {
2241           vtkErrorMacro( "Could not node node num map for global implicit id" );
2242           src->Delete();
2243           return nullptr;
2244         }
2245     }
2246     else // single file, just make the implicit index explicit
2247     {
2248       for (vtkIdType i = 0; i < src->GetNumberOfTuples (); i ++)
2249       {
2250         src->SetValue (i, i + 1);
2251       }
2252     }
2253     if ( this->SqueezePoints && src )
2254     {
2255       vtkIdTypeArray* iarr = vtkIdTypeArray::New();
2256       iarr->SetName( vtkExodusIIReader::GetImplicitNodeIdArrayName() );
2257       iarr->SetNumberOfComponents( 1 );
2258       iarr->SetNumberOfTuples( bsinfop->NextSqueezePoint );
2259       vtkIdType* gloIds = iarr->GetPointer( 0 );
2260       vtkIdType* srcIds = src->GetPointer( 0 );
2261       std::map<vtkIdType,vtkIdType>::iterator it;
2262       for ( it = bsinfop->PointMap.begin(); it != bsinfop->PointMap.end(); ++ it )
2263       {
2264         gloIds[it->second] = srcIds[it->first];
2265       }
2266       arr = iarr;
2267     }
2268     else
2269     {
2270       arr = src;
2271     }
2272     src->Delete ();
2273   }
2274   else if (
2275     key.ObjectType == vtkExodusIIReader::ELEMENT_ID ||
2276     key.ObjectType == vtkExodusIIReader::EDGE_ID ||
2277     key.ObjectType == vtkExodusIIReader::FACE_ID ||
2278     key.ObjectType == vtkExodusIIReader::NODE_ID
2279     )
2280   {
2281     vtkIdTypeArray* iarr;
2282     int nMaps;
2283     vtkIdType mapSize;
2284     vtkExodusIICacheKey ktmp;
2285     if ( key.ObjectType == vtkExodusIIReader::ELEMENT_ID )
2286     {
2287       nMaps = this->ModelParameters.num_elem_maps;
2288       mapSize = this->ModelParameters.num_elem;
2289       ktmp = vtkExodusIICacheKey( -1, vtkExodusIIReader::ELEM_MAP, 0, 0 );
2290     }
2291     else if ( key.ObjectType == vtkExodusIIReader::FACE_ID )
2292     {
2293       nMaps = this->ModelParameters.num_face_maps;
2294       mapSize = this->ModelParameters.num_face;
2295       ktmp = vtkExodusIICacheKey( -1, vtkExodusIIReader::FACE_MAP, 0, 0 );
2296     }
2297     else if ( key.ObjectType == vtkExodusIIReader::EDGE_ID )
2298     {
2299       nMaps = this->ModelParameters.num_edge_maps;
2300       mapSize = this->ModelParameters.num_edge;
2301       ktmp = vtkExodusIICacheKey( -1, vtkExodusIIReader::EDGE_MAP, 0, 0 );
2302     }
2303     else // ( key.ObjectType == vtkExodusIIReader::NODE_ID )
2304     {
2305       nMaps = this->ModelParameters.num_node_maps;
2306       mapSize = this->ModelParameters.num_nodes;
2307       ktmp = vtkExodusIICacheKey( -1, vtkExodusIIReader::NODE_MAP, 0, 0 );
2308     }
2309     // If there are no new-style maps, get the old-style map (which creates a default if nothing is stored on disk).
2310     if ( nMaps < 1 || ! (iarr = vtkArrayDownCast<vtkIdTypeArray>(this->GetCacheOrRead( ktmp ))) )
2311     {
2312       iarr = vtkIdTypeArray::New();
2313       iarr->SetNumberOfComponents( 1 );
2314       iarr->SetNumberOfTuples( mapSize );
2315       if ( mapSize )
2316       {
2317         if ( ex_get_id_map( exoid, static_cast<ex_entity_type>( ktmp.ObjectType ), (vtkIdType*)iarr->GetPointer( 0 ) ) < 0 )
2318         {
2319           vtkErrorMacro( "Could not read old-style node or element map." );
2320           iarr->Delete();
2321           iarr = nullptr;
2322         }
2323       }
2324     }
2325     else
2326     {
2327       // FastDelete will be called below (because we are assumed to have created the array with New()).
2328       // So we must reference the array one extra time here to account for the extra delete...
2329       iarr->Register( this );
2330     }
2331     arr = iarr;
2332   }
2333   else if ( key.ObjectType == vtkExodusIIReader::GLOBAL_CONN )
2334   {
2335     vtkErrorMacro(
2336       "Global connectivity is created in AssembleOutputConnectivity since it can't be cached\n"
2337       "with a single vtkDataArray. Who told you to call this routine to get it?"
2338       );
2339   }
2340   else if ( key.ObjectType == vtkExodusIIReader::ENTITY_COUNTS )
2341   {
2342     int ctypidx = (key.ArrayId == 0 ? 0 : 1);
2343     int otypidx = conn_obj_idx_cvt[ctypidx];
2344     int otyp = obj_types[ otypidx ];
2345     BlockInfoType* binfop = (BlockInfoType*) this->GetObjectInfo( otypidx, key.ObjectId );
2346     vtkIntArray* iarr = vtkIntArray::New();
2347     iarr->SetNumberOfComponents (1);
2348     iarr->SetNumberOfTuples (binfop->Size);
2349     if ( ex_get_entity_count_per_polyhedra ( exoid, static_cast<ex_entity_type>( otyp ), binfop->Id,
2350                                              iarr->GetPointer(0)) < 0 )
2351     {
2352       vtkErrorMacro( "Unable to read " << binfop->Id << " (index " << key.ObjectId <<
2353         ") entity count per polyhedra" );
2354       iarr->Delete();
2355       iarr = nullptr;
2356     }
2357     arr = iarr;
2358   }
2359   else if (
2360     key.ObjectType == vtkExodusIIReader::ELEM_BLOCK_ELEM_CONN ||
2361     key.ObjectType == vtkExodusIIReader::FACE_BLOCK_CONN ||
2362     key.ObjectType == vtkExodusIIReader::EDGE_BLOCK_CONN
2363   )
2364   {
2365     int ctypidx = this->GetConnTypeIndexFromConnType( key.ObjectType );
2366     int otypidx = conn_obj_idx_cvt[ctypidx];
2367     int otyp = obj_types[ otypidx ];
2368     BlockInfoType* binfop = (BlockInfoType*) this->GetObjectInfo( otypidx, key.ObjectId );
2369 
2370     auto* iarr = vtkIdTypeArray::New();
2371     if (binfop->CellType == VTK_POLYGON)
2372     {
2373       iarr->SetNumberOfValues (binfop->BdsPerEntry[0]);
2374     }
2375     else if (binfop->CellType == VTK_POLYHEDRON)
2376     {
2377       iarr->SetNumberOfValues (binfop->BdsPerEntry[2]);
2378     }
2379     else
2380     {
2381       iarr->SetNumberOfComponents( binfop->BdsPerEntry[0] );
2382       iarr->SetNumberOfTuples( binfop->Size );
2383     }
2384 
2385     if ( ex_get_conn( exoid, static_cast<ex_entity_type>( otyp ), binfop->Id, iarr->GetPointer(0), nullptr, nullptr ) < 0 )
2386     {
2387       vtkErrorMacro( "Unable to read " << objtype_names[otypidx] << " " << binfop->Id << " (index " << key.ObjectId <<
2388         ") nodal connectivity." );
2389       iarr->Delete();
2390       iarr = nullptr;
2391     }
2392 
2393     vtkIdType c;
2394     auto ptr = iarr->GetPointer( 0 );
2395     if (
2396       binfop->CellType == VTK_QUADRATIC_HEXAHEDRON ||
2397       binfop->CellType == VTK_TRIQUADRATIC_HEXAHEDRON
2398       )
2399     {
2400       // Edge order for VTK is different than Exodus edge order.
2401       for ( c = 0; c < iarr->GetNumberOfTuples(); ++c )
2402       {
2403         int k;
2404         int itmp[4];
2405 
2406         for ( k = 0; k < 12; ++k, ++ptr)
2407           *ptr = *ptr - 1;
2408 
2409         for ( k = 0; k < 4; ++k, ++ptr)
2410         {
2411           itmp[k] = *ptr;
2412           *ptr = ptr[4] - 1;
2413         }
2414 
2415         for ( k = 0; k < 4; ++k, ++ptr )
2416           *ptr = itmp[k] - 1;
2417 
2418         if ( binfop->CellType == VTK_TRIQUADRATIC_HEXAHEDRON )
2419         { // Face/body order for VTK is different than Exodus (Patran) order.
2420           for ( k = 0; k < 4; ++k, ++ptr )
2421           {
2422             itmp[k] = *ptr;
2423             *ptr = ptr[3] - 1;
2424           }
2425           *(ptr++) = itmp[1] - 1;
2426           *(ptr++) = itmp[2] - 1;
2427           *(ptr++) = itmp[0] - 1;
2428         }
2429       }
2430       ptr += binfop->BdsPerEntry[0] - binfop->PointsPerCell;
2431     }
2432     else if (binfop->CellType == VTK_QUADRATIC_WEDGE)
2433     {
2434       int k;
2435       int itmp[3];
2436       for ( c = 0; c < iarr->GetNumberOfTuples(); ++c )
2437       {
2438         for (k = 0; k < 9; ++k, ++ptr)
2439           *ptr = *ptr - 1;
2440 
2441         for (k = 0; k < 3; ++k, ++ptr)
2442         {
2443           itmp[k] = *ptr;
2444           *ptr = ptr[3] - 1;
2445         }
2446 
2447         for (k = 0; k < 3; ++k, ++ptr)
2448         {
2449           *ptr = itmp[k] - 1;
2450         }
2451       }
2452       ptr += binfop->BdsPerEntry[0] - binfop->PointsPerCell;
2453     }
2454     else if (binfop->CellType == VTK_LAGRANGE_WEDGE && binfop->PointsPerCell == 21)
2455     {
2456       // Exodus orders edges like so:
2457       //   r-dir @ -z, 1-r-s-dir @ -z, s-dir @ -z,
2458       //   t-dir @ +1-r-s, t-dir @ +r, t-dir @ +s,
2459       //   r-dir @ +z, 1-r-s-dir @ +z, s-dir @ +z,
2460       // VTK orders edges like so:
2461       //   r-dir @ -z, 1-r-s-dir @ -z, s-dir @ -z,
2462       //   r-dir @ +z, 1-r-s-dir @ +z, s-dir @ +z,
2463       //   t-dir @ +1-r-s, t-dir @ +r, t-dir @ +s,
2464       int k;
2465       int itmp[3];
2466       for ( c = 0; c < iarr->GetNumberOfTuples(); ++c )
2467       {
2468         for (k = 0; k < 9; ++k, ++ptr)
2469           *ptr = *ptr - 1;
2470 
2471         for (k = 0; k < 3; ++k, ++ptr)
2472         {
2473           itmp[k] = *ptr;
2474           *ptr = ptr[3] - 1;
2475         }
2476 
2477         for (k = 0; k < 3; ++k, ++ptr)
2478         {
2479           *ptr = itmp[k] - 1;
2480         }
2481         // The body-centered node immediately follows the edges in the
2482         // Exodus file and is then followed by wedge face nodes,
2483         // but not in the same order as VTK or the linear Exodus side-set
2484         // ordering:
2485         int ftmp[6];
2486         static int wedgeMapping[6] = {1, 2, 5, 3, 4, 0};
2487         for (k = 0; k < 6; ++k)
2488         {
2489           ftmp[k] = ptr[wedgeMapping[k]];
2490         }
2491         for (k = 0; k < 6; ++k, ++ptr)
2492         {
2493           *ptr = ftmp[k] - 1;
2494         }
2495       }
2496       ptr += binfop->BdsPerEntry[0] - binfop->PointsPerCell;
2497     }
2498     else if (binfop->CellType == VTK_LAGRANGE_TETRAHEDRON && binfop->PointsPerCell == 15)
2499     {
2500       int k;
2501       for ( c = 0; c < iarr->GetNumberOfTuples(); ++c )
2502       {
2503         // Tet corners and edges are ordered as expected
2504         for (k = 0; k < 10; ++k, ++ptr)
2505         {
2506           *ptr = *ptr - 1;
2507         }
2508         // ... but the body-centered node is placed *before* the
2509         // tet face nodes and the faces are not in the canonical
2510         // side-set ordering.
2511         static int tetMapping[5] = { 1, 4, 2, 3, 0 };
2512         int ftmp[5];
2513         for (k = 0; k < 5; ++k)
2514         {
2515           ftmp[k] = ptr[tetMapping[k]];
2516         }
2517         for (k = 0; k < 5; ++k, ++ptr)
2518         {
2519           *ptr = ftmp[k] - 1;
2520         }
2521       }
2522       ptr += binfop->BdsPerEntry[0] - binfop->PointsPerCell;
2523     }
2524     else
2525     {
2526       for ( c = 0; c <= iarr->GetMaxId(); ++c, ++ptr )
2527       {
2528         *ptr = *ptr - 1;
2529       }
2530     }
2531 
2532     arr = iarr;
2533   }
2534   else if (
2535     key.ObjectType == vtkExodusIIReader::ELEM_BLOCK_FACE_CONN ||
2536     key.ObjectType == vtkExodusIIReader::ELEM_BLOCK_EDGE_CONN )
2537   {
2538     arr = nullptr;
2539 
2540     // bdsEntry will determine whether we call ex_get_conn to read edge or face connectivity:
2541     int bdsEntry = key.ObjectType == vtkExodusIIReader::ELEM_BLOCK_EDGE_CONN ? 1 : 2;
2542 
2543     // Fetch the block information from the key
2544     //int ctypidx = this->GetConnTypeIndexFromConnType( key.ObjectType );
2545     int otypidx = 2; // These always refer to the element block
2546     int otyp = obj_types[ otypidx ];
2547     BlockInfoType* binfop = (BlockInfoType*) this->GetObjectInfo( otypidx, key.ObjectId );
2548 
2549     // Only create the array if there's anything to put in it.
2550     if (binfop->BdsPerEntry[bdsEntry] > 0)
2551     {
2552       auto* iarr = vtkIdTypeArray::New();
2553       iarr->SetNumberOfValues (binfop->BdsPerEntry[2]);
2554 
2555       if (
2556         ex_get_conn(
2557           exoid,
2558           static_cast<ex_entity_type>( otyp ),
2559           binfop->Id,
2560           nullptr,
2561           bdsEntry == 1 ? iarr->GetPointer(0) : nullptr,
2562           bdsEntry == 2 ? iarr->GetPointer(0) : nullptr ) < 0)
2563       {
2564         vtkErrorMacro(
2565           "Unable to read " << objtype_names[otypidx] << " "
2566           << binfop->Id << " (index " << key.ObjectId <<
2567           ") " << (bdsEntry == 1 ? "edge" : "face") << " connectivity." );
2568         iarr->Delete();
2569         iarr = nullptr;
2570       }
2571       else
2572       {
2573         vtkIdType c;
2574         auto ptr = iarr->GetPointer( 0 );
2575         for ( c = 0; c <= iarr->GetMaxId(); ++c, ++ptr )
2576         {
2577           *ptr = *ptr - 1;
2578         }
2579       }
2580       arr = iarr;
2581     }
2582   }
2583   else if (
2584     key.ObjectType == vtkExodusIIReader::NODE_SET_CONN ||
2585     key.ObjectType == vtkExodusIIReader::ELEM_SET_CONN
2586   )
2587   {
2588     int otyp = this->GetSetTypeFromSetConnType( key.ObjectType );
2589     int otypidx = this->GetObjectTypeIndexFromObjectType( otyp );
2590     SetInfoType* sinfop = &this->SetInfo[otyp][key.ObjectId];
2591 
2592     auto* iarr = vtkIdTypeArray::New();
2593     iarr->SetNumberOfComponents( 1 );
2594     iarr->SetNumberOfTuples( sinfop->Size );
2595     auto iptr = iarr->GetPointer( 0 );
2596 
2597     if ( ex_get_set( exoid, static_cast<ex_entity_type>( otyp ), sinfop->Id, iptr, nullptr ) < 0 )
2598     {
2599       vtkErrorMacro( "Unable to read " << objtype_names[otypidx] << " " << sinfop->Id << " (index " << key.ObjectId <<
2600         ") nodal connectivity." );
2601       iarr->Delete();
2602       iarr = nullptr;
2603     }
2604 
2605     vtkIdType id;
2606     for ( id = 0; id < sinfop->Size; ++id, ++iptr )
2607     { // VTK uses 0-based indexing, unlike Exodus:
2608       --(*iptr);
2609     }
2610 
2611     arr = iarr;
2612   }
2613   else if ( key.ObjectType == vtkExodusIIReader::EDGE_SET_CONN || key.ObjectType == vtkExodusIIReader::FACE_SET_CONN )
2614   {
2615     int otyp = this->GetSetTypeFromSetConnType( key.ObjectType );
2616     int otypidx = this->GetObjectTypeIndexFromObjectType( otyp );
2617     SetInfoType* sinfop = &this->SetInfo[otyp][key.ObjectId];
2618 
2619     auto* iarr = vtkIdTypeArray::New();
2620     iarr->SetNumberOfComponents( 2 );
2621     iarr->SetNumberOfTuples( sinfop->Size );
2622     std::vector<int> tmpOrient; // hold the edge/face orientation information until we can interleave it.
2623     tmpOrient.resize( sinfop->Size );
2624 
2625     if ( ex_get_set( exoid, static_cast<ex_entity_type>( otyp ), sinfop->Id, iarr->GetPointer(0), &tmpOrient[0] ) < 0 )
2626     {
2627       vtkErrorMacro( "Unable to read " << objtype_names[otypidx] << " " << sinfop->Id << " (index " << key.ObjectId <<
2628         ") nodal connectivity." );
2629       iarr->Delete();
2630       iarr = nullptr;
2631       return nullptr;
2632     }
2633 
2634     auto iap = iarr->GetPointer( 0 );
2635     vtkIdType c;
2636     for ( c = sinfop->Size - 1; c >= 0; --c )
2637     {
2638       iap[2*c] = iap[c] - 1; // VTK uses 0-based indexing
2639       iap[2*c + 1] = tmpOrient[c];
2640     }
2641 
2642     arr = iarr;
2643   }
2644   else if ( key.ObjectType == vtkExodusIIReader::SIDE_SET_CONN )
2645   {
2646     if(key.ArrayId <= 0)
2647     {
2648       // Stick all of side_set_node_list and side_set_node_count and side_set_nodes_per_side in one array
2649       // let InsertSetSides() figure it all out. Except for 0-based indexing
2650       SetInfoType* sinfop = &this->SetInfo[vtkExodusIIReader::SIDE_SET][key.ObjectId];
2651       vtkIdType ssnllen; // side set node list length
2652       if ( ex_get_side_set_node_list_len( exoid, sinfop->Id, &ssnllen ) < 0 )
2653       {
2654         vtkErrorMacro( "Unable to fetch side set \"" << sinfop->Name.c_str() << "\" (" << sinfop->Id << ") node list length" );
2655         arr = nullptr;
2656         return nullptr;
2657       }
2658       auto* iarr = vtkIdTypeArray::New();
2659       vtkIdType ilen = ssnllen + sinfop->Size;
2660       iarr->SetNumberOfComponents( 1 );
2661       iarr->SetNumberOfTuples( ilen );
2662       auto* dat = iarr->GetPointer( 0 );
2663       if ( ex_get_side_set_node_list( exoid, sinfop->Id, dat, dat + sinfop->Size ) < 0 )
2664       {
2665         vtkErrorMacro( "Unable to fetch side set \"" << sinfop->Name.c_str() << "\" (" << sinfop->Id << ") node list" );
2666         iarr->Delete();
2667         arr = nullptr;
2668         return nullptr;
2669       }
2670       while ( ilen > sinfop->Size )
2671       { // move to 0-based indexing on nodes, don't touch nodes/side counts at head of array
2672         --dat[--ilen];
2673       }
2674       arr = iarr;
2675     } // if(key.ArrayId <= 0)
2676     else
2677     {
2678       // return information about where the side set cells come from on the elements
2679       // the first tuple value is the element id and the second is the canonical side
2680       // sinfop->Size is the number of sides in this side set
2681       SetInfoType* sinfop = &this->SetInfo[vtkExodusIIReader::SIDE_SET][key.ObjectId];
2682       std::vector<vtkIdType> side_set_elem_list(sinfop->Size);
2683       std::vector<vtkIdType> side_set_side_list(sinfop->Size);
2684       if ( ex_get_side_set( exoid, sinfop->Id, &side_set_elem_list[0], &side_set_side_list[0]) < 0 )
2685       {
2686         vtkErrorMacro( "Unable to fetch side set \"" << sinfop->Name.c_str() << "\" (" << sinfop->Id << ") node list" );
2687         arr = nullptr;
2688         return nullptr;
2689       }
2690       vtkIdTypeArray* iarr = vtkIdTypeArray::New();
2691       iarr->SetNumberOfComponents( 2 );
2692       iarr->SetNumberOfTuples( sinfop->Size );
2693       for(int i=0;i<sinfop->Size;i++)
2694       { // we'll have to fix up the side indexing later
2695         // because Exodus and VTK have different canonical orderings for wedges and hexes.
2696         vtkIdType info[2] = {side_set_elem_list[i], side_set_side_list[i]};
2697         iarr->SetTypedTuple(i, info);
2698       }
2699       arr = iarr;
2700     }
2701   }
2702   else if ( key.ObjectType == vtkExodusIIReader::NODAL_COORDS )
2703   {
2704     // read node coords
2705     vtkDataArray* displ = nullptr;
2706     if ( this->ApplyDisplacements && key.Time >= 0 )
2707     {
2708       displ = this->FindDisplacementVectors( key.Time );
2709     }
2710 
2711     std::vector<double> coordTmp;
2712     vtkDoubleArray* darr = vtkDoubleArray::New();
2713     arr = darr;
2714     arr->SetNumberOfComponents( 3 );
2715     arr->SetNumberOfTuples( this->ModelParameters.num_nodes );
2716     int dim = this->ModelParameters.num_dim;
2717     int c;
2718     vtkIdType t;
2719     double* xc = nullptr;
2720     double* yc = nullptr;
2721     double* zc = nullptr;
2722     coordTmp.resize( this->ModelParameters.num_nodes );
2723     for ( c = 0; c < dim; ++c )
2724     {
2725       switch ( c )
2726       {
2727       case 0:
2728         xc = &coordTmp[0];
2729         break;
2730       case 1:
2731         yc = xc;
2732         xc = nullptr;
2733         break;
2734       case 2:
2735         zc = yc;
2736         yc = nullptr;
2737         break;
2738       default:
2739         vtkErrorMacro( "Bad coordinate index " << c << " when reading point coordinates." );
2740         xc = yc = zc = nullptr;
2741       }
2742       if ( ex_get_coord( exoid, xc, yc, zc ) < 0 )
2743       {
2744         vtkErrorMacro( "Unable to read node coordinates for index " << c << "." );
2745         arr->Delete();
2746         arr = nullptr;
2747         break;
2748       }
2749       double* cptr = darr->GetPointer( c );
2750 
2751       //
2752       // num_nodes can get big.  Lets unroll the loop
2753       //
2754       for ( t = 0; t+8 < this->ModelParameters.num_nodes; t+=8 )
2755       {
2756         *(cptr+3*0) = coordTmp[t+0];
2757         *(cptr+3*1) = coordTmp[t+1];
2758         *(cptr+3*2) = coordTmp[t+2];
2759         *(cptr+3*3) = coordTmp[t+3];
2760         *(cptr+3*4) = coordTmp[t+4];
2761         *(cptr+3*5) = coordTmp[t+5];
2762         *(cptr+3*6) = coordTmp[t+6];
2763         *(cptr+3*7) = coordTmp[t+7];
2764         cptr += 3*8;
2765       }
2766 
2767       for ( ; t < this->ModelParameters.num_nodes; ++t )
2768       {
2769         *cptr = coordTmp[t];
2770         cptr += 3;
2771       }
2772     }
2773     if ( dim < 3 )
2774     {
2775       double* cptr = darr->GetPointer( 2 );
2776       for ( t = 0; t < this->ModelParameters.num_nodes; ++t, cptr += 3 )
2777       {
2778         *cptr = 0.;
2779       }
2780     }
2781     //
2782     // Unrolling some of the inner loops for the most common case - dim 3.
2783     // Also moving the maxTuples from inside of the for(;;) loops
2784     // Also moving cos() calculations out of the bottom of loops.
2785     //
2786     if ( displ )
2787     {
2788       double* coords = darr->GetPointer( 0 );
2789       if ( this->HasModeShapes && this->AnimateModeShapes )
2790       {
2791         double tempDouble = this->DisplacementMagnitude * cos(2.0 * vtkMath::Pi() * this->ModeShapeTime);
2792         if ( dim == 3)
2793         {
2794           vtkIdType  maxTuples =  arr->GetNumberOfTuples();
2795           for ( vtkIdType idx = 0; idx < maxTuples; ++idx )
2796           {
2797             double* dispVal = displ->GetTuple( idx );
2798             coords[0] += dispVal[0] * tempDouble;
2799             coords[1] += dispVal[1] * tempDouble;
2800             coords[2] += dispVal[2] * tempDouble;
2801             coords += 3;
2802           }
2803         }
2804         else
2805         {
2806           for ( vtkIdType idx = 0; idx < displ->GetNumberOfTuples(); ++idx )
2807           {
2808             double* dispVal = displ->GetTuple( idx );
2809             for ( c = 0; c < dim; ++c )
2810               coords[c] += dispVal[c] * tempDouble;
2811 
2812             coords += 3;
2813           }
2814         }
2815       }
2816       else
2817       {
2818         if ( dim == 3)
2819         {
2820           vtkIdType  maxTuples =  arr->GetNumberOfTuples();
2821           for ( vtkIdType idx = 0; idx < maxTuples; ++idx )
2822           {
2823             double* dispVal = displ->GetTuple( idx );
2824             coords[0] += dispVal[0] * this->DisplacementMagnitude;
2825             coords[1] += dispVal[1] * this->DisplacementMagnitude;
2826             coords[2] += dispVal[2] * this->DisplacementMagnitude;
2827 
2828             coords += 3;
2829           }
2830         }
2831         else
2832         {
2833           for ( vtkIdType idx = 0; idx < displ->GetNumberOfTuples(); ++idx )
2834           {
2835             double* dispVal = displ->GetTuple( idx );
2836             for ( c = 0; c < dim; ++c )
2837               coords[c] += dispVal[c] * this->DisplacementMagnitude;
2838 
2839             coords += 3;
2840           }
2841         }
2842       }
2843     }
2844   }
2845   else if ( key.ObjectType == vtkExodusIIReader::OBJECT_ID )
2846   {
2847     BlockSetInfoType* bsinfop;
2848     // Yes, the next 2 statements are an intentional misuse of key
2849     // fields reserved for the ObjectId and ArrayId (since ObjectType
2850     // is used to signal that we want IDs instead of a field value).
2851     int otypidx = this->GetObjectTypeIndexFromObjectType( key.ObjectId );
2852     int obj = key.ArrayId;
2853     bsinfop = (BlockSetInfoType*) this->GetObjectInfo( otypidx, obj );
2854 
2855     arr = vtkIntArray::New();
2856     arr->SetName( this->GetObjectIdArrayName() );
2857     arr->SetNumberOfComponents( 1 );
2858     arr->SetNumberOfTuples( bsinfop->Size );
2859     arr->FillComponent( 0, bsinfop->Id );
2860 
2861   }
2862   else if (
2863     key.ObjectType == vtkExodusIIReader::ELEM_BLOCK_ATTRIB ||
2864     key.ObjectType == vtkExodusIIReader::FACE_BLOCK_ATTRIB ||
2865     key.ObjectType == vtkExodusIIReader::EDGE_BLOCK_ATTRIB
2866     )
2867   {
2868     int blkType =
2869       (key.ObjectType == vtkExodusIIReader::ELEM_BLOCK_ATTRIB ? vtkExodusIIReader::ELEM_BLOCK :
2870        (key.ObjectType == vtkExodusIIReader::FACE_BLOCK_ATTRIB ? vtkExodusIIReader::FACE_BLOCK :
2871         vtkExodusIIReader::EDGE_BLOCK));
2872     BlockInfoType* binfop = &this->BlockInfo[blkType][key.ObjectId];
2873     vtkDoubleArray* darr = vtkDoubleArray::New();
2874     arr = darr;
2875     darr->SetName( binfop->AttributeNames[key.ArrayId].c_str() );
2876     darr->SetNumberOfComponents( 1 );
2877     darr->SetNumberOfTuples( binfop->Size );
2878     if ( ex_get_one_attr(
2879         exoid, static_cast<ex_entity_type>(blkType), binfop->Id, key.ArrayId + 1, darr->GetVoidPointer( 0 ) ) < 0 )
2880     { // NB: The error message references the file-order object id, not the numerically sorted index presented to users.
2881       vtkErrorMacro( "Unable to read attribute " << key.ArrayId
2882         << " for object " << key.ObjectId << " of type " << key.ObjectType  << " block type " << blkType << "." );
2883       arr->Delete();
2884       arr = nullptr;
2885     }
2886   }
2887   else if ( key.ObjectType == vtkExodusIIReader::INFO_RECORDS )
2888   {
2889     // Get Exodus II INFO records.  Each INFO record is a single character string.
2890     vtkIdType num_info = 0;
2891     float fdum;
2892     char* cdum = nullptr;
2893     int i;
2894 
2895     vtkCharArray* carr = vtkCharArray::New();
2896     carr->SetName("Info_Records");
2897     carr->SetNumberOfComponents( MAX_LINE_LENGTH+1 );
2898 
2899     if( ex_inquire( exoid, EX_INQ_INFO, &num_info, &fdum, cdum ) < 0 )
2900     {
2901       vtkErrorMacro( "Unable to get number of INFO records from ex_inquire" );
2902       carr->Delete();
2903       arr = nullptr;
2904     }
2905     else
2906     {
2907       if ( num_info > 0 )
2908       {
2909         carr->SetNumberOfTuples(num_info);
2910         char** info = (char**) calloc( num_info, sizeof(char*) );
2911 
2912         for ( i = 0; i < num_info; ++i )
2913           info[i] = (char *) calloc ( ( MAX_LINE_LENGTH + 1 ), sizeof(char) );
2914 
2915         if ( ex_get_info( exoid, info ) < 0 )
2916         {
2917           vtkErrorMacro( "Unable to read INFO records from ex_get_info");
2918           carr->Delete();
2919           arr = nullptr;
2920         }
2921         else
2922         {
2923           for ( i = 0; i < num_info; ++i )
2924           {
2925             carr->InsertTypedTuple( i, info[i] );
2926           }
2927           arr = carr;
2928         }
2929 
2930         for ( i = 0; i < num_info; ++i )
2931         {
2932           free(info[i]);
2933         }
2934         free(info);
2935       }
2936       else
2937       {
2938         carr->Delete();
2939         arr = nullptr;
2940       }
2941     }
2942   }
2943   else if ( key.ObjectType == vtkExodusIIReader::QA_RECORDS )
2944   {
2945     // Get Exodus II QA records.  Each QA record is made up of 4 character strings.
2946     vtkIdType num_qa_rec = 0;
2947     float fdum;
2948     char* cdum = nullptr;
2949     int i,j;
2950 
2951     vtkCharArray* carr = vtkCharArray::New();
2952     carr->SetName( "QA_Records" );
2953     carr->SetNumberOfComponents( maxNameLength + 1 );
2954 
2955     if ( ex_inquire( exoid, EX_INQ_QA, &num_qa_rec, &fdum, cdum ) < 0 )
2956     {
2957       vtkErrorMacro( "Unable to get number of QA records from ex_inquire" );
2958       carr->Delete();
2959       arr = nullptr;
2960     }
2961     else
2962     {
2963       if( num_qa_rec > 0 )
2964       {
2965         carr->SetNumberOfTuples(num_qa_rec*4);
2966         char* (*qa_record)[4] = (char* (*)[4]) calloc(num_qa_rec, sizeof(*qa_record));
2967 
2968         for ( i = 0; i < num_qa_rec; ++i )
2969         {
2970           for ( j = 0; j < 4 ; ++j )
2971           { // QA record string length is different than MaxNameLength
2972             qa_record[i][j] = (char *) calloc( ( MAX_STR_LENGTH + 1 ), sizeof(char) );
2973           }
2974         }
2975 
2976         if ( ex_get_qa( exoid, qa_record ) < 0 )
2977         {
2978           vtkErrorMacro( "Unable to read QA records from ex_get_qa");
2979           carr->Delete();
2980           arr = nullptr;
2981         }
2982         else
2983         {
2984           for ( i = 0; i < num_qa_rec; ++i )
2985           {
2986             for ( j = 0; j < 4 ; ++j )
2987             {
2988               carr->InsertTypedTuple( ( i * 4 ) + j, qa_record[i][j] );
2989             }
2990           }
2991           arr = carr;
2992         }
2993 
2994         for ( i = 0; i < num_qa_rec; ++i )
2995         {
2996           for ( j = 0; j < 4 ; ++j )
2997           {
2998             free( qa_record[i][j] );
2999           }
3000         }
3001         free( qa_record );
3002       }
3003       else
3004       {
3005         carr->Delete();
3006         arr = nullptr;
3007       }
3008     }
3009   }
3010   else
3011   {
3012     vtkWarningMacro( "You requested an array for objects of type " << key.ObjectType <<
3013       " which I know nothing about" );
3014     arr = nullptr;
3015   }
3016 
3017   // Even if the array is larger than the allowable cache size, it will keep the most recent insertion.
3018   // So, we delete our reference knowing that the Cache will keep the object "alive" until whatever
3019   // called GetCacheOrRead() references the array. But, once you get an array from GetCacheOrRead(),
3020   // you better start running!
3021   if ( arr )
3022   {
3023     this->Cache->Insert( key, arr );
3024     arr->FastDelete();
3025   }
3026   return arr;
3027 }
3028 
3029 //-----------------------------------------------------------------------------
GetConnTypeIndexFromConnType(int ctyp)3030 int vtkExodusIIReaderPrivate::GetConnTypeIndexFromConnType( int ctyp )
3031 {
3032   int i;
3033   for ( i = 0; i < num_conn_types; ++i )
3034   {
3035     if ( conn_types[i] == ctyp )
3036     {
3037       return i;
3038     }
3039   }
3040   return -1;
3041 }
3042 
3043 //-----------------------------------------------------------------------------
GetObjectTypeIndexFromObjectType(int otyp)3044 int vtkExodusIIReaderPrivate::GetObjectTypeIndexFromObjectType( int otyp )
3045 {
3046   int i;
3047   for ( i = 0; i < num_obj_types; ++i )
3048   {
3049     if ( obj_types[i] == otyp )
3050     {
3051       return i;
3052     }
3053   }
3054   return -1;
3055 }
3056 
3057 //-----------------------------------------------------------------------------
GetNumberOfObjectsAtTypeIndex(int typeIndex)3058 int vtkExodusIIReaderPrivate::GetNumberOfObjectsAtTypeIndex( int typeIndex )
3059 {
3060   if ( typeIndex < 0 )
3061   {
3062     return 0;
3063   }
3064   else if ( typeIndex < 3 )
3065   {
3066     return (int) this->BlockInfo[obj_types[typeIndex]].size();
3067   }
3068   else if ( typeIndex < 8 )
3069   {
3070     return (int) this->SetInfo[obj_types[typeIndex]].size();
3071   }
3072   else if ( typeIndex < 12 )
3073   {
3074     return (int) this->MapInfo[obj_types[typeIndex]].size();
3075   }
3076   return 0;
3077 }
3078 
3079 //-----------------------------------------------------------------------------
GetObjectInfo(int typeIndex,int objectIndex)3080 vtkExodusIIReaderPrivate::ObjectInfoType* vtkExodusIIReaderPrivate::GetObjectInfo( int typeIndex, int objectIndex )
3081 {
3082   if ( typeIndex < 0 )
3083   {
3084     return nullptr;
3085   }
3086   else if ( typeIndex < 3 )
3087   {
3088     return &this->BlockInfo[obj_types[typeIndex]][objectIndex];
3089   }
3090   else if ( typeIndex < 8 )
3091   {
3092     return &this->SetInfo[obj_types[typeIndex]][objectIndex];
3093   }
3094   else if ( typeIndex < 12 )
3095   {
3096     return &this->MapInfo[obj_types[typeIndex]][objectIndex];
3097   }
3098   return nullptr;
3099 }
3100 
3101 //-----------------------------------------------------------------------------
GetSortedObjectInfo(int otyp,int k)3102 vtkExodusIIReaderPrivate::ObjectInfoType* vtkExodusIIReaderPrivate::GetSortedObjectInfo( int otyp, int k )
3103 {
3104   int i = this->GetObjectTypeIndexFromObjectType( otyp );
3105   if ( i < 0 )
3106   {
3107     vtkDebugMacro( "Could not find collection of objects with type " << otyp << "." );
3108     return nullptr;
3109   }
3110   int N = this->GetNumberOfObjectsAtTypeIndex( i );
3111   if ( k < 0 || k >= N )
3112   {
3113     const char* otname = i >= 0 ? objtype_names[i] : "object";
3114     static_cast<void>(otname); // not referenced warning
3115     vtkDebugMacro( "You requested " << otname << " " << k << " in a collection of only " << N << " objects." );
3116     return nullptr;
3117   }
3118   return this->GetObjectInfo( i, this->SortedObjectIndices[otyp][k] );
3119 }
3120 
3121 //-----------------------------------------------------------------------------
GetUnsortedObjectInfo(int otyp,int k)3122 vtkExodusIIReaderPrivate::ObjectInfoType* vtkExodusIIReaderPrivate::GetUnsortedObjectInfo( int otyp, int k )
3123 {
3124   int i = this->GetObjectTypeIndexFromObjectType( otyp );
3125   if ( i < 0 )
3126   {
3127     vtkDebugMacro( "Could not find collection of objects with type " << otyp << "." );
3128     return nullptr;
3129   }
3130   int N = this->GetNumberOfObjectsAtTypeIndex( i );
3131   if ( k < 0 || k >= N )
3132   {
3133     const char* otname = i >= 0 ? objtype_names[i] : "object";
3134     static_cast<void>(otname); // not referenced warning
3135     vtkDebugMacro( "You requested " << otname << " " << k << " in a collection of only " << N << " objects." );
3136     return nullptr;
3137   }
3138   return this->GetObjectInfo( i, k );
3139 }
3140 
3141 
3142 //-----------------------------------------------------------------------------
GetBlockIndexFromFileGlobalId(int otyp,int refId)3143 int vtkExodusIIReaderPrivate::GetBlockIndexFromFileGlobalId( int otyp, int refId )
3144 {
3145   std::vector<BlockInfoType>::iterator bi;
3146   int i = 0;
3147   for ( bi = this->BlockInfo[otyp].begin(); bi != this->BlockInfo[otyp].end(); ++bi, ++i )
3148   {
3149     if ( refId >= bi->FileOffset && refId <= bi->FileOffset + bi->Size )
3150       return i;
3151   }
3152   return -1;
3153 }
3154 
3155 //-----------------------------------------------------------------------------
GetBlockFromFileGlobalId(int otyp,int refId)3156 vtkExodusIIReaderPrivate::BlockInfoType* vtkExodusIIReaderPrivate::GetBlockFromFileGlobalId( int otyp, int refId )
3157 {
3158   int blk = this->GetBlockIndexFromFileGlobalId( otyp, refId );
3159   if ( blk >= 0 )
3160   {
3161     return &this->BlockInfo[otyp][blk];
3162   }
3163   return nullptr;
3164 }
3165 
3166 //-----------------------------------------------------------------------------
GetSqueezePointId(BlockSetInfoType * bsinfop,int i)3167 vtkIdType vtkExodusIIReaderPrivate::GetSqueezePointId( BlockSetInfoType* bsinfop, int i )
3168 {
3169   if (i<0)
3170   {
3171     vtkGenericWarningMacro("Invalid point id: " << i
3172       << ". Data file may be incorrect.");
3173     i = 0;
3174   }
3175 
3176   vtkIdType x;
3177   std::map<vtkIdType,vtkIdType>::iterator it = bsinfop->PointMap.find( i );
3178   if ( it == bsinfop->PointMap.end() )
3179   { // Nothing found; add a new entry to the map.
3180     x = bsinfop->NextSqueezePoint ++ ;
3181     bsinfop->PointMap[i] = x;
3182     bsinfop->ReversePointMap[x] = i;
3183   }
3184   else
3185   {
3186     x = it->second;
3187   }
3188   return x;
3189 }
3190 
3191 //-----------------------------------------------------------------------------
DetermineVtkCellType(BlockInfoType & binfo)3192 void vtkExodusIIReaderPrivate::DetermineVtkCellType( BlockInfoType& binfo )
3193 {
3194   vtkStdString elemType( vtksys::SystemTools::UpperCase( binfo.TypeName ) );
3195 
3196   // Check for quadratic elements
3197   if ((elemType.substr(0,3) == "TRI") &&           (binfo.BdsPerEntry[0] == 6))
3198     { binfo.CellType=VTK_QUADRATIC_TRIANGLE;       binfo.PointsPerCell = 6; }
3199   else if ((elemType.substr(0,3) == "SHE") &&      (binfo.BdsPerEntry[0] == 8))
3200     { binfo.CellType=VTK_QUADRATIC_QUAD;           binfo.PointsPerCell = 8; }
3201   else if ((elemType.substr(0,3) == "SHE") &&      (binfo.BdsPerEntry[0] == 9))
3202     { binfo.CellType=VTK_QUADRATIC_QUAD;           binfo.PointsPerCell = 8; }
3203   else if ((elemType.substr(0,3) == "TET") &&      (binfo.BdsPerEntry[0] == 10))
3204     { binfo.CellType=VTK_QUADRATIC_TETRA;          binfo.PointsPerCell = 10; }
3205   else if ((elemType.substr(0,3) == "TET") &&      (binfo.BdsPerEntry[0] == 11))
3206     { binfo.CellType=VTK_QUADRATIC_TETRA;          binfo.PointsPerCell = 10; }
3207   else if ((elemType.substr(0,3) == "TET") &&      (binfo.BdsPerEntry[0] == 15))
3208     { binfo.CellType=VTK_LAGRANGE_TETRAHEDRON;     binfo.PointsPerCell = 15; }
3209   else if ((elemType.substr(0,3) == "WED") &&      (binfo.BdsPerEntry[0] == 15))
3210     { binfo.CellType=VTK_QUADRATIC_WEDGE;          binfo.PointsPerCell = 15; }
3211   else if ((elemType.substr(0,3) == "WED") &&      (binfo.BdsPerEntry[0] == 21))
3212     { binfo.CellType=VTK_LAGRANGE_WEDGE;           binfo.PointsPerCell = 21; }
3213   else if ((elemType.substr(0,3) == "HEX") &&      (binfo.BdsPerEntry[0] == 20))
3214     { binfo.CellType=VTK_QUADRATIC_HEXAHEDRON;     binfo.PointsPerCell = 20; }
3215   else if ((elemType.substr(0,3) == "HEX") &&      (binfo.BdsPerEntry[0] == 21))
3216     { binfo.CellType=VTK_QUADRATIC_HEXAHEDRON;     binfo.PointsPerCell = 20; }
3217   else if ((elemType.substr(0,3) == "HEX") &&      (binfo.BdsPerEntry[0] == 27))
3218     { binfo.CellType=VTK_TRIQUADRATIC_HEXAHEDRON;  binfo.PointsPerCell = 27; }
3219   else if ((elemType.substr(0,3) == "QUA") &&      (binfo.BdsPerEntry[0] == 8))
3220     { binfo.CellType=VTK_QUADRATIC_QUAD;           binfo.PointsPerCell = 8; }
3221   else if ((elemType.substr(0,3) == "QUA") &&      (binfo.BdsPerEntry[0] == 9))
3222     { binfo.CellType=VTK_BIQUADRATIC_QUAD;         binfo.PointsPerCell = 9; }
3223   else if ((elemType.substr(0,3) == "TRU") &&      (binfo.BdsPerEntry[0] == 3))
3224     { binfo.CellType=VTK_QUADRATIC_EDGE;           binfo.PointsPerCell = 3; }
3225   else if ((elemType.substr(0,3) == "BEA") &&      (binfo.BdsPerEntry[0] == 3))
3226     { binfo.CellType=VTK_QUADRATIC_EDGE;           binfo.PointsPerCell = 3; }
3227   else if ((elemType.substr(0,3) == "BAR") &&      (binfo.BdsPerEntry[0] == 3))
3228     { binfo.CellType=VTK_QUADRATIC_EDGE;           binfo.PointsPerCell = 3; }
3229   else if ((elemType.substr(0,3) == "EDG") &&      (binfo.BdsPerEntry[0] == 3))
3230     { binfo.CellType=VTK_QUADRATIC_EDGE;           binfo.PointsPerCell = 3; }
3231   else if ((elemType.substr(0,3) == "PYR") &&      (binfo.BdsPerEntry[0] == 13))
3232     { binfo.CellType=VTK_QUADRATIC_PYRAMID;        binfo.PointsPerCell = 13; }
3233 
3234   // Check for regular elements
3235   else if (elemType.substr(0,3) == "CIR") { binfo.CellType = VTK_VERTEX;     binfo.PointsPerCell = 1; }
3236   else if (elemType.substr(0,3) == "SPH") { binfo.CellType = VTK_VERTEX;     binfo.PointsPerCell = 1; }
3237   else if (elemType.substr(0,3) == "BAR") { binfo.CellType = VTK_LINE;       binfo.PointsPerCell = 2; }
3238   else if (elemType.substr(0,3) == "TRU") { binfo.CellType = VTK_LINE;       binfo.PointsPerCell = 2; }
3239   else if (elemType.substr(0,3) == "BEA") { binfo.CellType = VTK_LINE;       binfo.PointsPerCell = 2; }
3240   else if (elemType.substr(0,3) == "EDG") { binfo.CellType = VTK_LINE;       binfo.PointsPerCell = 2; }
3241   else if (elemType.substr(0,3) == "TRI") { binfo.CellType = VTK_TRIANGLE;   binfo.PointsPerCell = 3; }
3242   else if (elemType.substr(0,3) == "QUA") { binfo.CellType = VTK_QUAD;       binfo.PointsPerCell = 4; }
3243   else if (elemType.substr(0,3) == "TET") { binfo.CellType = VTK_TETRA;      binfo.PointsPerCell = 4; }
3244   else if (elemType.substr(0,3) == "PYR") { binfo.CellType = VTK_PYRAMID;    binfo.PointsPerCell = 5; }
3245   else if (elemType.substr(0,3) == "WED") { binfo.CellType = VTK_WEDGE;      binfo.PointsPerCell = 6; }
3246   else if (elemType.substr(0,3) == "HEX") { binfo.CellType = VTK_HEXAHEDRON; binfo.PointsPerCell = 8; }
3247   else if (elemType.substr(0,3) == "NSI") { binfo.CellType = VTK_POLYGON;    binfo.PointsPerCell = 0; }
3248   else if (elemType.substr(0,3) == "NFA") { binfo.CellType = VTK_POLYHEDRON; binfo.PointsPerCell = 0; }
3249   else if ((elemType.substr(0,3) == "SHE") && (binfo.BdsPerEntry[0] == 3))
3250     { binfo.CellType = VTK_TRIANGLE;           binfo.PointsPerCell = 3; }
3251   else if ((elemType.substr(0,3) == "SHE") && (binfo.BdsPerEntry[0] == 4))
3252     { binfo.CellType = VTK_QUAD;               binfo.PointsPerCell = 4; }
3253   else if ((elemType.substr(0,8) == "STRAIGHT") && (binfo.BdsPerEntry[0] == 2 ))
3254     { binfo.CellType = VTK_LINE;                    binfo.PointsPerCell = 2; }
3255   else if (elemType.substr(0,3) == "SUP")
3256   {
3257     binfo.CellType=VTK_POLY_VERTEX;
3258     binfo.PointsPerCell = binfo.BdsPerEntry[0];
3259   }
3260   else if ((elemType.substr(0,4) == "NULL") && (binfo.Size == 0))
3261   {
3262     (void)binfo; // silently ignore empty element blocks
3263   }
3264   else
3265   {
3266     vtkErrorMacro("Unsupported element type: " << elemType.c_str());
3267   }
3268 
3269   //cell types not currently handled
3270   //quadratic wedge - 15,16 nodes
3271   //quadratic pyramid - 13 nodes
3272 }
3273 
3274 //-----------------------------------------------------------------------------
FindArrayInfoByName(int otyp,const char * name)3275 vtkExodusIIReaderPrivate::ArrayInfoType* vtkExodusIIReaderPrivate::FindArrayInfoByName( int otyp, const char* name )
3276 {
3277   std::vector<ArrayInfoType>::iterator ai;
3278   for ( ai = this->ArrayInfo[otyp].begin(); ai != this->ArrayInfo[otyp].end(); ++ai )
3279   {
3280     if ( ai->Name == name )
3281       return &(*ai);
3282   }
3283   return nullptr;
3284 }
3285 
3286 //-----------------------------------------------------------------------------
IsObjectTypeBlock(int otyp)3287 int vtkExodusIIReaderPrivate::IsObjectTypeBlock( int otyp )
3288 {
3289   return (otyp == vtkExodusIIReader::ELEM_BLOCK || otyp == vtkExodusIIReader::EDGE_BLOCK || otyp == vtkExodusIIReader::FACE_BLOCK);
3290 }
3291 
3292 //-----------------------------------------------------------------------------
IsObjectTypeSet(int otyp)3293 int vtkExodusIIReaderPrivate::IsObjectTypeSet( int otyp )
3294 {
3295   return (otyp == vtkExodusIIReader::ELEM_SET || otyp == vtkExodusIIReader::EDGE_SET || otyp == vtkExodusIIReader::FACE_SET || otyp == vtkExodusIIReader::NODE_SET || otyp == vtkExodusIIReader::SIDE_SET);
3296 }
3297 
3298 //-----------------------------------------------------------------------------
IsObjectTypeMap(int otyp)3299 int vtkExodusIIReaderPrivate::IsObjectTypeMap( int otyp )
3300 {
3301   return (otyp == vtkExodusIIReader::ELEM_MAP || otyp == vtkExodusIIReader::EDGE_MAP || otyp == vtkExodusIIReader::FACE_MAP || otyp == vtkExodusIIReader::NODE_MAP);
3302 }
3303 
3304 //-----------------------------------------------------------------------------
GetObjectTypeFromMapType(int mtyp)3305 int vtkExodusIIReaderPrivate::GetObjectTypeFromMapType( int mtyp )
3306 {
3307   switch (mtyp)
3308   {
3309   case vtkExodusIIReader::ELEM_MAP:
3310     return vtkExodusIIReader::ELEM_BLOCK;
3311   case vtkExodusIIReader::FACE_MAP:
3312     return vtkExodusIIReader::FACE_BLOCK;
3313   case vtkExodusIIReader::EDGE_MAP:
3314     return vtkExodusIIReader::EDGE_BLOCK;
3315   case vtkExodusIIReader::NODE_MAP:
3316     return vtkExodusIIReader::NODAL;
3317   }
3318   return -1;
3319 }
3320 
3321 //-----------------------------------------------------------------------------
GetMapTypeFromObjectType(int otyp)3322 int vtkExodusIIReaderPrivate::GetMapTypeFromObjectType( int otyp )
3323 {
3324   switch (otyp)
3325   {
3326   case vtkExodusIIReader::ELEM_BLOCK:
3327     return vtkExodusIIReader::ELEM_MAP;
3328   case vtkExodusIIReader::FACE_BLOCK:
3329     return vtkExodusIIReader::FACE_MAP;
3330   case vtkExodusIIReader::EDGE_BLOCK:
3331     return vtkExodusIIReader::EDGE_MAP;
3332   case vtkExodusIIReader::NODAL:
3333     return vtkExodusIIReader::NODE_MAP;
3334   }
3335   return -1;
3336 }
3337 
3338 //-----------------------------------------------------------------------------
GetTemporalTypeFromObjectType(int otyp)3339 int vtkExodusIIReaderPrivate::GetTemporalTypeFromObjectType( int otyp )
3340 {
3341   switch (otyp)
3342   {
3343   case vtkExodusIIReader::ELEM_BLOCK:
3344     return vtkExodusIIReader::ELEM_BLOCK_TEMPORAL;
3345   //case vtkExodusIIReader::FACE_BLOCK:
3346   //  return vtkExodusIIReader::FACE_MAP;
3347   //case vtkExodusIIReader::EDGE_BLOCK:
3348   //  return vtkExodusIIReader::EDGE_MAP;
3349   case vtkExodusIIReader::NODAL:
3350     return vtkExodusIIReader::NODAL_TEMPORAL;
3351   case vtkExodusIIReader::GLOBAL:
3352     return vtkExodusIIReader::GLOBAL_TEMPORAL;
3353   }
3354   return -1;
3355 }
3356 
3357 //-----------------------------------------------------------------------------
GetSetTypeFromSetConnType(int sctyp)3358 int vtkExodusIIReaderPrivate::GetSetTypeFromSetConnType( int sctyp )
3359 {
3360   switch ( sctyp )
3361   {
3362   case vtkExodusIIReader::NODE_SET_CONN:
3363     return vtkExodusIIReader::NODE_SET;
3364   case vtkExodusIIReader::EDGE_SET_CONN:
3365     return vtkExodusIIReader::EDGE_SET;
3366   case vtkExodusIIReader::FACE_SET_CONN:
3367     return vtkExodusIIReader::FACE_SET;
3368   case vtkExodusIIReader::SIDE_SET_CONN:
3369     return vtkExodusIIReader::SIDE_SET;
3370   case vtkExodusIIReader::ELEM_SET_CONN:
3371     return vtkExodusIIReader::ELEM_SET;
3372   }
3373   return -1;
3374 }
3375 
3376 //-----------------------------------------------------------------------------
GetBlockConnTypeFromBlockType(int btyp)3377 int vtkExodusIIReaderPrivate::GetBlockConnTypeFromBlockType( int btyp )
3378 {
3379   switch ( btyp )
3380   {
3381   case vtkExodusIIReader::EDGE_BLOCK:
3382     return vtkExodusIIReader::EDGE_BLOCK_CONN;
3383   case vtkExodusIIReader::FACE_BLOCK:
3384     return vtkExodusIIReader::FACE_BLOCK_CONN;
3385   case vtkExodusIIReader::ELEM_BLOCK:
3386     return vtkExodusIIReader::ELEM_BLOCK_ELEM_CONN;
3387   }
3388   return -1;
3389 }
3390 
3391 //-----------------------------------------------------------------------------
RemoveBeginningAndTrailingSpaces(int len,char ** names,int maxNameLength)3392 void vtkExodusIIReaderPrivate::RemoveBeginningAndTrailingSpaces(
3393   int len, char **names, int maxNameLength )
3394 {
3395   for (int i=0; i<len; i++)
3396   {
3397     char *c = names[i];
3398     int nmlen = (int)strlen(c);
3399 
3400     char *cbegin = c;
3401     char *cend = c + nmlen - 1;
3402 
3403     // remove spaces or non-printing character from start and end
3404 
3405     for (int j=0; j<nmlen; j++)
3406     {
3407       if (!isgraph(*cbegin)) cbegin++;
3408       else break;
3409     }
3410 
3411     for (int j=0; j<nmlen; j++)
3412     {
3413       if (!isgraph(*cend)) cend--;
3414       else break;
3415     }
3416 
3417     if (cend < cbegin)
3418     {
3419       snprintf(names[i], maxNameLength + 1, "null_%d", i);
3420       continue;
3421     }
3422 
3423     int newlen = cend - cbegin + 1;
3424 
3425     if (newlen < nmlen)
3426     {
3427       for (int j=0; j<newlen; j++)
3428       {
3429         *c++ = *cbegin++;
3430       }
3431       *c = '\0';
3432     }
3433   }
3434 }
3435 
3436 //-----------------------------------------------------------------------------
ClearConnectivityCaches()3437 void vtkExodusIIReaderPrivate::ClearConnectivityCaches()
3438 {
3439   std::map<int,std::vector<BlockInfoType> >::iterator blksit;
3440   for ( blksit = this->BlockInfo.begin(); blksit != this->BlockInfo.end(); ++ blksit )
3441   {
3442     std::vector<BlockInfoType>::iterator blkit;
3443     for ( blkit = blksit->second.begin(); blkit != blksit->second.end(); ++ blkit )
3444     {
3445       if ( blkit->CachedConnectivity )
3446       {
3447         blkit->CachedConnectivity->Delete();
3448         blkit->CachedConnectivity = nullptr;
3449       }
3450     }
3451   }
3452   std::map<int,std::vector<SetInfoType> >::iterator setsit;
3453   for ( setsit = this->SetInfo.begin(); setsit != this->SetInfo.end(); ++ setsit )
3454   {
3455     std::vector<SetInfoType>::iterator setit;
3456     for ( setit = setsit->second.begin(); setit != setsit->second.end(); ++ setit )
3457     {
3458       if ( setit->CachedConnectivity )
3459       {
3460         setit->CachedConnectivity->Delete();
3461         setit->CachedConnectivity = nullptr;
3462       }
3463     }
3464   }
3465 }
3466 
3467 //-----------------------------------------------------------------------------
SetParser(vtkExodusIIReaderParser * parser)3468 void vtkExodusIIReaderPrivate::SetParser(vtkExodusIIReaderParser *parser)
3469 {
3470   // Properly sets the parser object but does not call Modified.  The parser
3471   // represents the state of the data in files, not the state of this object.
3472   if (this->Parser != parser)
3473   {
3474     vtkExodusIIReaderParser *oldParser = this->Parser;
3475     this->Parser = parser;
3476     if (this->Parser) this->Parser->Register(this);
3477     if (oldParser) oldParser->UnRegister(this);
3478   }
3479 }
3480 
3481 //-----------------------------------------------------------------------------
GetNumberOfParts()3482 int vtkExodusIIReaderPrivate::GetNumberOfParts()
3483 {
3484   return static_cast<int>( this->PartInfo.size() );
3485 }
3486 
3487 //-----------------------------------------------------------------------------
GetPartName(int idx)3488 const char* vtkExodusIIReaderPrivate::GetPartName(int idx)
3489 {
3490   return this->PartInfo[idx].Name.c_str();
3491 }
3492 
3493 //-----------------------------------------------------------------------------
GetPartBlockInfo(int idx)3494 const char* vtkExodusIIReaderPrivate::GetPartBlockInfo(int idx)
3495 {
3496   char buffer[80];
3497   vtkStdString blocks;
3498   std::vector<int> blkIndices = this->PartInfo[idx].BlockIndices;
3499   for (unsigned int i=0;i<blkIndices.size();i++)
3500   {
3501     snprintf(buffer,sizeof(buffer),"%d, ",blkIndices[i]);
3502     blocks += buffer;
3503   }
3504 
3505   blocks.erase(blocks.size()-2,blocks.size()-1);
3506 
3507   return blocks.c_str();
3508 }
3509 
3510 //-----------------------------------------------------------------------------
GetPartStatus(int idx)3511 int vtkExodusIIReaderPrivate::GetPartStatus(int idx)
3512 {
3513   //a part is only active if all its blocks are active
3514   std::vector<int> blkIndices = this->PartInfo[idx].BlockIndices;
3515   for (unsigned int i=0;i<blkIndices.size();i++)
3516   {
3517     if (!this->GetUnsortedObjectStatus(vtkExodusIIReader::ELEM_BLOCK,blkIndices[i]))
3518     {
3519       return 0;
3520     }
3521   }
3522   return 1;
3523 }
3524 
3525 //-----------------------------------------------------------------------------
GetPartStatus(const vtkStdString & name)3526 int vtkExodusIIReaderPrivate::GetPartStatus(const vtkStdString& name)
3527 {
3528   for (unsigned int i=0;i<this->PartInfo.size();i++)
3529   {
3530     if (this->PartInfo[i].Name==name)
3531     {
3532       return this->GetPartStatus(i);
3533     }
3534   }
3535   return -1;
3536 }
3537 
3538 //-----------------------------------------------------------------------------
SetPartStatus(int idx,int on)3539 void vtkExodusIIReaderPrivate::SetPartStatus(int idx, int on)
3540 {
3541   //update the block status for all the blocks in this part
3542   std::vector<int> blkIndices = this->PartInfo[idx].BlockIndices;
3543   for (unsigned int i=0;i<blkIndices.size();i++)
3544   {
3545     this->SetUnsortedObjectStatus(vtkExodusIIReader::ELEM_BLOCK, blkIndices[i], on);
3546   }
3547 }
3548 
3549 //-----------------------------------------------------------------------------
SetPartStatus(const vtkStdString & name,int flag)3550 void vtkExodusIIReaderPrivate::SetPartStatus(const vtkStdString& name, int flag)
3551 {
3552   for(unsigned int idx=0; idx<this->PartInfo.size(); ++idx)
3553   {
3554     if ( name == this->PartInfo[idx].Name )
3555     {
3556       this->SetPartStatus(idx,flag);
3557       return;
3558     }
3559   }
3560 }
3561 
3562 //-----------------------------------------------------------------------------
GetNumberOfMaterials()3563 int vtkExodusIIReaderPrivate::GetNumberOfMaterials()
3564 {
3565   return static_cast<int>( this->MaterialInfo.size() );
3566 }
3567 
3568 //-----------------------------------------------------------------------------
GetMaterialName(int idx)3569 const char* vtkExodusIIReaderPrivate::GetMaterialName(int idx)
3570 {
3571   return this->MaterialInfo[idx].Name.c_str();
3572 }
3573 
3574 //-----------------------------------------------------------------------------
GetMaterialStatus(int idx)3575 int vtkExodusIIReaderPrivate::GetMaterialStatus(int idx)
3576 {
3577   std::vector<int> blkIndices = this->MaterialInfo[idx].BlockIndices;
3578 
3579   for (unsigned int i=0;i<blkIndices.size();i++)
3580   {
3581     if (!this->GetUnsortedObjectStatus(vtkExodusIIReader::ELEM_BLOCK,blkIndices[i]))
3582     {
3583       return 0;
3584     }
3585   }
3586   return 1;
3587 }
3588 
3589 //-----------------------------------------------------------------------------
GetMaterialStatus(const vtkStdString & name)3590 int vtkExodusIIReaderPrivate::GetMaterialStatus(const vtkStdString& name)
3591 {
3592   for (unsigned int i=0;i<this->MaterialInfo.size();i++)
3593   {
3594     if (this->MaterialInfo[i].Name==name)
3595     {
3596       return this->GetMaterialStatus(i);
3597     }
3598   }
3599   return -1;
3600 }
3601 
3602 //-----------------------------------------------------------------------------
SetMaterialStatus(int idx,int on)3603 void vtkExodusIIReaderPrivate::SetMaterialStatus(int idx, int on)
3604 {
3605   //update the block status for all the blocks in this material
3606   std::vector<int> blkIndices = this->MaterialInfo[idx].BlockIndices;
3607 
3608   for (unsigned int i=0;i<blkIndices.size();i++)
3609   {
3610     this->SetUnsortedObjectStatus(vtkExodusIIReader::ELEM_BLOCK,blkIndices[i],on);
3611   }
3612 }
3613 
3614 //-----------------------------------------------------------------------------
SetMaterialStatus(const vtkStdString & name,int flag)3615 void vtkExodusIIReaderPrivate::SetMaterialStatus(const vtkStdString& name, int flag)
3616 {
3617   for(unsigned int idx=0; idx<this->MaterialInfo.size(); ++idx)
3618   {
3619     if ( name == this->MaterialInfo[idx].Name )
3620     {
3621         this->SetMaterialStatus(idx,flag);
3622         return;
3623     }
3624   }
3625 }
3626 
3627 //-----------------------------------------------------------------------------
GetNumberOfAssemblies()3628 int vtkExodusIIReaderPrivate::GetNumberOfAssemblies()
3629 {
3630   return static_cast<int>( this->AssemblyInfo.size() );
3631 }
3632 
3633 //-----------------------------------------------------------------------------
GetAssemblyName(int idx)3634 const char* vtkExodusIIReaderPrivate::GetAssemblyName(int idx)
3635 {
3636   return this->AssemblyInfo[idx].Name.c_str();
3637 }
3638 
3639 //-----------------------------------------------------------------------------
GetAssemblyStatus(int idx)3640 int vtkExodusIIReaderPrivate::GetAssemblyStatus(int idx)
3641 {
3642   std::vector<int> blkIndices = this->AssemblyInfo[idx].BlockIndices;
3643 
3644   for (unsigned int i=0;i<blkIndices.size();i++)
3645   {
3646     if (!this->GetUnsortedObjectStatus(vtkExodusIIReader::ELEM_BLOCK,blkIndices[i]))
3647     {
3648       return 0;
3649     }
3650   }
3651   return 1;
3652 }
3653 
3654 //-----------------------------------------------------------------------------
GetAssemblyStatus(const vtkStdString & name)3655 int vtkExodusIIReaderPrivate::GetAssemblyStatus(const vtkStdString& name)
3656 {
3657   for (unsigned int i=0;i<this->AssemblyInfo.size();i++)
3658   {
3659     if (this->AssemblyInfo[i].Name==name)
3660     {
3661       return this->GetAssemblyStatus(i);
3662     }
3663   }
3664   return -1;
3665 }
3666 
3667 //-----------------------------------------------------------------------------
SetAssemblyStatus(int idx,int on)3668 void vtkExodusIIReaderPrivate::SetAssemblyStatus(int idx, int on)
3669 {
3670   std::vector<int> blkIndices = this->AssemblyInfo[idx].BlockIndices;
3671 
3672   //update the block status for all the blocks in this material
3673   for (unsigned int i=0;i<blkIndices.size();i++)
3674   {
3675     this->SetUnsortedObjectStatus(vtkExodusIIReader::ELEM_BLOCK,blkIndices[i],on);
3676   }
3677 }
3678 
3679 //-----------------------------------------------------------------------------
SetAssemblyStatus(const vtkStdString & name,int flag)3680 void vtkExodusIIReaderPrivate::SetAssemblyStatus(const vtkStdString& name, int flag)
3681 {
3682   for(unsigned int idx=0; idx<this->AssemblyInfo.size(); ++idx)
3683   {
3684     if ( name == this->AssemblyInfo[idx].Name )
3685     {
3686       this->SetAssemblyStatus(idx,flag);
3687       return;
3688     }
3689   }
3690 }
3691 
3692 //-----------------------------------------------------------------------------
3693 // Normally, this would be below with all the other vtkExodusIIReader member definitions,
3694 // but the PrintSelf test script is really lame.
PrintSelf(ostream & os,vtkIndent indent)3695 void vtkExodusIIReader::PrintSelf( ostream& os, vtkIndent indent )
3696 {
3697   this->Superclass::PrintSelf( os, indent );
3698   os << indent << "FileName: " << ( this->FileName ? this->FileName : "(null)" ) << "\n";
3699   os << indent << "XMLFileName: " << ( this->XMLFileName ? this->XMLFileName : "(null)" ) << "\n";
3700   os << indent << "DisplayType: " << this->DisplayType << "\n";
3701   os << indent << "TimeStep: " << this->TimeStep << "\n";
3702   os << indent << "TimeStepRange: [" << this->TimeStepRange[0] << ", " << this->TimeStepRange[1] << "]\n";
3703   os << indent << "ModeShapesRange:  [ "
3704     << this->GetModeShapesRange()[0] << ", " << this->GetModeShapesRange()[1] << "]\n";
3705   os << indent << "IgnoreFileTime: " << this->GetIgnoreFileTime() << "\n";
3706   os << indent << "SILUpdateStamp: " << this->SILUpdateStamp << "\n";
3707   if ( this->Metadata )
3708   {
3709     os << indent << "Metadata:\n";
3710     this->Metadata->PrintData( os, indent.GetNextIndent() );
3711   }
3712   else
3713   {
3714     os << indent << "Metadata: (null)\n";
3715   }
3716 }
3717 
3718 
PrintData(ostream & os,vtkIndent indent)3719 void vtkExodusIIReaderPrivate::PrintData( ostream& os, vtkIndent indent )
3720 {
3721   //this->Superclass::Print Self( os, indent );
3722   os << indent << "Exoid: " << this->Exoid << "\n";
3723   os << indent << "AppWordSize: " << this->AppWordSize << "\n";
3724   os << indent << "DiskWordSize: " << this->DiskWordSize << "\n";
3725   os << indent << "ExodusVersion: " << this->ExodusVersion << "\n";
3726   os << indent << "ModelParameters:\n";
3727 
3728   vtkIndent inden2 = indent.GetNextIndent();
3729   os << inden2 << "Title: " << this->ModelParameters.title << "\n";
3730   os << inden2 << "Dimension: " << this->ModelParameters.num_dim << "\n";
3731   os << inden2 << "Nodes: " << this->ModelParameters.num_nodes << "\n";
3732   os << inden2 << "Edges: " << this->ModelParameters.num_edge << "\n";
3733   os << inden2 << "Faces: " << this->ModelParameters.num_face << "\n";
3734   os << inden2 << "Elements: " << this->ModelParameters.num_elem << "\n";
3735   os << inden2 << "Edge Blocks: " << this->ModelParameters.num_edge_blk << "\n";
3736   os << inden2 << "Face Blocks: " << this->ModelParameters.num_face_blk << "\n";
3737   os << inden2 << "Element Blocks: " << this->ModelParameters.num_elem_blk << "\n";
3738   os << inden2 << "Node Sets: " << this->ModelParameters.num_node_sets << "\n";
3739   os << inden2 << "Edge Sets: " << this->ModelParameters.num_edge_sets << "\n";
3740   os << inden2 << "Face Sets: " << this->ModelParameters.num_face_sets << "\n";
3741   os << inden2 << "Side Sets: " << this->ModelParameters.num_side_sets << "\n";
3742   os << inden2 << "Element Sets: " << this->ModelParameters.num_elem_sets << "\n";
3743   os << inden2 << "Node Maps: " << this->ModelParameters.num_node_maps << "\n";
3744   os << inden2 << "Edge Maps: " << this->ModelParameters.num_edge_maps << "\n";
3745   os << inden2 << "Face Maps: " << this->ModelParameters.num_face_maps << "\n";
3746   os << inden2 << "Element Maps: " << this->ModelParameters.num_elem_maps << "\n";
3747 
3748   os << indent << "Time steps (" << this->Times.size() << "):";
3749   int i;
3750   for ( i = 0; i < (int)this->Times.size(); ++i )
3751   {
3752     os << " " << this->Times[i];
3753   }
3754   os << "\n";
3755   os << indent << "HasModeShapes: " << this->HasModeShapes << "\n";
3756   os << indent << "ModeShapeTime: " << this->ModeShapeTime << "\n";
3757   os << indent << "AnimateModeShapes: " << this->AnimateModeShapes << "\n";
3758 
3759   // Print nodal variables
3760   if ( !this->ArrayInfo[ vtkExodusIIReader::NODAL ].empty() )
3761   {
3762     os << indent << "Nodal Arrays:\n";
3763     std::vector<ArrayInfoType>::iterator ai;
3764     for ( ai = this->ArrayInfo[ vtkExodusIIReader::NODAL ].begin(); ai != this->ArrayInfo[ vtkExodusIIReader::NODAL ].end(); ++ai )
3765     {
3766       printArray( os, indent, vtkExodusIIReader::NODAL, *ai );
3767     }
3768   }
3769 
3770   // Print blocks
3771   os << indent << "Blocks:\n";
3772   std::map<int,std::vector<BlockInfoType> >::iterator bti;
3773   for ( bti = this->BlockInfo.begin(); bti != this->BlockInfo.end(); ++bti )
3774   {
3775     std::vector<BlockInfoType>::iterator bi;
3776     for ( bi = bti->second.begin(); bi != bti->second.end(); ++bi )
3777     {
3778       printBlock( os, indent.GetNextIndent(), bti->first, *bi );
3779     }
3780     if ( !this->ArrayInfo[ bti->first ].empty() )
3781     {
3782       os << indent << "    Results variables:\n";
3783       std::vector<ArrayInfoType>::iterator ai;
3784       for ( ai = this->ArrayInfo[ bti->first ].begin(); ai != this->ArrayInfo[ bti->first ].end(); ++ai )
3785       {
3786         printArray( os, indent.GetNextIndent(), bti->first, *ai );
3787       }
3788     }
3789   }
3790 
3791   // Print sets
3792   os << indent << "Sets:\n";
3793   std::map<int,std::vector<SetInfoType> >::iterator sti;
3794   for ( sti = this->SetInfo.begin(); sti != this->SetInfo.end(); ++sti )
3795   {
3796     std::vector<SetInfoType>::iterator si;
3797     for ( si = sti->second.begin(); si != sti->second.end(); ++si )
3798     {
3799       printSet( os, indent.GetNextIndent(), sti->first, *si );
3800     }
3801     if ( !this->ArrayInfo[ sti->first ].empty() )
3802     {
3803       os << indent << "    Results variables:\n";
3804       std::vector<ArrayInfoType>::iterator ai;
3805       for ( ai = this->ArrayInfo[ sti->first ].begin(); ai != this->ArrayInfo[ sti->first ].end(); ++ai )
3806       {
3807         printArray( os, indent.GetNextIndent(), sti->first, *ai );
3808       }
3809     }
3810   }
3811 
3812   // Print maps
3813   os << indent << "Maps:\n";
3814   std::map<int,std::vector<MapInfoType> >::iterator mti;
3815   for ( mti = this->MapInfo.begin(); mti != this->MapInfo.end(); ++mti )
3816   {
3817     std::vector<MapInfoType>::iterator mi;
3818     for ( mi = mti->second.begin(); mi != mti->second.end(); ++mi )
3819     {
3820       printMap( os, indent.GetNextIndent(), mti->first, *mi );
3821     }
3822   }
3823 
3824   os << indent << "Array Cache:\n";
3825   this->Cache->PrintSelf( os, inden2 );
3826 
3827   os << indent << "SqueezePoints: " << this->SqueezePoints << "\n";
3828   os << indent << "ApplyDisplacements: " << this->ApplyDisplacements << "\n";
3829   os << indent << "DisplacementMagnitude: " << this->DisplacementMagnitude << "\n";
3830   os << indent << "GenerateObjectIdArray: " << this->GenerateObjectIdArray << "\n";
3831   os << indent << "GenerateFileIdArray: " << this->GenerateFileIdArray << "\n";
3832   os << indent << "FileId: " << this->FileId << "\n";
3833 }
3834 
OpenFile(const char * filename)3835 int vtkExodusIIReaderPrivate::OpenFile( const char* filename )
3836 {
3837   if ( ! filename || ! strlen( filename ) )
3838   {
3839     vtkErrorMacro( "Exodus filename pointer was nullptr or pointed to an empty string." );
3840     return 0;
3841   }
3842 
3843   if ( this->Exoid >= 0 )
3844   {
3845     this->CloseFile();
3846   }
3847 
3848   this->Exoid = ex_open( filename, EX_READ,
3849     &this->AppWordSize, &this->DiskWordSize, &this->ExodusVersion );
3850   if ( this->Exoid <= 0 )
3851   {
3852     vtkErrorMacro( "Unable to open \"" << filename << "\" for reading" );
3853     return 0;
3854   }
3855 
3856 #ifdef VTK_USE_64BIT_IDS
3857   // Set the exodus API to always return integer types as 64-bit
3858   // without this call, large exodus files are not supported (which
3859   // is ok in 32 bit ids mode since VTK's ids can't fit the data).
3860   ex_set_int64_status(this->Exoid, EX_ALL_INT64_API);
3861 #endif
3862   // figure out the longest string name we have and then set that to be the
3863   // maximum length for the variable names. This is called every time that the reader
3864   // is updated so we don't have to worry about setting the global max_name_length variable.
3865   // this is because in our current version of the ExodusII libraries the exo Id isn't used
3866   // in the ex_set_max_name_length() function.
3867   ex_set_max_name_length(this->Exoid, this->Parent->GetMaxNameLength());
3868 
3869   vtkIdType numNodesInFile;
3870   char dummyChar;
3871   float dummyFloat;
3872   ex_inquire(this->Exoid, EX_INQ_NODES, &numNodesInFile, &dummyFloat, &dummyChar);
3873 
3874   return 1;
3875 }
3876 
CloseFile()3877 int vtkExodusIIReaderPrivate::CloseFile()
3878 {
3879   if ( this->Exoid >= 0 )
3880   {
3881     VTK_EXO_FUNC( ex_close( this->Exoid ), "Could not close an open file (" << this->Exoid << ")" );
3882     this->Exoid = -1;
3883   }
3884   return 0;
3885 }
3886 
UpdateTimeInformation()3887 int vtkExodusIIReaderPrivate::UpdateTimeInformation()
3888 {
3889   // BUG #15632: For files with spatial partitions, vtkPExodusIIReader uses vtkExodusIIReader
3890   // to read each of the files. Since time information between those files doesn't change and
3891   // it can be quite time consuming to collect the time information, vtkPExodusIIReader forcibly passes
3892   // time information from the first reader to all others. SkipUpdateTimeInformation helps us get that
3893   // going without significant changes to the reader.
3894   if (this->SkipUpdateTimeInformation)
3895   {
3896     return 0;
3897   }
3898 
3899   int exoid = this->Exoid;
3900   vtkIdType itmp[5];
3901   int num_timesteps;
3902   int i;
3903 
3904   VTK_EXO_FUNC( ex_inquire( exoid, EX_INQ_TIME, itmp, nullptr, nullptr ), "Inquire for EX_INQ_TIME failed" );
3905   num_timesteps = itmp[0];
3906 
3907   this->Times.clear();
3908   if ( num_timesteps > 0 )
3909   {
3910     this->Times.resize( num_timesteps );
3911 
3912     int exo_err = ex_get_all_times( this->Exoid, &this->Times[0] );
3913     if ( exo_err < 0 || this->IgnoreFileTime)
3914     {
3915       for ( i = 0; i < num_timesteps; ++i )
3916       {
3917           this->Times[i] = i;
3918       }
3919       //vtkWarningMacro("Could not retrieve time values, assuming times equal to timesteps");
3920     }
3921   }
3922   return 0;
3923 }
3924 
3925 //-----------------------------------------------------------------------------
BuildSIL()3926 void vtkExodusIIReaderPrivate::BuildSIL()
3927 {
3928   // Initialize the SIL, dump all previous information.
3929   this->SIL->Initialize();
3930   if (this->Parser)
3931   {
3932     // The parser has built the SIL for us,
3933     // use that.
3934     this->SIL->ShallowCopy(this->Parser->GetSIL());
3935     return;
3936   }
3937 
3938   // Else build a minimal SIL with only the blocks.
3939   vtkSmartPointer<vtkVariantArray> childEdge =
3940     vtkSmartPointer<vtkVariantArray>::New();
3941   childEdge->InsertNextValue(0);
3942 
3943   vtkSmartPointer<vtkVariantArray> crossEdge =
3944     vtkSmartPointer<vtkVariantArray>::New();
3945   crossEdge->InsertNextValue(0);
3946 
3947   // CrossEdge is an edge linking hierarchies.
3948   vtkUnsignedCharArray* crossEdgesArray = vtkUnsignedCharArray::New();
3949   crossEdgesArray->SetName("CrossEdges");
3950   this->SIL->GetEdgeData()->AddArray(crossEdgesArray);
3951   crossEdgesArray->Delete();
3952 
3953   std::deque<std::string> names;
3954   int cc;
3955 
3956   // Now build the hierarchy.
3957   vtkIdType rootId = this->SIL->AddVertex();
3958   names.push_back("SIL");
3959 
3960   // Add the ELEM_BLOCK subtree.
3961   vtkIdType blocksRoot = this->SIL->AddChild(rootId, childEdge);
3962   names.push_back("Blocks");
3963 
3964   // Add the assembly subtree
3965   this->SIL->AddChild(rootId, childEdge);
3966   names.push_back("Assemblies");
3967 
3968   // Add the materials subtree
3969   this->SIL->AddChild(rootId, childEdge);
3970   names.push_back("Materials");
3971 
3972   // This is the map of block names to node ids.
3973   std::map<std::string, vtkIdType> blockids;
3974   int numBlocks = this->GetNumberOfObjectsOfType(vtkExodusIIReader::ELEM_BLOCK);
3975   for (cc=0; cc < numBlocks; cc++)
3976   {
3977     vtkIdType child = this->SIL->AddChild(blocksRoot, childEdge);
3978     std::string block_name =
3979       this->GetObjectName(vtkExodusIIReader::ELEM_BLOCK, cc);
3980     names.push_back(block_name);
3981     blockids[block_name] = child;
3982   }
3983 
3984   // This array is used to assign names to nodes.
3985   vtkStringArray* namesArray = vtkStringArray::New();
3986   namesArray->SetName("Names");
3987   namesArray->SetNumberOfTuples(this->SIL->GetNumberOfVertices());
3988   this->SIL->GetVertexData()->AddArray(namesArray);
3989   namesArray->Delete();
3990 
3991   std::deque<std::string>::iterator iter;
3992   for (cc=0, iter = names.begin(); iter != names.end(); ++iter, ++cc)
3993   {
3994     namesArray->SetValue(cc, (*iter).c_str());
3995   }
3996 }
3997 
3998 //-----------------------------------------------------------------------------
RequestInformation()3999 int vtkExodusIIReaderPrivate::RequestInformation()
4000 {
4001   int exoid = this->Exoid;
4002   //int itmp[5];
4003   vtkIdType* ids;
4004   vtkIdType nids;
4005   int obj;
4006   int i, j;
4007   int num_timesteps;
4008   char** obj_names;
4009   char** obj_typenames = nullptr;
4010   char** var_names = nullptr;
4011   int have_var_names;
4012   int num_vars = 0; /* number of variables per object */
4013   char tmpName[256];
4014   tmpName[255] = '\0';
4015   int maxNameLength = this->Parent->GetMaxNameLength();
4016 
4017   this->InformationTimeStamp.Modified(); // Update MTime so that it will be newer than parent's FileNameMTime
4018 
4019   VTK_EXO_FUNC( ex_get_init_ext( exoid, &this->ModelParameters ),
4020     "Unable to read database parameters." );
4021 
4022   VTK_EXO_FUNC( this->UpdateTimeInformation(), "" );
4023 
4024   //VTK_EXO_FUNC( ex_inquire( exoid, EX_INQ_TIME,       itmp, 0, 0 ), "Inquire for EX_INQ_TIME failed" );
4025   //num_timesteps = itmp[0];
4026 
4027   num_timesteps = static_cast<int>( this->Times.size() );
4028 /*
4029   this->Times.clear();
4030   if ( num_timesteps > 0 )
4031     {
4032     this->Times.resize( num_timesteps );
4033     VTK_EXO_FUNC( ex_get_all_times( this->Exoid, &this->Times[0] ), "Could not retrieve time values." );
4034     }
4035 */
4036   for ( i = 0; i < num_obj_types; ++i )
4037   {
4038     if(OBJTYPE_IS_NODAL(i))
4039     {
4040       continue;
4041     }
4042 
4043     vtkIdType blockEntryFileOffset = 1;
4044     vtkIdType setEntryFileOffset = 1;
4045 
4046     std::map<int,int> sortedObjects;
4047 
4048     int* truth_tab = nullptr;
4049     have_var_names = 0;
4050 
4051     VTK_EXO_FUNC( ex_inquire( exoid, obj_sizes[i], &nids, nullptr, nullptr ), "Object ID list size could not be determined." );
4052 
4053     if ( nids )
4054     {
4055       ids = (vtkIdType*) malloc ( nids * sizeof(vtkIdType) );
4056       obj_names = (char**) malloc( nids * sizeof(char*) );
4057       for ( obj = 0; obj < nids; ++obj )
4058       {
4059         obj_names[obj] = (char*) malloc( (maxNameLength + 1) * sizeof(char) );
4060       }
4061       if ( OBJTYPE_IS_BLOCK(i) )
4062       {
4063         obj_typenames = (char**) malloc( nids * sizeof(char*) );
4064         for ( obj = 0; obj < nids; ++obj )
4065         {
4066           obj_typenames[obj] = (char*) malloc( (maxNameLength + 1) * sizeof(char) );
4067           obj_typenames[obj][0] = '\0';
4068         }
4069       }
4070     }
4071     else
4072     {
4073       ids = nullptr;
4074       obj_names = nullptr;
4075       obj_typenames = nullptr;
4076     }
4077 
4078     if ( nids == 0 && ! OBJTYPE_IS_MAP(i) )
4079       continue;
4080 
4081     if ( nids )
4082     {
4083       VTK_EXO_FUNC( ex_get_ids( exoid, static_cast<ex_entity_type>( obj_types[i] ), ids ),
4084         "Could not read object ids for i=" << i << " and otyp=" << obj_types[i] << "." );
4085       VTK_EXO_FUNC( ex_get_names( exoid, static_cast<ex_entity_type>( obj_types[i] ), obj_names ),
4086         "Could not read object names." );
4087     }
4088 
4089     BlockInfoType binfo;
4090     SetInfoType sinfo;
4091     MapInfoType minfo;
4092 
4093     if ( OBJTYPE_IS_BLOCK(i) )
4094     {
4095       this->BlockInfo[obj_types[i]].clear();
4096       this->BlockInfo[obj_types[i]].reserve( nids );
4097     }
4098     else if ( OBJTYPE_IS_SET(i) )
4099     {
4100       this->SetInfo[obj_types[i]].clear();
4101       this->SetInfo[obj_types[i]].reserve( nids );
4102     }
4103     else
4104     {
4105       this->MapInfo[obj_types[i]].clear();
4106       this->MapInfo[obj_types[i]].reserve( nids );
4107     }
4108 
4109     if ( (OBJTYPE_IS_BLOCK(i)) || (OBJTYPE_IS_SET(i)))
4110     {
4111       VTK_EXO_FUNC( ex_get_var_param( exoid, obj_typestr[i], &num_vars ), "Could not read number of variables." );
4112 
4113       if (num_vars && num_timesteps > 0)
4114       {
4115         truth_tab = (int*) malloc(num_vars * nids * sizeof(int));
4116         VTK_EXO_FUNC( ex_get_var_tab( exoid, obj_typestr[i], nids, num_vars, truth_tab ), "Could not read truth table." );
4117 
4118         var_names = (char**) malloc(num_vars * sizeof(char*));
4119         for (j = 0; j < num_vars; ++j)
4120           var_names[j] = (char*) malloc( (maxNameLength + 1) * sizeof(char));
4121 
4122         VTK_EXO_FUNC( ex_get_var_names( exoid, obj_typestr[i], num_vars, var_names ), "Could not read variable names." );
4123         this->RemoveBeginningAndTrailingSpaces(num_vars, var_names, maxNameLength);
4124         have_var_names = 1;
4125       }
4126     }
4127 
4128     if ( !have_var_names)
4129       var_names = nullptr;
4130 
4131     for (obj = 0; obj < nids; ++obj)
4132     {
4133 
4134       if ( OBJTYPE_IS_BLOCK(i))
4135       {
4136 
4137         binfo.Name = obj_names[obj];
4138         binfo.Id = ids[obj];
4139         binfo.CachedConnectivity = nullptr;
4140         binfo.NextSqueezePoint = 0;
4141         if (obj_types[i] == vtkExodusIIReader::ELEM_BLOCK)
4142         {
4143           VTK_EXO_FUNC( ex_get_block( exoid, static_cast<ex_entity_type>( obj_types[i] ), ids[obj], obj_typenames[obj],
4144                   &binfo.Size, &binfo.BdsPerEntry[0], &binfo.BdsPerEntry[1], &binfo.BdsPerEntry[2], &binfo.AttributesPerEntry ),
4145               "Could not read block params." );
4146           binfo.Status = 1; // load element blocks by default
4147           binfo.TypeName = obj_typenames[obj];
4148         }
4149         else
4150         {
4151           VTK_EXO_FUNC( ex_get_block( exoid, static_cast<ex_entity_type>( obj_types[i] ), ids[obj], obj_typenames[obj],
4152                   &binfo.Size, &binfo.BdsPerEntry[0], &binfo.BdsPerEntry[1], &binfo.BdsPerEntry[2], &binfo.AttributesPerEntry ),
4153               "Could not read block params." );
4154           binfo.Status = 0; // don't load edge/face blocks by default
4155           binfo.TypeName = obj_typenames[obj];
4156           binfo.BdsPerEntry[1] = binfo.BdsPerEntry[2] = 0;
4157         }
4158         this->GetInitialObjectStatus(obj_types[i], &binfo);
4159         //num_entries = binfo.Size;
4160         binfo.FileOffset = blockEntryFileOffset;
4161         blockEntryFileOffset += binfo.Size;
4162         if (binfo.Name.length() == 0)
4163         {
4164           snprintf( tmpName, sizeof(tmpName),
4165 #ifdef VTK_USE_64BIT_IDS
4166               "Unnamed block ID: %lld Type: %s",
4167 #else
4168               "Unnamed block ID: %d Type: %s",
4169 #endif
4170               ids[obj], binfo.TypeName.length() ? binfo.TypeName.c_str() : "nullptr");
4171           binfo.Name = tmpName;
4172         }
4173         binfo.OriginalName = binfo.Name;
4174         this->DetermineVtkCellType(binfo);
4175 
4176         if (binfo.AttributesPerEntry)
4177         {
4178           char** attr_names;
4179           attr_names
4180               = (char**) malloc(binfo.AttributesPerEntry * sizeof(char*));
4181           for (j = 0; j < binfo.AttributesPerEntry; ++j)
4182             attr_names[j]
4183                 = (char*) malloc( (maxNameLength + 1) * sizeof(char));
4184 
4185           VTK_EXO_FUNC( ex_get_attr_names( exoid, static_cast<ex_entity_type>( obj_types[i] ), ids[obj], attr_names ),
4186             "Could not read attributes names." );
4187 
4188           for (j = 0; j < binfo.AttributesPerEntry; ++j)
4189           {
4190             binfo.AttributeNames.push_back(attr_names[j]);
4191             binfo.AttributeStatus.push_back( 0); // don't load attributes by default
4192           }
4193 
4194           for (j = 0; j < binfo.AttributesPerEntry; ++j)
4195             free(attr_names[j]);
4196           free(attr_names);
4197         }
4198 
4199         // Check to see if there is metadata that defines what part, material,
4200         //  and assembly(ies) this block belongs to.
4201 
4202         if (this->Parser && this->Parser->HasInformationAboutBlock(binfo.Id))
4203         {
4204           // Update the block name using the XML.
4205           binfo.Name = this->Parser->GetBlockName(binfo.Id);
4206 
4207           // int blockIdx = static_cast<int>( this->BlockInfo[obj_types[i]].size() );
4208           //// Add this block to our parts, materials, and assemblies collections
4209           //unsigned int k;
4210           //int found = 0;
4211 
4212           //// Look to see if this part has already been created
4213           //for (k=0;k<this->PartInfo.size();k++)
4214           //  {
4215           //  if (this->PartInfo[k].Name==partName)
4216           //    {
4217           //    //binfo.PartId = k;
4218           //    this->PartInfo[k].BlockIndices.push_back(blockIdx);
4219           //    found=1;
4220           //    }
4221           //  }
4222 
4223           //if (!found)
4224           //  {
4225           //  PartInfoType pinfo;
4226           //  pinfo.Name = partName;
4227           //  pinfo.Id = static_cast<int>( this->PartInfo.size() );
4228           //  //binfo.PartId = k;
4229           //  pinfo.BlockIndices.push_back(blockIdx);
4230           //  this->PartInfo.push_back(pinfo);
4231           //  }
4232           //
4233           //found=0;
4234           //for (k=0;k<this->MaterialInfo.size();k++)
4235           //  {
4236           //  if (this->MaterialInfo[k].Name==materialName)
4237           //    {
4238           //    //binfo.MaterialId = k;
4239           //    this->MaterialInfo[k].BlockIndices.push_back(blockIdx);
4240           //    found=1;
4241           //    }
4242           //  }
4243           //if (!found)
4244           //  {
4245           //  MaterialInfoType matinfo;
4246           //  matinfo.Name = materialName;
4247           //  matinfo.Id = static_cast<int>( this->MaterialInfo.size() );
4248           //  //binfo.MaterialId = k;
4249           //  matinfo.BlockIndices.push_back(blockIdx);
4250           //  this->MaterialInfo.push_back(matinfo);
4251           //  }
4252           //
4253           //for (k=0;k<localAssemblyNames.size();k++)
4254           //  {
4255           //  vtkStdString assemblyName=localAssemblyNames[k];
4256           //  found=0;
4257           //  for (unsigned int n=0;n<this->AssemblyInfo.size();n++)
4258           //    {
4259           //    if (this->AssemblyInfo[n].Name==assemblyName){
4260           //      //binfo.AssemblyIds.push_back(j);
4261           //      this->AssemblyInfo[n].BlockIndices.push_back(blockIdx);
4262           //      found=1;
4263           //      }
4264           //    }
4265           //  if (!found)
4266           //    {
4267           //    AssemblyInfoType ainfo;
4268           //    ainfo.Name = assemblyName;
4269           //    ainfo.Id = static_cast<int>( this->AssemblyInfo.size() );
4270           //    //binfo.AssemblyIds.push_back(k);
4271           //    ainfo.BlockIndices.push_back(blockIdx);
4272           //    this->AssemblyInfo.push_back(ainfo);
4273           //    }
4274           //  }
4275         }
4276 
4277         sortedObjects[binfo.Id]
4278             = static_cast<int>(this->BlockInfo[obj_types[i]].size());
4279         this->BlockInfo[obj_types[i]].push_back(binfo);
4280 
4281       }
4282       else if ( OBJTYPE_IS_SET(i))
4283       {
4284 
4285         sinfo.Name = obj_names[obj];
4286         sinfo.Status = 0;
4287         sinfo.Id = ids[obj];
4288         sinfo.CachedConnectivity = nullptr;
4289         sinfo.NextSqueezePoint = 0;
4290 
4291         VTK_EXO_FUNC( ex_get_set_param( exoid, static_cast<ex_entity_type>( obj_types[i] ), ids[obj], &sinfo.Size, &sinfo.DistFact),
4292             "Could not read set parameters." );
4293         //num_entries = sinfo.Size;
4294         sinfo.FileOffset = setEntryFileOffset;
4295         setEntryFileOffset += sinfo.Size;
4296         this->GetInitialObjectStatus(obj_types[i], &sinfo);
4297         if (sinfo.Name.length() == 0)
4298         {
4299           snprintf( tmpName, sizeof(tmpName),
4300 #ifdef VTK_USE_64BIT_IDS
4301               "Unnamed set ID: %lld",
4302 #else
4303               "Unnamed set ID: %d",
4304 #endif
4305               ids[obj]);
4306           sinfo.Name = tmpName;
4307         }
4308         sortedObjects[sinfo.Id] = (int) this->SetInfo[obj_types[i]].size();
4309         this->SetInfo[obj_types[i]].push_back(sinfo);
4310 
4311       }
4312       else
4313       { /* object is map */
4314 
4315         minfo.Id = ids[obj];
4316         minfo.Status = obj == 0 ? 1 : 0; // only load the first map by default
4317         switch (obj_types[i])
4318         {
4319           case vtkExodusIIReader::NODE_MAP:
4320             minfo.Size = this->ModelParameters.num_nodes;
4321             break;
4322           case vtkExodusIIReader::EDGE_MAP:
4323             minfo.Size = this->ModelParameters.num_edge;
4324             break;
4325           case vtkExodusIIReader::FACE_MAP:
4326             minfo.Size = this->ModelParameters.num_face;
4327             break;
4328           case vtkExodusIIReader::ELEM_MAP:
4329             minfo.Size = this->ModelParameters.num_elem;
4330             break;
4331           default:
4332             minfo.Size = 0;
4333         }
4334         minfo.Name = obj_names[obj];
4335         if (minfo.Name.length() == 0)
4336         {
4337           snprintf( tmpName, sizeof(tmpName),
4338 #ifdef VTK_USE_64BIT_IDS
4339               "Unnamed map ID: %lld",
4340 #else
4341               "Unnamed map ID: %d",
4342 #endif
4343               ids[obj] );
4344           minfo.Name = tmpName;
4345         }
4346         sortedObjects[minfo.Id] = (int) this->MapInfo[obj_types[i]].size();
4347         this->MapInfo[obj_types[i]].push_back(minfo);
4348 
4349       }
4350 
4351     } // end of loop over all object ids
4352 
4353     // Now that we have all objects of that type in the sortedObjects, we can
4354     // iterate over it to fill in the SortedObjectIndices (the map is a *sorted*
4355     // associative container)
4356     std::map<int,int>::iterator soit;
4357     for ( soit = sortedObjects.begin(); soit != sortedObjects.end(); ++soit )
4358     {
4359       this->SortedObjectIndices[obj_types[i]].push_back( soit->second );
4360     }
4361 
4362     if ( ((OBJTYPE_IS_BLOCK(i)) || (OBJTYPE_IS_SET(i))) && num_vars && num_timesteps > 0 )
4363     {
4364       this->ArrayInfo[obj_types[i]].clear();
4365       // Fill in ArrayInfo entries, combining array names into vectors/tensors where appropriate:
4366       this->GlomArrayNames( obj_types[i], nids, num_vars, var_names, truth_tab );
4367     }
4368 
4369     if ( var_names )
4370     {
4371       for ( j = 0; j < num_vars; ++j )
4372         free( var_names[j] );
4373       free( var_names );
4374     }
4375     if ( truth_tab )
4376       free( truth_tab );
4377 
4378     if ( nids )
4379     {
4380       free( ids );
4381 
4382       for ( obj = 0; obj < nids; ++obj )
4383         free( obj_names[obj] );
4384       free( obj_names );
4385 
4386       if ( OBJTYPE_IS_BLOCK(i) )
4387       {
4388         for ( obj = 0; obj < nids; ++obj )
4389           free( obj_typenames[obj] );
4390         free( obj_typenames );
4391       }
4392     }
4393 
4394   } // end of loop over all object types
4395   //this->ComputeGridOffsets();
4396 
4397   // Now read information for nodal arrays
4398   VTK_EXO_FUNC( ex_get_var_param( exoid, "n", &num_vars ), "Unable to read number of nodal variables." );
4399   if ( num_vars > 0 )
4400   {
4401     var_names = (char**) malloc( num_vars * sizeof(char*) );
4402     for ( j = 0; j < num_vars; ++j )
4403     {
4404       var_names[j] = (char*) malloc( (maxNameLength + 1) * sizeof(char) );
4405     }
4406 
4407     VTK_EXO_FUNC( ex_get_var_names( exoid, "n", num_vars, var_names ), "Could not read nodal variable names." );
4408     this->RemoveBeginningAndTrailingSpaces( num_vars, var_names, maxNameLength );
4409 
4410     nids = 1;
4411     std::vector<int> dummy_truth;
4412     dummy_truth.reserve( num_vars );
4413     for ( j = 0; j < num_vars; ++j )
4414     {
4415       dummy_truth.push_back( 1 );
4416     }
4417 
4418     this->GlomArrayNames( vtkExodusIIReader::NODAL, nids, num_vars, var_names, &dummy_truth[0] );
4419 
4420     for ( j = 0; j < num_vars; ++j )
4421     {
4422       free( var_names[j] );
4423     }
4424     free( var_names );
4425     var_names = nullptr;
4426   }
4427 
4428   // Now read information for global variables
4429   VTK_EXO_FUNC( ex_get_var_param( exoid, "g", &num_vars ), "Unable to read number of global variables." );
4430   if ( num_vars > 0 )
4431   {
4432     var_names = (char**) malloc( num_vars * sizeof(char*) );
4433     for ( j = 0; j < num_vars; ++j )
4434     {
4435       var_names[j] = (char*) malloc( (maxNameLength + 1) * sizeof(char) );
4436     }
4437 
4438     VTK_EXO_FUNC( ex_get_var_names( exoid, "g", num_vars, var_names ), "Could not read global variable names." );
4439     this->RemoveBeginningAndTrailingSpaces( num_vars, var_names, maxNameLength );
4440 
4441     nids = 1;
4442     std::vector<int> dummy_truth;
4443     dummy_truth.reserve( num_vars );
4444     for ( j = 0; j < num_vars; ++j )
4445     {
4446       dummy_truth.push_back( 1 );
4447     }
4448 
4449     this->GlomArrayNames( vtkExodusIIReader::GLOBAL, nids, num_vars, var_names, &dummy_truth[0] );
4450 
4451     for ( j = 0; j < num_vars; ++j )
4452     {
4453       free( var_names[j] );
4454     }
4455     free( var_names );
4456     var_names = nullptr;
4457   }
4458 
4459   return 0;
4460 }
4461 
RequestData(vtkIdType timeStep,vtkMultiBlockDataSet * output)4462 int vtkExodusIIReaderPrivate::RequestData( vtkIdType timeStep, vtkMultiBlockDataSet* output )
4463 {
4464   // The work done here depends on several conditions:
4465   // - Has connectivity changed (i.e., has block/set status changed)?
4466   //   - If so, AND if point "squeeze" turned on, must reload points and re-squeeze.
4467   //   - If so, must re-assemble all arrays
4468   //   - Must recreate block/set id array.
4469   // - Has requested time changed?
4470   //   - If so, AND if "deflect mesh" turned on, must load new deflections and compute new points.
4471   //   - If so, must assemble all time-varying arrays for new time.
4472   // - Has array status changed?
4473   //   - If so, must delete old and/or load new arrays.
4474   // Obviously, many of these tasks overlap. For instance, it would be
4475   // foolish to re-assemble all the arrays when the connectivity has
4476   // changed and then toss them out in order to load arrays for a
4477   // different time step.
4478 
4479   // Caching strategy: use GLOBAL "object type" for assembled arrays.
4480   // If connectivity hasn't changed, then these arrays can be used;
4481   // otherwise, "raw" arrays must be used.
4482   // Pro:
4483   //   - single cache == easier bookkeeping (two caches would require us to decide how to equitably split avail mem between them)
4484   //   - many different operations are accelerated:
4485   //     - just changing which variables are loaded
4486   //     - changing which blocks are in output (doesn't require disk access if cache hit)
4487   //     - possible extension to single-node/cell over time
4488   // Con:
4489   //   - higher memory consumption for caching the same set of arrays (or, holding cache size fixed: fewer arrays fit)
4490 
4491   if ( ! output )
4492   {
4493     vtkErrorMacro( "You must specify an output mesh" );
4494   }
4495 
4496   // Iterate over all block and set types, creating a
4497   // multiblock dataset to hold objects of each type.
4498   int conntypidx;
4499   int nbl = 0;
4500   output->SetNumberOfBlocks( num_conn_types );
4501   for ( conntypidx = 0; conntypidx < num_conn_types; ++conntypidx )
4502   {
4503     int otypidx = conn_obj_idx_cvt[conntypidx];
4504     int otyp = obj_types[otypidx];
4505     // Loop over all blocks/sets of this type
4506     int numObj = this->GetNumberOfObjectsOfType( otyp );
4507     vtkMultiBlockDataSet* mbds;
4508     mbds = vtkMultiBlockDataSet::New();
4509     mbds->SetNumberOfBlocks( numObj );
4510     output->SetBlock( conntypidx, mbds );
4511     output->GetMetaData(conntypidx)->Set(vtkCompositeDataSet::NAME(),
4512       conn_types_names[conntypidx]);
4513     mbds->FastDelete();
4514     //cout << "++ Block: " << mbds << " ObjectType: " << otyp << "\n";
4515     int obj;
4516     int sortIdx;
4517     for ( sortIdx = 0; sortIdx < numObj; ++sortIdx )
4518     {
4519       const char* object_name = this->GetObjectName(otyp, sortIdx);
4520 
4521       // Preserve the "sorted" order when concatenating
4522       obj = this->SortedObjectIndices[otyp][sortIdx];
4523       BlockSetInfoType* bsinfop = static_cast<BlockSetInfoType*>( this->GetObjectInfo( otypidx, obj ) );
4524       //cout << ( bsinfop->Status ? "++" : "--" ) << "   ObjectId: " << bsinfop->Id;
4525       if ( ! bsinfop->Status )
4526       {
4527         mbds->SetBlock( sortIdx, nullptr );
4528         if (object_name)
4529         {
4530           mbds->GetMetaData(sortIdx)->Set(vtkCompositeDataSet::NAME(), object_name);
4531         }
4532         continue;
4533       }
4534       vtkUnstructuredGrid* ug = vtkUnstructuredGrid::New();
4535       mbds->SetBlock( sortIdx, ug );
4536       if (object_name)
4537       {
4538         mbds->GetMetaData(sortIdx)->Set(vtkCompositeDataSet::NAME(), object_name);
4539       }
4540       ug->FastDelete();
4541       //cout << " Grid: " << ug << "\n";
4542 
4543       // Connectivity first. Either from the cache in bsinfop or read from disk.
4544       // Connectivity isn't allowed to change with time.
4545       this->AssembleOutputConnectivity( timeStep, otyp, obj, conntypidx, bsinfop, ug );
4546 
4547       // Now prepare points.
4548       // These shouldn't change unless the connectivity has changed.
4549       this->AssembleOutputPoints( timeStep, bsinfop, ug );
4550 
4551       // Then, add the desired arrays from cache (or disk)
4552       // Point and cell arrays are handled differently because they
4553       // have different problems to solve.
4554       // Point arrays must use the PointMap index to subset values.
4555       // Cell arrays may be used as-is.
4556       this->AssembleOutputPointArrays( timeStep, bsinfop, ug );
4557       this->AssembleOutputCellArrays( timeStep, otyp, obj, bsinfop, ug );
4558 
4559       // Some arrays may be procedurally generated (e.g., the ObjectId
4560       // array, global element and node number arrays). This constructs
4561       // them as required.
4562       this->AssembleOutputProceduralArrays( timeStep, otyp, obj, ug );
4563 
4564       // QA and informational records in the ExodusII file are appended
4565       // to each and every output unstructured grid.
4566       this->AssembleOutputGlobalArrays( timeStep, otyp, obj, bsinfop, ug );
4567 
4568       // Maps (as distinct from the global element and node arrays above)
4569       // are per-cell or per-node integers. As with point arrays, the
4570       // PointMap is used to subset node maps. Cell arrays are stored in
4571       // ExodusII files for all elements (across all blocks of a given type)
4572       // and thus must be subset for the unstructured grid of interest.
4573       this->AssembleOutputPointMaps( timeStep, bsinfop, ug );
4574       this->AssembleOutputCellMaps( timeStep, otyp, obj, bsinfop, ug );
4575       ++nbl;
4576     }
4577   }
4578 
4579   this->CloseFile();
4580 
4581   return 0;
4582 }
4583 
SetUpEmptyGrid(vtkMultiBlockDataSet * output)4584 int vtkExodusIIReaderPrivate::SetUpEmptyGrid( vtkMultiBlockDataSet* output )
4585 {
4586   if ( ! output )
4587   {
4588     vtkErrorMacro( "You must specify an output mesh" );
4589   }
4590 
4591   // Iterate over all block and set types, creating a
4592   // multiblock dataset to hold objects of each type.
4593   int conntypidx;
4594   int nbl = 0;
4595   output->SetNumberOfBlocks( num_conn_types );
4596   for ( conntypidx = 0; conntypidx < num_conn_types; ++conntypidx )
4597   {
4598     int otypidx = conn_obj_idx_cvt[conntypidx];
4599     int otyp = obj_types[otypidx];
4600     // Loop over all blocks/sets of this type
4601     int numObj = this->GetNumberOfObjectsOfType( otyp );
4602     vtkMultiBlockDataSet* mbds;
4603     mbds = vtkMultiBlockDataSet::New();
4604     mbds->SetNumberOfBlocks( numObj );
4605     output->SetBlock( conntypidx, mbds );
4606     output->GetMetaData(conntypidx)->Set(vtkCompositeDataSet::NAME(),
4607       conn_types_names[conntypidx]);
4608     mbds->FastDelete();
4609     int obj;
4610     int sortIdx;
4611     for ( sortIdx = 0; sortIdx < numObj; ++sortIdx )
4612     {
4613       // Preserve the "sorted" order when concatenating
4614       obj = this->SortedObjectIndices[otyp][sortIdx];
4615       BlockSetInfoType* bsinfop = static_cast<BlockSetInfoType*>( this->GetObjectInfo( otypidx, obj ) );
4616       //cout << ( bsinfop->Status ? "++" : "--" ) << "   ObjectId: " << bsinfop->Id;
4617       if ( ! bsinfop->Status )
4618       {
4619         //cout << "\n";
4620         mbds->SetBlock( sortIdx, nullptr );
4621         continue;
4622       }
4623       vtkUnstructuredGrid* ug = vtkUnstructuredGrid::New();
4624       mbds->SetBlock( sortIdx, ug );
4625       ug->FastDelete();
4626       ++nbl;
4627     }
4628   }
4629 #if 0
4630   int idx;
4631   vtkUnstructuredGrid* leaf;
4632 
4633   // Set up an empty unstructured grid
4634   leaf->Allocate(0);
4635 
4636   // Create new points
4637   vtkPoints* newPoints = vtkPoints::New();
4638   newPoints->SetNumberOfPoints( 0 );
4639   leaf->SetPoints( newPoints );
4640   newPoints->Delete();
4641   newPoints = nullptr;
4642 
4643   // Create point and cell arrays
4644   int typ;
4645   for ( typ = 0; typ < numObjResultTypes; ++typ )
4646   {
4647     int otyp = objResultTypes[typ];
4648     int nObjArr = this->GetNumberOfObjectArrays( otyp );
4649     for ( idx = 0; idx < nObjArr; ++idx )
4650     {
4651       vtkDoubleArray* da = vtkDoubleArray::New();
4652       da->SetName( this->GetObjectArrayName( otyp, idx ) );
4653       da->SetNumberOfComponents( this->GetNumberOfObjectArrayComponents( otyp, idx ) );
4654       if ( otyp == vtkExodusIIReader::NODAL )
4655       {
4656         leaf->GetPointData()->AddArray( da );
4657       }
4658       else
4659       {
4660         leaf->GetCellData()->AddArray( da );
4661       }
4662       da->FastDelete();
4663     }
4664   }
4665 
4666   for ( typ = 0; typ < numObjAttribTypes; ++typ )
4667   {
4668     int otyp = objAttribTypes[typ];
4669     int nObj = this->GetNumberOfObjects( otyp );
4670     for ( idx = 0; idx < nObj; ++ idx )
4671     {
4672       // Attributes are defined per block, not per block type.
4673       int nObjAtt = this->GetNumberOfObjectAttributes( otyp, idx );
4674       for ( int aidx = 0; aidx < nObjAtt; ++ aidx )
4675       {
4676         vtkDoubleArray* da = vtkDoubleArray::New();
4677         da->SetName( this->GetObjectAttributeName( otyp, idx, aidx ) );
4678         da->SetNumberOfComponents( 1 );
4679         // All attributes are cell data
4680         leaf->GetCellData()->AddArray( da );
4681         da->FastDelete();
4682       }
4683     }
4684   }
4685 
4686   if ( this->GetGenerateObjectIdCellArray() )
4687   {
4688     vtkIntArray* ia = vtkIntArray::New();
4689     ia->SetName( this->GetObjectIdArrayName() );
4690     ia->SetNumberOfComponents( 1 );
4691     leaf->GetCellData()->AddArray( ia );
4692     ia->FastDelete();
4693   }
4694 
4695   if ( this->GetGenerateGlobalNodeIdArray() )
4696   {
4697     vtkIntArray* ia = vtkIntArray::New();
4698     ia->SetName( this->GetGlobalNodeIdArrayName() );
4699     ia->SetNumberOfComponents( 1 );
4700     leaf->GetPointData()->AddArray( ia );
4701     ia->FastDelete();
4702   }
4703 
4704   if ( this->GetGenerateGlobalElementIdArray() )
4705   {
4706     vtkIntArray* ia = vtkIntArray::New();
4707     ia->SetName( this->GetGlobalElementIdArrayName() );
4708     ia->SetNumberOfComponents( 1 );
4709     leaf->GetCellData()->AddArray( ia );
4710     ia->FastDelete();
4711   }
4712 #endif // 0
4713   return 1;
4714 }
4715 
Reset()4716 void vtkExodusIIReaderPrivate::Reset()
4717 {
4718   this->CloseFile();
4719   this->ResetCache(); // must come before BlockInfo and SetInfo are cleared.
4720   this->BlockInfo.clear();
4721   this->SetInfo.clear();
4722   this->MapInfo.clear();
4723   this->PartInfo.clear();
4724   this->MaterialInfo.clear();
4725   this->AssemblyInfo.clear();
4726   this->SortedObjectIndices.clear();
4727   this->ArrayInfo.clear();
4728   this->ExodusVersion = -1.;
4729   this->Times.clear();
4730   memset( (void*)&this->ModelParameters, 0, sizeof(this->ModelParameters) );
4731 
4732   // Don't clear file id since it's not part of meta-data that's read from the
4733   // file, it's set externally (by vtkPExodusIIReader).
4734   // Refer to BUG #7633.
4735   //this->FileId = 0;
4736 
4737   this->Modified();
4738 }
4739 
ResetSettings()4740 void vtkExodusIIReaderPrivate::ResetSettings()
4741 {
4742   this->GenerateGlobalElementIdArray = 0;
4743   this->GenerateGlobalNodeIdArray = 0;
4744   this->GenerateImplicitElementIdArray = 0;
4745   this->GenerateImplicitNodeIdArray = 0;
4746   this->GenerateGlobalIdArray = 0;
4747   this->GenerateObjectIdArray = 1;
4748   this->GenerateFileIdArray = 0;
4749 
4750   this->ApplyDisplacements = 1;
4751   this->DisplacementMagnitude = 1.;
4752 
4753   this->HasModeShapes = 0;
4754   this->ModeShapeTime = -1.;
4755   this->AnimateModeShapes = 1;
4756 
4757   this->SqueezePoints = 1;
4758 
4759   this->InitialArrayInfo.clear();
4760   this->InitialObjectInfo.clear();
4761 }
4762 
ResetCache()4763 void vtkExodusIIReaderPrivate::ResetCache()
4764 {
4765   this->Cache->Clear();
4766   this->Cache->SetCacheCapacity(this->CacheSize); // FIXME: Perhaps Cache should have a Reset and a Clear method?
4767   this->ClearConnectivityCaches();
4768 }
4769 
SetCacheSize(double size)4770 void vtkExodusIIReaderPrivate::SetCacheSize( double size )
4771 {
4772   if (this->CacheSize != size)
4773   {
4774     this->CacheSize = size;
4775     this->Cache->SetCacheCapacity(this->CacheSize);
4776     this->Modified();
4777   }
4778 }
4779 
IsXMLMetadataValid()4780 bool vtkExodusIIReaderPrivate::IsXMLMetadataValid()
4781 {
4782   // Make sure that each block id referred to in the metadata arrays exist
4783   // in the data
4784 
4785   std::set<int> blockIdsFromXml;
4786   this->Parser->GetBlockIds(blockIdsFromXml);
4787   std::vector<BlockInfoType> blocksFromData = this->BlockInfo[vtkExodusIIReader::ELEM_BLOCK];
4788   std::vector<BlockInfoType>::iterator iter2;
4789   std::set<int>::iterator iter;
4790   bool isBlockValid = false;
4791   for(iter = blockIdsFromXml.begin(); iter!=blockIdsFromXml.end(); ++iter)
4792   {
4793     isBlockValid = false;
4794     for(iter2 = blocksFromData.begin(); iter2!=blocksFromData.end(); ++iter2)
4795     {
4796       if(*iter == (*iter2).Id)
4797       {
4798         isBlockValid = true;
4799         break;
4800       }
4801     }
4802     if(!isBlockValid)
4803     {
4804       break;
4805     }
4806   }
4807 
4808   return isBlockValid;
4809 }
4810 
SetSqueezePoints(int sp)4811 void vtkExodusIIReaderPrivate::SetSqueezePoints( int sp )
4812 {
4813   if ( this->SqueezePoints == sp )
4814     return;
4815 
4816   this->SqueezePoints = sp;
4817   this->Modified();
4818 
4819   // Invalidate global "topology" cache
4820   // The point maps should be invalidated
4821   // FIXME: bsinfop->NextSqueezePoint = 0 for all bsinfop
4822   // FIXME: bsinfop->CachedConnectivity = 0 for all bsinfop
4823   // FIXME: bsinfop->PointMap.clear() for all bsinfop
4824   // FIXME: bsinfop->ReversePointMap.clear() for all bsinfop
4825 }
4826 
GetNumberOfNodes()4827 int vtkExodusIIReaderPrivate::GetNumberOfNodes()
4828 {
4829   return this->ModelParameters.num_nodes;
4830 }
4831 
GetNumberOfObjectsOfType(int otyp)4832 int vtkExodusIIReaderPrivate::GetNumberOfObjectsOfType( int otyp )
4833 {
4834   int i = this->GetObjectTypeIndexFromObjectType( otyp );
4835   if ( i < 0 )
4836   {
4837     // Could signal warning here, but might not want it if file simply doesn't have objects of some obscure type (e.g., edge sets)
4838     return 0;
4839   }
4840   return this->GetNumberOfObjectsAtTypeIndex( i );
4841 }
4842 
GetNumberOfObjectArraysOfType(int otyp)4843 int vtkExodusIIReaderPrivate::GetNumberOfObjectArraysOfType( int otyp )
4844 {
4845   std::map<int,std::vector<ArrayInfoType> >::iterator it = this->ArrayInfo.find( otyp );
4846   if ( it != this->ArrayInfo.end() )
4847   {
4848     return (int) it->second.size();
4849   }
4850   // Could signal warning here, but might not want it if file simply doesn't have objects of some obscure type (e.g., edge sets)
4851   return 0;
4852 }
4853 
GetObjectName(int otyp,int k)4854 const char* vtkExodusIIReaderPrivate::GetObjectName( int otyp, int k )
4855 {
4856   ObjectInfoType* oinfop = this->GetSortedObjectInfo( otyp, k );
4857   return oinfop ? oinfop->Name.c_str() : nullptr;
4858 }
4859 
GetObjectId(int otyp,int k)4860 int vtkExodusIIReaderPrivate::GetObjectId( int otyp, int k )
4861 {
4862   ObjectInfoType* oinfop = this->GetSortedObjectInfo( otyp, k );
4863   return oinfop ? oinfop->Id : -1;
4864 }
4865 
GetObjectSize(int otyp,int k)4866 int vtkExodusIIReaderPrivate::GetObjectSize( int otyp, int k )
4867 {
4868   ObjectInfoType* oinfop = this->GetSortedObjectInfo( otyp, k );
4869   return oinfop ? oinfop->Size : 0;
4870 }
4871 
GetObjectStatus(int otyp,int k)4872 int vtkExodusIIReaderPrivate::GetObjectStatus( int otyp, int k )
4873 {
4874   ObjectInfoType* oinfop = this->GetSortedObjectInfo( otyp, k );
4875   return oinfop ? oinfop->Status : 0;
4876 }
4877 
GetUnsortedObjectStatus(int otyp,int k)4878 int vtkExodusIIReaderPrivate::GetUnsortedObjectStatus( int otyp, int k )
4879 {
4880   ObjectInfoType* oinfop = this->GetUnsortedObjectInfo( otyp, k );
4881   return oinfop ? oinfop->Status : 0;
4882 }
4883 
GetInitialObjectStatus(int otyp,ObjectInfoType * objType)4884 void vtkExodusIIReaderPrivate::GetInitialObjectStatus( int otyp, ObjectInfoType *objType )
4885 {
4886   for(unsigned int oidx=0; oidx<this->InitialObjectInfo[otyp].size(); oidx++)
4887   {
4888     if( (!this->InitialObjectInfo[otyp][oidx].Name.empty() &&
4889          objType->Name == this->InitialObjectInfo[otyp][oidx].Name) ||
4890         (this->InitialObjectInfo[otyp][oidx].Id != -1 &&
4891         objType->Id == this->InitialObjectInfo[otyp][oidx].Id) )
4892     {
4893       objType->Status = this->InitialObjectInfo[otyp][oidx].Status;
4894       break;
4895     }
4896   }
4897 }
4898 
SetObjectStatus(int otyp,int k,int stat)4899 void vtkExodusIIReaderPrivate::SetObjectStatus( int otyp, int k, int stat )
4900 {
4901   stat = (stat != 0); // Force stat to be either 0 or 1
4902   // OK, found the object
4903   ObjectInfoType* oinfop = this->GetSortedObjectInfo( otyp, k );
4904   if ( ! oinfop )
4905   { // error message will have been generated by GetSortedObjectInfo()
4906     return;
4907   }
4908 
4909   if ( oinfop->Status == stat )
4910   { // no change => do nothing
4911     return;
4912   }
4913   oinfop->Status = stat;
4914 
4915   this->Modified();
4916 }
4917 
SetUnsortedObjectStatus(int otyp,int k,int stat)4918 void vtkExodusIIReaderPrivate::SetUnsortedObjectStatus( int otyp, int k, int stat )
4919 {
4920   stat = (stat != 0); // Force stat to be either 0 or 1
4921   // OK, found the object
4922   ObjectInfoType* oinfop = this->GetUnsortedObjectInfo( otyp, k );
4923   if ( ! oinfop )
4924   { // error message will have been generated by GetSortedObjectInfo()
4925     return;
4926   }
4927 
4928   if ( oinfop->Status == stat )
4929   { // no change => do nothing
4930     return;
4931   }
4932   oinfop->Status = stat;
4933 
4934   this->Modified();
4935 }
4936 
SetInitialObjectStatus(int objectType,const char * objName,int status)4937 void vtkExodusIIReaderPrivate::SetInitialObjectStatus( int objectType, const char* objName, int status )
4938 {
4939   ObjectInfoType info;
4940   vtkStdString nm = objName;
4941   int idx = 0;
4942   int idlen = 0;
4943   int id = -1;
4944 
4945   // When no name is found for an object, it is given one of a certain format.
4946   // Parse the id out of that string and use it to identify the object later.
4947   if ( ( idx = static_cast<int>( nm.find( "ID: " ) ) ) != (int) vtkStdString::npos )
4948   {
4949     idx += 4;
4950     idlen = 0;
4951     while(idx+idlen < static_cast<int>(nm.length()) &&  nm.at(idx+idlen) != ' ' )
4952     {
4953       idlen++;
4954     }
4955     id = atoi(nm.substr(idx,idlen).c_str());
4956   }
4957   else
4958   {
4959     info.Name = objName;
4960   }
4961   info.Id = id;
4962   info.Status = status;
4963   this->InitialObjectInfo[objectType].push_back(info);
4964 }
4965 
GetObjectArrayName(int otyp,int i)4966 const char* vtkExodusIIReaderPrivate::GetObjectArrayName( int otyp, int i )
4967 {
4968   std::map<int,std::vector<ArrayInfoType> >::iterator it = this->ArrayInfo.find( otyp );
4969   if ( it != this->ArrayInfo.end() )
4970   {
4971     int N = (int) it->second.size();
4972     if ( i < 0 || i >= N )
4973     {
4974       vtkDebugMacro( "You requested array " << i << " in a collection of only " << N << " arrays." );
4975       return nullptr;
4976     }
4977     return it->second[i].Name.c_str();
4978   }
4979   vtkDebugMacro( "Could not find collection of arrays for objects of type " << otyp <<
4980     " (" << objtype_names[this->GetObjectTypeIndexFromObjectType(otyp)] << ")." );
4981   return nullptr;
4982 }
4983 
GetNumberOfObjectArrayComponents(int otyp,int i)4984 int vtkExodusIIReaderPrivate::GetNumberOfObjectArrayComponents( int otyp, int i )
4985 {
4986   std::map<int,std::vector<ArrayInfoType> >::iterator it = this->ArrayInfo.find( otyp );
4987   if ( it != this->ArrayInfo.end() )
4988   {
4989     int N = (int) it->second.size();
4990     if ( i < 0 || i >= N )
4991     {
4992       vtkDebugMacro( "You requested array " << i << " in a collection of only " << N << " arrays." );
4993       return 0;
4994     }
4995     return it->second[i].Components;
4996   }
4997   vtkDebugMacro( "Could not find collection of arrays for objects of type " << otyp <<
4998     " (" << objtype_names[this->GetObjectTypeIndexFromObjectType(otyp)] << ")." );
4999   return 0;
5000 }
5001 
GetObjectArrayStatus(int otyp,int i)5002 int vtkExodusIIReaderPrivate::GetObjectArrayStatus( int otyp, int i )
5003 {
5004   std::map<int,std::vector<ArrayInfoType> >::iterator it = this->ArrayInfo.find( otyp );
5005   if ( it != this->ArrayInfo.end() )
5006   {
5007     int N = (int) it->second.size();
5008     if ( i < 0 || i >= N )
5009     {
5010       vtkDebugMacro( "You requested array " << i << " in a collection of only " << N << " arrays." );
5011       return 0;
5012     }
5013     return it->second[i].Status;
5014   }
5015   vtkDebugMacro( "Could not find collection of arrays for objects of type " << otyp <<
5016     " (" << objtype_names[this->GetObjectTypeIndexFromObjectType(otyp)] << ")." );
5017   return 0;
5018 }
5019 
5020 
GetInitialObjectArrayStatus(int otyp,ArrayInfoType * objType)5021 void vtkExodusIIReaderPrivate::GetInitialObjectArrayStatus( int otyp, ArrayInfoType *objType )
5022 {
5023   for(unsigned int oidx=0; oidx<this->InitialArrayInfo[otyp].size(); oidx++)
5024   {
5025     if(objType->Name == this->InitialArrayInfo[otyp][oidx].Name)
5026     {
5027       objType->Status = this->InitialArrayInfo[otyp][oidx].Status;
5028       break;
5029     }
5030   }
5031 }
5032 
SetObjectArrayStatus(int otyp,int i,int stat)5033 void vtkExodusIIReaderPrivate::SetObjectArrayStatus( int otyp, int i, int stat )
5034 {
5035   stat = ( stat != 0 ); // Force stat to be either 0 or 1
5036   std::map<int,std::vector<ArrayInfoType> >::iterator it = this->ArrayInfo.find( otyp );
5037   if ( it != this->ArrayInfo.end() )
5038   {
5039     int N = (int) it->second.size();
5040     if ( i < 0 || i >= N )
5041     {
5042       vtkDebugMacro( "You requested array " << i << " in a collection of only " << N << " arrays." );
5043       return;
5044     }
5045     if ( it->second[i].Status == stat )
5046     {
5047       // no change => do nothing
5048       return;
5049     }
5050     it->second[i].Status = stat;
5051     this->Modified();
5052     // FIXME: Mark something so we know what's changed since the last RequestData?!
5053     // For the "global" (assembled) array, this is tricky because we really only want
5054     // to invalidate a range of the total array... For now, we'll just force the "global"
5055     // array to be reassembled even if it does mean a lot more copying -- it's not like
5056     // it was any faster before.
5057     //vtkExodusIICacheKey key( 0, GLOBAL, 0, i );
5058     //vtkExodusIICacheKey pattern( 0, 1, 0, 1 );
5059     this->Cache->Invalidate(
5060       vtkExodusIICacheKey( 0, vtkExodusIIReader::GLOBAL, otyp, i ),
5061       vtkExodusIICacheKey( 0, 1, 1, 1 ) );
5062   }
5063   else
5064   {
5065     vtkDebugMacro( "Could not find collection of arrays for objects of type " << otyp <<
5066       " (" << objtype_names[this->GetObjectTypeIndexFromObjectType(otyp)] << ")." );
5067   }
5068 }
5069 
SetInitialObjectArrayStatus(int objectType,const char * arrayName,int status)5070 void vtkExodusIIReaderPrivate::SetInitialObjectArrayStatus( int objectType, const char* arrayName, int status )
5071 {
5072   ArrayInfoType ainfo;
5073   ainfo.Name = arrayName;
5074   ainfo.Status = status;
5075   this->InitialArrayInfo[objectType].push_back(ainfo);
5076 }
5077 
GetNumberOfObjectAttributes(int otyp,int oi)5078 int vtkExodusIIReaderPrivate::GetNumberOfObjectAttributes( int otyp, int oi )
5079 {
5080   std::map<int,std::vector<BlockInfoType> >::iterator it = this->BlockInfo.find( otyp );
5081   if ( it != this->BlockInfo.end() )
5082   {
5083     int N = (int) it->second.size();
5084     if ( oi < 0 || oi >= N )
5085     {
5086       int otypIdx = this->GetObjectTypeIndexFromObjectType(otyp);
5087       const char* btname = otypIdx >= 0 ? objtype_names[otypIdx] : "block";
5088       static_cast<void>(btname); // not referenced warning
5089       vtkDebugMacro( "You requested " << btname << " " << oi << " in a collection of only " << N << " blocks." );
5090       return 0;
5091     }
5092     oi = this->SortedObjectIndices[otyp][oi]; // index into sorted list of objects (block order, not file order)
5093     return (int) it->second[oi].AttributeNames.size();
5094   }
5095   return 0;
5096 }
5097 
GetObjectAttributeName(int otyp,int oi,int ai)5098 const char* vtkExodusIIReaderPrivate::GetObjectAttributeName( int otyp, int oi, int ai )
5099 {
5100   std::map<int,std::vector<BlockInfoType> >::iterator it = this->BlockInfo.find( otyp );
5101   if ( it != this->BlockInfo.end() )
5102   {
5103     int N = (int) it->second.size();
5104     if ( oi < 0 || oi >= N )
5105     {
5106       vtkDebugMacro( "You requested block " << oi << " in a collection of only " << N << " blocks." );
5107       return nullptr;
5108     }
5109     oi = this->SortedObjectIndices[otyp][oi]; // index into sorted list of objects (block order, not file order)
5110     N = (int) it->second[oi].AttributeNames.size();
5111     if ( ai < 0 || ai >= N )
5112     {
5113       vtkDebugMacro( "You requested attribute " << ai << " in a collection of only " << N << " attributes." );
5114       return nullptr;
5115     }
5116     else
5117     {
5118       return it->second[oi].AttributeNames[ai].c_str();
5119     }
5120   }
5121   vtkDebugMacro( "Could not find collection of blocks of type " << otyp <<
5122     " (" << objtype_names[this->GetObjectTypeIndexFromObjectType(otyp)] << ")." );
5123   return nullptr;
5124 }
5125 
GetObjectAttributeIndex(int otyp,int oi,const char * attribName)5126 int vtkExodusIIReaderPrivate::GetObjectAttributeIndex( int otyp, int oi, const char* attribName )
5127 {
5128   std::map<int,std::vector<BlockInfoType> >::iterator it = this->BlockInfo.find( otyp );
5129   if ( it != this->BlockInfo.end() )
5130   {
5131     int N = (int) it->second.size();
5132     if ( oi < 0 || oi >= N )
5133     {
5134       vtkDebugMacro( "You requested block " << oi << " in a collection of only " << N << " blocks." );
5135       return -1;
5136     }
5137     oi = this->SortedObjectIndices[otyp][oi]; // index into sorted list of objects (block order, not file order)
5138     N = (int) it->second[oi].AttributeNames.size();
5139     int ai;
5140     for ( ai = 0; ai < N; ++ai )
5141     {
5142       if ( it->second[oi].AttributeNames[ai] == attribName )
5143       {
5144         return ai;
5145       }
5146     }
5147     return -1;
5148   }
5149   vtkDebugMacro( "Could not find collection of blocks of type " << otyp <<
5150     " (" << objtype_names[this->GetObjectTypeIndexFromObjectType(otyp)] << ")." );
5151   return -1;
5152 }
5153 
GetObjectAttributeStatus(int otyp,int oi,int ai)5154 int vtkExodusIIReaderPrivate::GetObjectAttributeStatus( int otyp, int oi, int ai )
5155 {
5156   std::map<int,std::vector<BlockInfoType> >::iterator it = this->BlockInfo.find( otyp );
5157   if ( it != this->BlockInfo.end() )
5158   {
5159     int N = (int) it->second.size();
5160     if ( oi < 0 || oi >= N )
5161     {
5162       vtkDebugMacro( "You requested block " << oi << " in a collection of only " << N << " blocks." );
5163       return 0;
5164     }
5165     oi = this->SortedObjectIndices[otyp][oi]; // index into sorted list of objects (block order, not file order)
5166     N = (int) it->second[oi].AttributeStatus.size();
5167     if ( ai < 0 || ai >= N )
5168     {
5169       vtkDebugMacro( "You requested attribute " << ai << " in a collection of only " << N << " attributes." );
5170       return 0;
5171     }
5172     else
5173     {
5174       return it->second[oi].AttributeStatus[ai];
5175     }
5176   }
5177   vtkDebugMacro( "Could not find collection of blocks of type " << otyp <<
5178     " (" << objtype_names[this->GetObjectTypeIndexFromObjectType(otyp)] << ")." );
5179   return 0;
5180 }
5181 
SetObjectAttributeStatus(int otyp,int oi,int ai,int status)5182 void vtkExodusIIReaderPrivate::SetObjectAttributeStatus( int otyp, int oi, int ai, int status )
5183 {
5184   status = status ? 1 : 0;
5185   std::map<int,std::vector<BlockInfoType> >::iterator it = this->BlockInfo.find( otyp );
5186   if ( it != this->BlockInfo.end() )
5187   {
5188     int N = (int) it->second.size();
5189     if ( oi < 0 || oi >= N )
5190     {
5191       vtkDebugMacro( "You requested block " << oi << " in a collection of only " << N << " blocks." );
5192       return;
5193     }
5194     oi = this->SortedObjectIndices[otyp][oi]; // index into sorted list of objects (block order, not file order)
5195     N = (int) it->second[oi].AttributeStatus.size();
5196     if ( ai < 0 || ai >= N )
5197     {
5198       vtkDebugMacro( "You requested attribute " << ai << " in a collection of only " << N << " attribute." );
5199       return;
5200     }
5201     else
5202     {
5203       if ( it->second[oi].AttributeStatus[ai] == status )
5204       {
5205         return;
5206       }
5207       it->second[oi].AttributeStatus[ai] = status;
5208       this->Modified();
5209     }
5210   }
5211   vtkDebugMacro( "Could not find collection of blocks of type " << otyp <<
5212     " (" << objtype_names[this->GetObjectTypeIndexFromObjectType(otyp)] << ")." );
5213 }
5214 
SetApplyDisplacements(vtkTypeBool d)5215 void vtkExodusIIReaderPrivate::SetApplyDisplacements( vtkTypeBool d )
5216 {
5217   if ( this->ApplyDisplacements == d )
5218     return;
5219 
5220   this->ApplyDisplacements = d;
5221   this->Modified();
5222 
5223   // Require the coordinates to be recomputed:
5224   this->Cache->Invalidate(
5225     vtkExodusIICacheKey( 0, vtkExodusIIReader::NODAL_COORDS, 0, 0 ),
5226     vtkExodusIICacheKey( 0, 1, 0, 0 ) );
5227 }
5228 
SetDisplacementMagnitude(double s)5229 void vtkExodusIIReaderPrivate::SetDisplacementMagnitude( double s )
5230 {
5231   if ( this->DisplacementMagnitude == s )
5232     return;
5233 
5234   this->DisplacementMagnitude = s;
5235   this->Modified();
5236 
5237   // Require the coordinates to be recomputed:
5238   this->Cache->Invalidate(
5239     vtkExodusIICacheKey( 0, vtkExodusIIReader::NODAL_COORDS, 0, 0 ),
5240     vtkExodusIICacheKey( 0, 1, 0, 0 ) );
5241 }
5242 
FindDisplacementVectors(int timeStep)5243 vtkDataArray* vtkExodusIIReaderPrivate::FindDisplacementVectors( int timeStep )
5244 {
5245   std::map<int,std::vector<ArrayInfoType> >::iterator it = this->ArrayInfo.find( vtkExodusIIReader::NODAL );
5246   if ( it != this->ArrayInfo.end() )
5247   {
5248     int N = (int) it->second.size();
5249     for ( int i = 0; i < N; ++i )
5250     {
5251       std::string upperName = vtksys::SystemTools::UpperCase( it->second[i].Name.substr( 0, 3 ) );
5252       if ( upperName == "DIS" && it->second[i].Components == this->ModelParameters.num_dim )
5253       {
5254         return this->GetCacheOrRead( vtkExodusIICacheKey( timeStep, vtkExodusIIReader::NODAL, 0, i ) );
5255       }
5256     }
5257   }
5258   return nullptr;
5259 }
5260 
5261 
5262 // -------------------------------------------------------- PUBLIC CLASS MEMBERS
5263 
5264 vtkStandardNewMacro(vtkExodusIIReader);
5265 vtkCxxSetObjectMacro(vtkExodusIIReader,Metadata,vtkExodusIIReaderPrivate);
5266 
vtkExodusIIReader()5267 vtkExodusIIReader::vtkExodusIIReader()
5268 {
5269   this->FileName = nullptr;
5270   this->XMLFileName = nullptr;
5271   this->Metadata = vtkExodusIIReaderPrivate::New();
5272   this->Metadata->Parent = this;
5273   this->Metadata->SetCacheSize(0.0);
5274   this->TimeStep = 0;
5275   this->TimeStepRange[0] = 0;
5276   this->TimeStepRange[1] = 0;
5277   this->ModeShapesRange[0] = 0;
5278   this->ModeShapesRange[1] = 0;
5279   this->DisplayType = 0;
5280   this->DisplayType = 0;
5281   this->SILUpdateStamp = -1;
5282 
5283   this->SetNumberOfInputPorts( 0 );
5284 }
5285 
~vtkExodusIIReader()5286 vtkExodusIIReader::~vtkExodusIIReader()
5287 {
5288   this->SetXMLFileName( nullptr );
5289   this->SetFileName( nullptr );
5290 
5291   this->SetMetadata( nullptr );
5292   //this->SetExodusModel( 0 );
5293 }
5294 
5295 // Normally, vtkExodusIIReader::PrintSelf would be here.
5296 // But it's above to prevent PrintSelf-Hybrid from failing because it assumes
5297 // the first PrintSelf method is the one for the class declared in the header file.
5298 
CanReadFile(const char * fname)5299 int vtkExodusIIReader::CanReadFile( const char* fname )
5300 {
5301   int exoid;
5302   int appWordSize = 8;
5303   int diskWordSize = 8;
5304   float version;
5305 
5306   if ( (exoid = ex_open( fname, EX_READ, &appWordSize, &diskWordSize, &version )) < 0 )
5307   {
5308     return 0;
5309   }
5310   if ( ex_close( exoid ) != 0 )
5311   {
5312     vtkWarningMacro( "Unable to close \"" << fname << "\" opened for testing." );
5313     return 0;
5314   }
5315   return 1;
5316 }
5317 
5318 #if 0
5319 void vtkExodusIIReaderPrivate::Modified()
5320 {
5321   cout << "E2RP modified\n"; this->Superclass::Modified();
5322 }
5323 
5324 void vtkExodusIIReader::Modified()
5325 {
5326   cout << "E2R modified\n"; this->Superclass::Modified();
5327 }
5328 #endif // 0
5329 
GetMTime()5330 vtkMTimeType vtkExodusIIReader::GetMTime()
5331 {
5332   //return this->MTime.GetMTime();
5333   /*
5334   vtkMTimeType mtime1, mtime2;
5335   vtkMTimeType readerMTime = this->MTime.GetMTime();
5336   vtkMTimeType privateMTime = this->Metadata->GetMTime();
5337   vtkMTimeType fileNameMTime = this->FileNameMTime.GetMTime();
5338   vtkMTimeType xmlFileNameMTime = this->XMLFileNameMTime.GetMTime();
5339   mtime1 = privateMTime > readerMTime ? privateMTime : readerMTime;
5340   mtime2 = fileNameMTime > xmlFileNameMTime ? fileNameMTime : xmlFileNameMTime;
5341   return mtime1 > mtime2 ? mtime1 : mtime2;
5342   */
5343   vtkMTimeType readerMTime = this->MTime.GetMTime();
5344   vtkMTimeType privateMTime = this->Metadata->GetMTime();
5345   return privateMTime > readerMTime ? privateMTime : readerMTime;
5346 }
5347 
GetMetadataMTime()5348 vtkMTimeType vtkExodusIIReader::GetMetadataMTime()
5349 {
5350   return this->Metadata->InformationTimeStamp < this->Metadata->GetMTime() ?
5351     this->Metadata->InformationTimeStamp : this->Metadata->GetMTime();
5352 }
5353 
5354 #define vtkSetStringMacroBody(propName,fname) \
5355   int modified = 0; \
5356   if ( fname == this->propName ) \
5357     return; \
5358   if ( fname && this->propName && !strcmp( fname, this->propName ) ) \
5359     return; \
5360   modified = 1; \
5361   delete [] this->propName; \
5362   if ( fname ) \
5363   { \
5364     size_t fnl = strlen( fname ) + 1; \
5365     char* dst = new char[fnl]; \
5366     const char* src = fname; \
5367     this->propName = dst; \
5368     do { *dst++ = *src++; } while ( --fnl ); \
5369   } \
5370   else \
5371   { \
5372     this->propName = 0; \
5373   }
5374 
SetFileName(const char * fname)5375 void vtkExodusIIReader::SetFileName( const char* fname )
5376 {
5377   vtkSetStringMacroBody(FileName,fname);
5378   if ( modified )
5379   {
5380     this->Metadata->Reset();
5381     this->FileNameMTime.Modified();
5382   }
5383 }
5384 
SetXMLFileName(const char * fname)5385 void vtkExodusIIReader::SetXMLFileName( const char* fname )
5386 {
5387   vtkSetStringMacroBody(XMLFileName,fname);
5388   if ( modified )
5389   {
5390     this->XMLFileNameMTime.Modified();
5391     this->Modified();
5392   }
5393 }
5394 
5395 
5396 
5397 //----------------------------------------------------------------------------
ProcessRequest(vtkInformation * request,vtkInformationVector ** inputVector,vtkInformationVector * outputVector)5398 int vtkExodusIIReader::ProcessRequest(vtkInformation* request,
5399                                         vtkInformationVector** inputVector,
5400                                         vtkInformationVector* outputVector)
5401 {
5402   if(request->Has(vtkDemandDrivenPipeline::REQUEST_DATA()))
5403   {
5404     return this->RequestData(request, inputVector, outputVector);
5405   }
5406 
5407   // execute information
5408   if(request->Has(vtkDemandDrivenPipeline::REQUEST_INFORMATION()))
5409   {
5410     return this->RequestInformation(request, inputVector, outputVector);
5411   }
5412 
5413   return this->Superclass::ProcessRequest(request, inputVector, outputVector);
5414 }
5415 
5416 
5417 //----------------------------------------------------------------------------
RequestInformation(vtkInformation * vtkNotUsed (request),vtkInformationVector ** vtkNotUsed (inputVector),vtkInformationVector * outputVector)5418 int vtkExodusIIReader::RequestInformation(
5419   vtkInformation* vtkNotUsed(request),
5420   vtkInformationVector** vtkNotUsed(inputVector),
5421   vtkInformationVector* outputVector )
5422 {
5423   int newMetadata = 0;
5424   vtkInformation* outInfo = outputVector->GetInformationObject(0);
5425 
5426   // If the metadata is older than the filename
5427   if ( this->GetMetadataMTime() < this->FileNameMTime )
5428   {
5429     if ( this->Metadata->OpenFile( this->FileName ) )
5430     {
5431       // We need to initialize the XML parser before calling RequestInformation
5432       //    on the metadata
5433       if ( this->FindXMLFile() )
5434       {
5435         vtkExodusIIReaderParser *parser = vtkExodusIIReaderParser::New();
5436         this->Metadata->SetParser(parser);
5437         // Now overwrite any names in the exodus file with names from XML file.
5438         parser->Go(this->XMLFileName);
5439         parser->Delete();
5440       }
5441 
5442       this->Metadata->RequestInformation();
5443 
5444       // Now check to see if the DART metadata is valid
5445       if(this->Metadata->Parser && !this->Metadata->IsXMLMetadataValid())
5446       {
5447         this->Metadata->Parser->Delete();
5448         this->Metadata->Parser = nullptr;
5449 
5450         // Reset block names.
5451         int numBlocks = this->Metadata->GetNumberOfObjectsOfType(vtkExodusIIReader::ELEM_BLOCK);
5452         for (int cc=0; cc < numBlocks; cc++)
5453         {
5454           vtkExodusIIReaderPrivate::BlockInfoType* binfop =
5455             static_cast<vtkExodusIIReaderPrivate::BlockInfoType*>(
5456               this->Metadata->GetSortedObjectInfo(vtkExodusIIReader::ELEM_BLOCK, cc));
5457           binfop->Name = binfop->OriginalName;
5458         }
5459       }
5460 
5461       // Once meta-data has been refreshed we update the SIL.
5462       this->Metadata->BuildSIL();
5463       this->SILUpdateStamp++; // update the timestamp.
5464 
5465       this->Metadata->CloseFile();
5466       newMetadata = 1;
5467     }
5468     else
5469     {
5470       vtkErrorMacro( "Unable to open file \"" << (this->FileName ? this->FileName : "(null)") << "\" to read metadata" );
5471       return 0;
5472     }
5473   }
5474 
5475   this->AdvertiseTimeSteps( outInfo );
5476 
5477   // Advertize the SIL.
5478   outInfo->Set(vtkDataObject::SIL(), this->Metadata->GetSIL());
5479 
5480   if ( newMetadata )
5481   {
5482     // update ExodusModelMetadata
5483   }
5484 
5485   return 1;
5486 }
5487 
RequestData(vtkInformation * vtkNotUsed (request),vtkInformationVector ** vtkNotUsed (inputVector),vtkInformationVector * outputVector)5488 int vtkExodusIIReader::RequestData(
5489   vtkInformation* vtkNotUsed(request),
5490   vtkInformationVector** vtkNotUsed(inputVector),
5491   vtkInformationVector* outputVector )
5492 {
5493   if ( ! this->FileName || ! this->Metadata->OpenFile( this->FileName ) )
5494   {
5495     vtkErrorMacro( "Unable to open file \"" << (this->FileName ? this->FileName : "(null)") << "\" to read data" );
5496     return 0;
5497   }
5498 
5499   vtkInformation* outInfo = outputVector->GetInformationObject(0);
5500   vtkMultiBlockDataSet *output = vtkMultiBlockDataSet::SafeDownCast( outInfo->Get( vtkDataObject::DATA_OBJECT() ) );
5501 
5502   // Check if a particular time was requested.
5503   if ( outInfo->Has( vtkStreamingDemandDrivenPipeline::UPDATE_TIME_STEP() ) )
5504   { // Get the requested time step. We only support requests of a single time step in this reader right now
5505     double requestedTimeStep = outInfo->Get( vtkStreamingDemandDrivenPipeline::UPDATE_TIME_STEP());
5506 
5507     // Save the time value in the output data information.
5508     int length = outInfo->Length( vtkStreamingDemandDrivenPipeline::TIME_STEPS() );
5509     double* steps = outInfo->Get( vtkStreamingDemandDrivenPipeline::TIME_STEPS() );
5510 
5511     if ( ! this->GetHasModeShapes() )
5512     {
5513       // find the highest time step with a time value that is smaller than the requested time.
5514       //timeStep = 0;
5515       //while (timeStep < length - 1 && steps[timeStep] < requestedTimeStep)
5516       //  {
5517       //  timeStep++;
5518       //  }
5519       //this->TimeStep = timeStep;
5520 
5521       //find the timestep with the closest value
5522       int cnt=0;
5523       int closestStep=0;
5524       double minDist=-1;
5525       for (cnt=0;cnt<length;cnt++)
5526       {
5527         double tdist=(steps[cnt]-requestedTimeStep>requestedTimeStep-steps[cnt])?
5528           steps[cnt]-requestedTimeStep:
5529           requestedTimeStep-steps[cnt];
5530         if (minDist<0 || tdist<minDist)
5531         {
5532           minDist=tdist;
5533           closestStep=cnt;
5534         }
5535       }
5536       this->TimeStep=closestStep;
5537       //cout << "Requested value: " << requestedTimeStep << " Step: " << this->TimeStep << endl;
5538       output->GetInformation()->Set( vtkDataObject::DATA_TIME_STEP(), steps[this->TimeStep] );
5539     }
5540     else if (this->GetAnimateModeShapes())
5541     {
5542       // Let the metadata know the time value so that the Metadata->RequestData call below will generate
5543       // the animated mode shape properly.
5544       this->Metadata->ModeShapeTime = requestedTimeStep;
5545       output->GetInformation()->Set( vtkDataObject::DATA_TIME_STEP(), this->Metadata->ModeShapeTime );
5546       //output->GetInformation()->Remove( vtkDataObject::DATA_TIME_STEP() );
5547     }
5548   }
5549 
5550   this->Metadata->RequestData( this->TimeStep, output );
5551 
5552   return 1;
5553 }
5554 
GetMaxNameLength()5555 int vtkExodusIIReader::GetMaxNameLength()
5556 {
5557   return ex_inquire_int(this->Metadata->Exoid, EX_INQ_DB_MAX_USED_NAME_LENGTH);
5558 }
5559 
SetGenerateObjectIdCellArray(vtkTypeBool x)5560 void vtkExodusIIReader::SetGenerateObjectIdCellArray( vtkTypeBool x ) { this->Metadata->SetGenerateObjectIdArray( x ); }
GetGenerateObjectIdCellArray()5561 vtkTypeBool vtkExodusIIReader::GetGenerateObjectIdCellArray() { return this->Metadata->GetGenerateObjectIdArray(); }
5562 
SetGenerateGlobalElementIdArray(vtkTypeBool x)5563 void vtkExodusIIReader::SetGenerateGlobalElementIdArray( vtkTypeBool x ) { this->Metadata->SetGenerateGlobalElementIdArray( x ); }
GetGenerateGlobalElementIdArray()5564 vtkTypeBool vtkExodusIIReader::GetGenerateGlobalElementIdArray() { return this->Metadata->GetGenerateGlobalElementIdArray(); }
5565 
SetGenerateGlobalNodeIdArray(vtkTypeBool x)5566 void vtkExodusIIReader::SetGenerateGlobalNodeIdArray( vtkTypeBool x ) { this->Metadata->SetGenerateGlobalNodeIdArray( x ); }
GetGenerateGlobalNodeIdArray()5567 vtkTypeBool vtkExodusIIReader::GetGenerateGlobalNodeIdArray() { return this->Metadata->GetGenerateGlobalNodeIdArray(); }
5568 
SetGenerateImplicitElementIdArray(vtkTypeBool x)5569 void vtkExodusIIReader::SetGenerateImplicitElementIdArray( vtkTypeBool x ) { this->Metadata->SetGenerateImplicitElementIdArray( x ); }
GetGenerateImplicitElementIdArray()5570 vtkTypeBool vtkExodusIIReader::GetGenerateImplicitElementIdArray() { return this->Metadata->GetGenerateImplicitElementIdArray(); }
5571 
SetGenerateImplicitNodeIdArray(vtkTypeBool x)5572 void vtkExodusIIReader::SetGenerateImplicitNodeIdArray( vtkTypeBool x ) { this->Metadata->SetGenerateImplicitNodeIdArray( x ); }
GetGenerateImplicitNodeIdArray()5573 vtkTypeBool vtkExodusIIReader::GetGenerateImplicitNodeIdArray() { return this->Metadata->GetGenerateImplicitNodeIdArray(); }
5574 
SetGenerateFileIdArray(vtkTypeBool x)5575 void vtkExodusIIReader::SetGenerateFileIdArray( vtkTypeBool x ) { this->Metadata->SetGenerateFileIdArray( x ); }
GetGenerateFileIdArray()5576 vtkTypeBool vtkExodusIIReader::GetGenerateFileIdArray() { return this->Metadata->GetGenerateFileIdArray(); }
5577 
SetFileId(int x)5578 void vtkExodusIIReader::SetFileId( int x ) { this->Metadata->SetFileId( x ); }
GetFileId()5579 int vtkExodusIIReader::GetFileId() { return this->Metadata->GetFileId(); }
5580 
5581 // FIXME: Implement the four functions that return ID_NOT_FOUND below.
GetGlobalElementID(vtkDataSet * data,int localID)5582 int vtkExodusIIReader::GetGlobalElementID( vtkDataSet* data, int localID )
5583 { return GetGlobalElementID( data, localID, SEARCH_TYPE_ELEMENT_THEN_NODE ); }
GetGlobalElementID(vtkDataSet * data,int localID,int searchType)5584 int vtkExodusIIReader::GetGlobalElementID ( vtkDataSet* data, int localID, int searchType )
5585 { (void)data; (void)localID; (void)searchType; return ID_NOT_FOUND; }
5586 
GetGlobalFaceID(vtkDataSet * data,int localID)5587 int vtkExodusIIReader::GetGlobalFaceID( vtkDataSet* data, int localID )
5588 { return GetGlobalFaceID( data, localID, SEARCH_TYPE_ELEMENT_THEN_NODE ); }
GetGlobalFaceID(vtkDataSet * data,int localID,int searchType)5589 int vtkExodusIIReader::GetGlobalFaceID ( vtkDataSet* data, int localID, int searchType )
5590 { (void)data; (void)localID; (void)searchType; return ID_NOT_FOUND; }
5591 
GetGlobalEdgeID(vtkDataSet * data,int localID)5592 int vtkExodusIIReader::GetGlobalEdgeID( vtkDataSet* data, int localID )
5593 { return GetGlobalEdgeID( data, localID, SEARCH_TYPE_ELEMENT_THEN_NODE ); }
GetGlobalEdgeID(vtkDataSet * data,int localID,int searchType)5594 int vtkExodusIIReader::GetGlobalEdgeID ( vtkDataSet* data, int localID, int searchType )
5595 { (void)data; (void)localID; (void)searchType; return ID_NOT_FOUND; }
5596 
GetGlobalNodeID(vtkDataSet * data,int localID)5597 int vtkExodusIIReader::GetGlobalNodeID( vtkDataSet* data, int localID )
5598 { return GetGlobalNodeID( data, localID, SEARCH_TYPE_NODE_THEN_ELEMENT ); }
GetGlobalNodeID(vtkDataSet * data,int localID,int searchType)5599 int vtkExodusIIReader::GetGlobalNodeID( vtkDataSet* data, int localID, int searchType )
5600 { (void)data; (void)localID; (void)searchType; return ID_NOT_FOUND; }
5601 
SetApplyDisplacements(vtkTypeBool d)5602 void vtkExodusIIReader::SetApplyDisplacements( vtkTypeBool d )
5603 {
5604   this->Metadata->SetApplyDisplacements( d );
5605 }
GetApplyDisplacements()5606 vtkTypeBool vtkExodusIIReader::GetApplyDisplacements()
5607 {
5608   return this->Metadata->GetApplyDisplacements();
5609 }
5610 
SetDisplacementMagnitude(float s)5611 void vtkExodusIIReader::SetDisplacementMagnitude( float s )
5612 {
5613   this->Metadata->SetDisplacementMagnitude( s );
5614 }
GetDisplacementMagnitude()5615 float vtkExodusIIReader::GetDisplacementMagnitude()
5616 {
5617   return this->Metadata->GetDisplacementMagnitude();
5618 }
5619 
SetHasModeShapes(vtkTypeBool ms)5620 void vtkExodusIIReader::SetHasModeShapes( vtkTypeBool ms )
5621 {
5622   this->Metadata->SetHasModeShapes(ms);
5623 }
5624 
GetHasModeShapes()5625 vtkTypeBool vtkExodusIIReader::GetHasModeShapes()
5626 {
5627   return this->Metadata->GetHasModeShapes();
5628 }
5629 
SetModeShapeTime(double phase)5630 void vtkExodusIIReader::SetModeShapeTime( double phase )
5631 {
5632   // Phase should repeat outside the bounds [0,1].  For example, 0.25 is
5633   // equivalent to 1.25, 2.25, -0.75, and -1.75.
5634   double x = phase - floor(phase);
5635   this->Metadata->SetModeShapeTime( x );
5636 }
5637 
GetModeShapeTime()5638 double vtkExodusIIReader::GetModeShapeTime()
5639 {
5640   return this->Metadata->GetModeShapeTime();
5641 }
5642 
SetAnimateModeShapes(vtkTypeBool flag)5643 void vtkExodusIIReader::SetAnimateModeShapes(vtkTypeBool flag)
5644 {
5645   this->Metadata->SetAnimateModeShapes(flag);
5646 }
5647 
GetAnimateModeShapes()5648 vtkTypeBool vtkExodusIIReader::GetAnimateModeShapes()
5649 {
5650   return this->Metadata->GetAnimateModeShapes();
5651 }
5652 
SetIgnoreFileTime(bool value)5653 void vtkExodusIIReader::SetIgnoreFileTime(bool value)
5654 {
5655   if (this->Metadata->GetIgnoreFileTime() == value)
5656   {
5657     return;
5658   }
5659 
5660   this->Metadata->SetIgnoreFileTime(value);
5661   this->Modified();
5662 }
5663 
GetIgnoreFileTime()5664 bool vtkExodusIIReader::GetIgnoreFileTime()
5665 {
5666   return this->Metadata->GetIgnoreFileTime();
5667 }
5668 
GetTitle()5669 const char* vtkExodusIIReader::GetTitle() { return this->Metadata->ModelParameters.title; }
GetDimensionality()5670 int vtkExodusIIReader::GetDimensionality() { return this->Metadata->ModelParameters.num_dim; }
GetNumberOfTimeSteps()5671 int vtkExodusIIReader::GetNumberOfTimeSteps() { return (int) this->Metadata->Times.size(); }
5672 
GetNumberOfNodesInFile()5673 int vtkExodusIIReader::GetNumberOfNodesInFile() { return this->Metadata->ModelParameters.num_nodes; }
GetNumberOfEdgesInFile()5674 int vtkExodusIIReader::GetNumberOfEdgesInFile() { return this->Metadata->ModelParameters.num_edge; }
GetNumberOfFacesInFile()5675 int vtkExodusIIReader::GetNumberOfFacesInFile() { return this->Metadata->ModelParameters.num_face; }
GetNumberOfElementsInFile()5676 int vtkExodusIIReader::GetNumberOfElementsInFile() { return this->Metadata->ModelParameters.num_elem; }
5677 
GetNumberOfObjects(int objectType)5678 int vtkExodusIIReader::GetNumberOfObjects( int objectType )
5679 {
5680   return this->Metadata->GetNumberOfObjectsOfType( objectType );
5681 }
5682 
GetObjectTypeFromName(const char * name)5683 int vtkExodusIIReader::GetObjectTypeFromName( const char* name )
5684 {
5685   vtkStdString tname( name );
5686   if ( tname == "edge" ) return EDGE_BLOCK;
5687   else if ( tname == "face" ) return FACE_BLOCK;
5688   else if ( tname == "element" ) return ELEM_BLOCK;
5689   else if ( tname == "node set" ) return NODE_SET;
5690   else if ( tname == "edge set" ) return EDGE_SET;
5691   else if ( tname == "face set" ) return FACE_SET;
5692   else if ( tname == "side set" ) return SIDE_SET;
5693   else if ( tname == "element set" ) return ELEM_SET;
5694   else if ( tname == "node map" ) return NODE_MAP;
5695   else if ( tname == "edge map" ) return EDGE_MAP;
5696   else if ( tname == "face map" ) return FACE_MAP;
5697   else if ( tname == "element map" ) return ELEM_MAP;
5698   else if ( tname == "grid" ) return GLOBAL;
5699   else if ( tname == "node" ) return NODAL;
5700   else if ( tname == "assembly" ) return ASSEMBLY;
5701   else if ( tname == "part" ) return PART;
5702   else if ( tname == "material" ) return MATERIAL;
5703   else if ( tname == "hierarchy" ) return HIERARCHY;
5704   else if ( tname == "cell" ) return GLOBAL_CONN;
5705   else if ( tname == "element block cell" ) return ELEM_BLOCK_ELEM_CONN;
5706   else if ( tname == "element block face" ) return ELEM_BLOCK_FACE_CONN;
5707   else if ( tname == "element block edge" ) return ELEM_BLOCK_EDGE_CONN;
5708   else if ( tname == "face block cell" ) return FACE_BLOCK_CONN;
5709   else if ( tname == "edge block cell" ) return EDGE_BLOCK_CONN;
5710   else if ( tname == "element set cell" ) return ELEM_SET_CONN;
5711   else if ( tname == "side set cell" ) return SIDE_SET_CONN;
5712   else if ( tname == "face set cell" ) return FACE_SET_CONN;
5713   else if ( tname == "edge set cell" ) return EDGE_SET_CONN;
5714   else if ( tname == "node set cell" ) return NODE_SET_CONN;
5715   else if ( tname == "nodal coordinates" ) return NODAL_COORDS;
5716   else if ( tname == "object id" ) return OBJECT_ID;
5717   else if ( tname == "implicit element id" ) return IMPLICIT_ELEMENT_ID;
5718   else if ( tname == "implicit node id" ) return IMPLICIT_NODE_ID;
5719   else if ( tname == "global element id" ) return GLOBAL_ELEMENT_ID;
5720   else if ( tname == "global node id" ) return GLOBAL_NODE_ID;
5721   else if ( tname == "element id" ) return ELEMENT_ID;
5722   else if ( tname == "node id" ) return NODE_ID;
5723   else if ( tname == "pointmap" ) return NODAL_SQUEEZEMAP;
5724   return -1;
5725 }
5726 
GetObjectTypeName(int otyp)5727 const char* vtkExodusIIReader::GetObjectTypeName( int otyp )
5728 {
5729   switch ( otyp )
5730   {
5731   case EDGE_BLOCK: return "edge";
5732   case FACE_BLOCK: return "face";
5733   case ELEM_BLOCK: return "element";
5734   case NODE_SET: return "node set";
5735   case EDGE_SET: return "edge set";
5736   case FACE_SET: return "face set";
5737   case SIDE_SET: return "side set";
5738   case ELEM_SET: return "element set";
5739   case NODE_MAP: return "node map";
5740   case EDGE_MAP: return "edge map";
5741   case FACE_MAP: return "face map";
5742   case ELEM_MAP: return "element map";
5743   case GLOBAL: return "grid";
5744   case NODAL: return "node";
5745   case ASSEMBLY: return "assembly";
5746   case PART: return "part";
5747   case MATERIAL: return "material";
5748   case HIERARCHY: return "hierarchy";
5749   case GLOBAL_CONN: return "cell";
5750   case ELEM_BLOCK_ELEM_CONN: return "element block cell";
5751   case ELEM_BLOCK_FACE_CONN: return "element block face";
5752   case ELEM_BLOCK_EDGE_CONN: return "element block edge";
5753   case FACE_BLOCK_CONN: return "face block cell";
5754   case EDGE_BLOCK_CONN: return "edge block cell";
5755   case ELEM_SET_CONN: return "element set cell";
5756   case SIDE_SET_CONN: return "side set cell";
5757   case FACE_SET_CONN: return "face set cell";
5758   case EDGE_SET_CONN: return "edge set cell";
5759   case NODE_SET_CONN: return "node set cell";
5760   case NODAL_COORDS: return "nodal coordinates";
5761   case OBJECT_ID: return "object id";
5762   case IMPLICIT_ELEMENT_ID: return "implicit element id";
5763   case IMPLICIT_NODE_ID: return "implicit node id";
5764   case GLOBAL_ELEMENT_ID: return "global element id";
5765   case GLOBAL_NODE_ID: return "global node id";
5766   case ELEMENT_ID: return "element id";
5767   case NODE_ID: return "node id";
5768   case NODAL_SQUEEZEMAP: return "pointmap";
5769   }
5770   return nullptr;
5771 }
5772 
GetNumberOfNodes()5773 int vtkExodusIIReader::GetNumberOfNodes() { return this->Metadata->GetNumberOfNodes(); }
5774 
GetNumberOfEntriesInObject(int objectType,int objectIndex)5775 int vtkExodusIIReader::GetNumberOfEntriesInObject( int objectType, int objectIndex )
5776 {
5777   return this->Metadata->GetObjectSize( objectType, objectIndex );
5778 }
5779 
GetObjectId(int objectType,int objectIndex)5780 int vtkExodusIIReader::GetObjectId( int objectType, int objectIndex )
5781 {
5782   return this->Metadata->GetObjectId( objectType, objectIndex );
5783 }
5784 
GetObjectStatus(int objectType,int objectIndex)5785 int vtkExodusIIReader::GetObjectStatus( int objectType, int objectIndex )
5786 {
5787   return this->Metadata->GetObjectStatus( objectType, objectIndex );
5788 }
5789 
SetObjectStatus(int objectType,int objectIndex,int status)5790 void vtkExodusIIReader::SetObjectStatus( int objectType, int objectIndex, int status )
5791 {
5792   this->Metadata->SetObjectStatus( objectType, objectIndex, status );
5793 }
5794 
SetObjectStatus(int objectType,const char * objectName,int status)5795 void vtkExodusIIReader::SetObjectStatus( int objectType, const char* objectName, int status )
5796 {
5797   if(objectName && strlen(objectName)>0)
5798   {
5799     if(this->GetNumberOfObjects(objectType) == 0)
5800     {
5801       // The object status is being set before the meta data has been finalized
5802       // so cache this value for later and use as the initial value
5803       // If the number of objects really is zero then this doesn't do any harm.
5804       this->Metadata->SetInitialObjectStatus(objectType, objectName, status);
5805       return;
5806     }
5807     this->SetObjectStatus( objectType, this->GetObjectIndex( objectType, objectName ), status );
5808   }
5809 }
5810 
GetObjectName(int objectType,int objectIndex)5811 const char* vtkExodusIIReader::GetObjectName( int objectType, int objectIndex )
5812 {
5813   return this->Metadata->GetObjectName( objectType, objectIndex );
5814 }
5815 
GetObjectIndex(int objectType,const char * objectName)5816 int vtkExodusIIReader::GetObjectIndex( int objectType, const char* objectName )
5817 {
5818   if ( ! objectName )
5819   {
5820     vtkErrorMacro( "You must specify a non-nullptr name" );
5821     return -1;
5822   }
5823   int nObj = this->GetNumberOfObjects( objectType );
5824   if ( nObj == 0 )
5825   {
5826     vtkDebugMacro( "No objects of that type (" << objectType << ") to find index for given name " << objectName << "." );
5827     return -1;
5828   }
5829   vtkStdString objectRealName(objectName);
5830   size_t i = objectRealName.find(" Size: ");
5831   if(i!= vtkStdString::npos)
5832   {
5833     objectRealName.erase(i);
5834   }
5835   for ( int obj = 0; obj < nObj; ++obj )
5836   {
5837     const char* storedObjName = this->GetObjectName( objectType, obj );
5838     if(objectRealName == vtkStdString(storedObjName))
5839     {
5840       return obj;
5841     }
5842   }
5843   vtkDebugMacro( "No objects named \"" << objectName << "\" of the specified type (" << objectType <<  ")." );
5844   return -1;
5845 }
5846 
GetObjectIndex(int objectType,int id)5847 int vtkExodusIIReader::GetObjectIndex( int objectType, int id )
5848 {
5849   int nObj = this->GetNumberOfObjects( objectType );
5850   if ( nObj == 0 )
5851   {
5852     vtkDebugMacro( "No objects of that type (" << objectType << ") to find index for given id " << id << "." );
5853     return -1;
5854   }
5855   for ( int obj = 0; obj < nObj; ++obj )
5856   {
5857     if ( this->GetObjectId( objectType, obj ) == id)
5858     {
5859       return obj;
5860     }
5861   }
5862   vtkDebugMacro( "No objects with id \"" << id << "\" of the specified type (" << objectType <<  ")." );
5863   return -1;
5864 }
5865 
GetNumberOfObjectArrays(int objectType)5866 int vtkExodusIIReader::GetNumberOfObjectArrays( int objectType )
5867 {
5868   return this->Metadata->GetNumberOfObjectArraysOfType( objectType );
5869 }
5870 
GetObjectArrayName(int objectType,int arrayIndex)5871 const char* vtkExodusIIReader::GetObjectArrayName( int objectType, int arrayIndex )
5872 {
5873   return this->Metadata->GetObjectArrayName( objectType, arrayIndex );
5874 }
5875 
GetNumberOfObjectArrayComponents(int objectType,int arrayIndex)5876 int vtkExodusIIReader::GetNumberOfObjectArrayComponents( int objectType, int arrayIndex )
5877 {
5878   return this->Metadata->GetNumberOfObjectArrayComponents( objectType, arrayIndex );
5879 }
5880 
GetObjectArrayStatus(int objectType,int arrayIndex)5881 int vtkExodusIIReader::GetObjectArrayStatus( int objectType, int arrayIndex )
5882 {
5883   return this->Metadata->GetObjectArrayStatus( objectType, arrayIndex );
5884 }
5885 
SetObjectArrayStatus(int objectType,int arrayIndex,int status)5886 void vtkExodusIIReader::SetObjectArrayStatus( int objectType, int arrayIndex, int status )
5887 {
5888   this->Metadata->SetObjectArrayStatus( objectType, arrayIndex, status );
5889 }
5890 
SetObjectArrayStatus(int objectType,const char * arrayName,int status)5891 void vtkExodusIIReader::SetObjectArrayStatus( int objectType, const char* arrayName, int status )
5892 {
5893   if(arrayName && strlen(arrayName)>0)
5894   {
5895     if(this->GetNumberOfObjectArrays( objectType ) == 0)
5896     {
5897       // The array status is being set before the meta data has been finalized
5898       // so cache this value for later and use as the initial value
5899       // If the number of arrays really is zero then this doesn't do any harm.
5900       this->Metadata->SetInitialObjectArrayStatus(objectType, arrayName, status);
5901       return;
5902     }
5903     this->SetObjectArrayStatus( objectType, this->GetObjectArrayIndex( objectType, arrayName ), status );
5904   }
5905 }
5906 
GetNumberOfObjectAttributes(int objectType,int objectIndex)5907 int vtkExodusIIReader::GetNumberOfObjectAttributes( int objectType, int objectIndex )
5908 {
5909   return this->Metadata->GetNumberOfObjectAttributes( objectType, objectIndex );
5910 }
5911 
GetObjectAttributeName(int objectType,int objectIndex,int attribIndex)5912 const char* vtkExodusIIReader::GetObjectAttributeName( int objectType, int objectIndex, int attribIndex )
5913 {
5914   return this->Metadata->GetObjectAttributeName( objectType, objectIndex, attribIndex );
5915 }
5916 
GetObjectAttributeIndex(int objectType,int objectIndex,const char * attribName)5917 int vtkExodusIIReader::GetObjectAttributeIndex( int objectType, int objectIndex, const char* attribName )
5918 {
5919   return this->Metadata->GetObjectAttributeIndex( objectType, objectIndex, attribName );
5920 }
5921 
GetObjectAttributeStatus(int objectType,int objectIndex,int attribIndex)5922 int vtkExodusIIReader::GetObjectAttributeStatus( int objectType, int objectIndex, int attribIndex )
5923 {
5924   return this->Metadata->GetObjectAttributeStatus( objectType, objectIndex, attribIndex );
5925 }
5926 
SetObjectAttributeStatus(int objectType,int objectIndex,int attribIndex,int status)5927 void vtkExodusIIReader::SetObjectAttributeStatus( int objectType, int objectIndex, int attribIndex, int status )
5928 {
5929   this->Metadata->SetObjectAttributeStatus( objectType, objectIndex, attribIndex, status );
5930 }
5931 
GetObjectArrayIndex(int objectType,const char * arrayName)5932 int vtkExodusIIReader::GetObjectArrayIndex( int objectType, const char* arrayName )
5933 {
5934   if ( ! arrayName )
5935   {
5936     vtkErrorMacro( "You must specify a non-nullptr name" );
5937     return -1;
5938   }
5939   int nObj = this->GetNumberOfObjectArrays( objectType );
5940   if ( nObj == 0 )
5941   {
5942     vtkDebugMacro( "No objects of that type (" << objectType << ") to find index for given array " << arrayName << "." );
5943     return -1;
5944   }
5945   for ( int obj = 0; obj < nObj; ++obj )
5946   {
5947     if ( !strcmp( arrayName, this->GetObjectArrayName( objectType, obj ) ) )
5948     {
5949       return obj;
5950     }
5951   }
5952   vtkDebugMacro( "No arrays named \"" << arrayName << "\" of the specified type (" << objectType <<  ")." );
5953   return -1;
5954 }
5955 
GetTotalNumberOfNodes()5956 vtkIdType vtkExodusIIReader::GetTotalNumberOfNodes() { return this->Metadata->GetModelParams()->num_nodes; }
GetTotalNumberOfEdges()5957 vtkIdType vtkExodusIIReader::GetTotalNumberOfEdges() { return this->Metadata->GetModelParams()->num_edge; }
GetTotalNumberOfFaces()5958 vtkIdType vtkExodusIIReader::GetTotalNumberOfFaces() { return this->Metadata->GetModelParams()->num_face; }
GetTotalNumberOfElements()5959 vtkIdType vtkExodusIIReader::GetTotalNumberOfElements() { return this->Metadata->GetModelParams()->num_elem; }
5960 
5961 // %---------------------------------------------------------------------------
GetNumberOfPartArrays()5962 int vtkExodusIIReader::GetNumberOfPartArrays()
5963 {
5964   return this->Metadata->GetNumberOfParts();
5965 }
5966 
GetPartArrayName(int arrayIdx)5967 const char* vtkExodusIIReader::GetPartArrayName( int arrayIdx )
5968 {
5969   return this->Metadata->GetPartName(arrayIdx);
5970 }
5971 
GetPartArrayID(const char * name)5972 int vtkExodusIIReader::GetPartArrayID( const char *name )
5973 {
5974   int numArrays = this->GetNumberOfPartArrays();
5975   for ( int i=0;i<numArrays;i++ )
5976   {
5977     if ( strcmp( name, this->GetPartArrayName( i ) ) == 0 )
5978     {
5979       return i;
5980     }
5981   }
5982   return -1;
5983 }
5984 
GetPartBlockInfo(int arrayIdx)5985 const char* vtkExodusIIReader::GetPartBlockInfo( int arrayIdx )
5986 {
5987   return this->Metadata->GetPartBlockInfo(arrayIdx);
5988 }
5989 
SetPartArrayStatus(int index,int flag)5990 void vtkExodusIIReader::SetPartArrayStatus( int index, int flag )
5991 {
5992   // Only modify if we are 'out of sync'
5993   if (this->Metadata->GetPartStatus(index) != flag)
5994   {
5995     this->Metadata->SetPartStatus(index, flag);
5996 
5997     // Because which parts are on/off affects the
5998     // geometry we need to remake the mesh cache
5999     //this->RemakeDataCacheFlag = 1;
6000     this->Modified();
6001   }
6002 }
6003 
SetPartArrayStatus(const char * name,int flag)6004 void vtkExodusIIReader::SetPartArrayStatus( const char* name, int flag )
6005 {
6006   // Only modify if we are 'out of sync'
6007   if (this->Metadata->GetPartStatus(name) != flag)
6008   {
6009     this->Metadata->SetPartStatus(name, flag);
6010 
6011     // Because which parts are on/off affects the
6012     // geometry we need to remake the mesh cache
6013     //this->RemakeDataCacheFlag = 1;
6014     this->Modified();
6015   }
6016 }
6017 
GetPartArrayStatus(int index)6018 int vtkExodusIIReader::GetPartArrayStatus( int index )
6019 {
6020   return this->Metadata->GetPartStatus(index);
6021 }
6022 
GetPartArrayStatus(const char * part)6023 int vtkExodusIIReader::GetPartArrayStatus( const char* part )
6024 {
6025   return this->Metadata->GetPartStatus(part);
6026 }
6027 
GetNumberOfMaterialArrays()6028 int vtkExodusIIReader::GetNumberOfMaterialArrays()
6029 {
6030   return this->Metadata->GetNumberOfMaterials();
6031 }
6032 
GetMaterialArrayName(int arrayIdx)6033 const char* vtkExodusIIReader::GetMaterialArrayName( int arrayIdx )
6034 {
6035   return this->Metadata->GetMaterialName(arrayIdx);
6036 }
6037 
GetMaterialArrayID(const char * matl)6038 int vtkExodusIIReader::GetMaterialArrayID( const char* matl )
6039 {
6040   (void)matl;
6041   return 0;
6042 }
6043 
SetMaterialArrayStatus(int index,int flag)6044 void vtkExodusIIReader::SetMaterialArrayStatus( int index, int flag )
6045 {
6046   // Only modify if we are 'out of sync'
6047   if (this->Metadata->GetMaterialStatus(index) != flag)
6048   {
6049     this->Metadata->SetMaterialStatus(index, flag);
6050 
6051     // Because which materials are on/off affects the
6052     // geometry we need to remake the mesh cache
6053     //this->RemakeDataCacheFlag = 1;
6054     this->Modified();
6055   }
6056 }
6057 
SetMaterialArrayStatus(const char * matl,int flag)6058 void vtkExodusIIReader::SetMaterialArrayStatus( const char* matl, int flag )
6059 {
6060   // Only modify if we are 'out of sync'
6061   if (this->Metadata->GetMaterialStatus(matl) != flag)
6062   {
6063     this->Metadata->SetMaterialStatus(matl, flag);
6064 
6065     // Because which materials are on/off affects the
6066     // geometry we need to remake the mesh cache
6067     //this->RemakeDataCacheFlag = 1;
6068     this->Modified();
6069   }
6070 }
6071 
GetMaterialArrayStatus(int index)6072 int vtkExodusIIReader::GetMaterialArrayStatus( int index )
6073 {
6074   return this->Metadata->GetMaterialStatus(index);
6075 }
6076 
GetMaterialArrayStatus(const char * matl)6077 int vtkExodusIIReader::GetMaterialArrayStatus( const char* matl )
6078 {
6079   return this->Metadata->GetMaterialStatus(matl);
6080 }
6081 
GetNumberOfAssemblyArrays()6082 int vtkExodusIIReader::GetNumberOfAssemblyArrays()
6083 {
6084   return this->Metadata->GetNumberOfAssemblies();
6085 }
6086 
GetAssemblyArrayName(int arrayIdx)6087 const char* vtkExodusIIReader::GetAssemblyArrayName( int arrayIdx )
6088 {
6089   return this->Metadata->GetAssemblyName(arrayIdx);
6090 }
6091 
GetAssemblyArrayID(const char * name)6092 int vtkExodusIIReader::GetAssemblyArrayID( const char* name )
6093 {
6094   int numArrays = this->GetNumberOfAssemblyArrays();
6095   for ( int i=0;i<numArrays;i++ )
6096   {
6097     if ( strcmp( name, this->GetAssemblyArrayName( i ) ) == 0 )
6098     {
6099       return i;
6100     }
6101   }
6102   return -1;
6103 }
6104 
6105 
SetAssemblyArrayStatus(int index,int flag)6106 void vtkExodusIIReader::SetAssemblyArrayStatus(int index, int flag)
6107 {
6108   // Only modify if we are 'out of sync'
6109   if (this->Metadata->GetAssemblyStatus(index) != flag)
6110   {
6111     this->Metadata->SetAssemblyStatus(index, flag);
6112 
6113     // Because which materials are on/off affects the
6114     // geometry we need to remake the mesh cache
6115     //this->RemakeDataCacheFlag = 1;
6116     this->Modified();
6117   }
6118 }
6119 
SetAssemblyArrayStatus(const char * name,int flag)6120 void vtkExodusIIReader::SetAssemblyArrayStatus(const char* name, int flag)
6121 {
6122   // Only modify if we are 'out of sync'
6123   if (this->Metadata->GetAssemblyStatus(name) != flag)
6124   {
6125     this->Metadata->SetAssemblyStatus(name, flag);
6126 
6127     // Because which materials are on/off affects the
6128     // geometry we need to remake the mesh cache
6129     //this->RemakeDataCacheFlag = 1;
6130     this->Modified();
6131   }
6132 }
6133 
6134 
GetAssemblyArrayStatus(int index)6135 int vtkExodusIIReader::GetAssemblyArrayStatus(int index)
6136 {
6137   return this->Metadata->GetAssemblyStatus(index);
6138 }
6139 
GetAssemblyArrayStatus(const char * name)6140 int vtkExodusIIReader::GetAssemblyArrayStatus(const char* name)
6141 {
6142   return this->Metadata->GetAssemblyStatus(name);
6143 }
6144 
GetNumberOfHierarchyArrays()6145 int vtkExodusIIReader::GetNumberOfHierarchyArrays()
6146 {
6147   //if (this->Metadata->Parser)
6148   //  {
6149   //  return this->Metadata->Parser->GetNumberOfHierarchyEntries();
6150   //  }
6151   return 0;
6152 }
6153 
6154 
GetHierarchyArrayName(int vtkNotUsed (arrayIdx))6155 const char* vtkExodusIIReader::GetHierarchyArrayName(int vtkNotUsed(arrayIdx))
6156 {
6157   //if (this->Metadata->Parser)
6158   //  {
6159   //  this->Metadata->Parser->SetCurrentHierarchyEntry(arrayIdx);
6160   //  return this->Metadata->Parser->GetCurrentHierarchyEntry();
6161   //  }
6162   return "Should not see this";
6163 }
6164 
SetHierarchyArrayStatus(int vtkNotUsed (index),int vtkNotUsed (flag))6165 void vtkExodusIIReader::SetHierarchyArrayStatus(int vtkNotUsed(index), int vtkNotUsed(flag))
6166 {
6167   //// Only modify if we are 'out of sync'
6168   ////if (this->GetHierarchyArrayStatus(index) != flag)
6169   //// {
6170   //if (this->Metadata->Parser)
6171   //  {
6172   //  std::vector<int> blocksIds = this->Metadata->Parser->GetBlocksForEntry(index);
6173   //  for (std::vector<int>::size_type i=0;i<blocksIds.size();i++)
6174   //    {
6175   //    this->Metadata->SetObjectStatus(vtkExodusIIReader::ELEM_BLOCK,
6176   //      this->GetObjectIndex(ELEM_BLOCK,blocksIds[i]),flag);
6177   //    }
6178   //
6179   //  // Because which materials are on/off affects the
6180   //  // geometry we need to remake the mesh cache
6181   //  //this->RemakeDataCacheFlag = 1;
6182   //  this->Modified();
6183   //  }
6184 }
6185 
SetHierarchyArrayStatus(const char * vtkNotUsed (name),int vtkNotUsed (flag))6186 void vtkExodusIIReader::SetHierarchyArrayStatus(const char* vtkNotUsed(name), int vtkNotUsed(flag))
6187 {
6188   //// Only modify if we are 'out of sync'
6189   ////if (this->GetHierarchyArrayStatus(name) != flag)
6190   ////{
6191   //if (this->Metadata->Parser)
6192   //  {
6193   //  std::vector<int> blocksIds=this->Metadata->Parser->GetBlocksForEntry
6194   //    (vtkStdString(name));
6195   //  for (std::vector<int>::size_type i=0;i<blocksIds.size();i++)
6196   //    {
6197   //    //cout << "turning block " << blocks[i] << " " << flag << endl;
6198   //    this->Metadata->SetObjectStatus(vtkExodusIIReader::ELEM_BLOCK,
6199   //      this->GetObjectIndex(ELEM_BLOCK,blocksIds[i]),flag);
6200   //    }
6201   //
6202   //  // Because which materials are on/off affects the
6203   //  // geometry we need to remake the mesh cache
6204   //  //this->RemakeDataCacheFlag = 1;
6205   //  this->Modified();
6206   //  }
6207 }
6208 
6209 //-----------------------------------------------------------------------------
GetHierarchyArrayStatus(int vtkNotUsed (index))6210 int vtkExodusIIReader::GetHierarchyArrayStatus(int vtkNotUsed(index))
6211 {
6212   //if (this->Metadata->Parser)
6213   //  {
6214   //  std::vector<int> blocksIds=this->Metadata->Parser->GetBlocksForEntry(index);
6215   //  for (std::vector<int>::size_type i=0;i<blocksIds.size();i++)
6216   //    {
6217   //    if (this->Metadata->GetObjectStatus(vtkExodusIIReader::ELEM_BLOCK,
6218   //        this->GetObjectIndex(ELEM_BLOCK,blocksIds[i]))==0)
6219   //      return 0;
6220   //    }
6221   //  }
6222   return 1;
6223 }
6224 
6225 //-----------------------------------------------------------------------------
GetHierarchyArrayStatus(const char * vtkNotUsed (name))6226 int vtkExodusIIReader::GetHierarchyArrayStatus(const char* vtkNotUsed(name))
6227 {
6228   //if (this->Metadata->Parser)
6229   //  {
6230   //  std::vector<int> blocksIds=this->Metadata->Parser->GetBlocksForEntry(name);
6231   //  for (std::vector<int>::size_type i=0;i<blocksIds.size();i++)
6232   //    {
6233   //    if (this->Metadata->GetObjectStatus(vtkExodusIIReader::ELEM_BLOCK,
6234   //        this->GetObjectIndex(ELEM_BLOCK,blocksIds[i]))==0)
6235   //      return 0;
6236   //    }
6237   //  }
6238   return 1;
6239 }
6240 
6241 //-----------------------------------------------------------------------------
GetSIL()6242 vtkGraph* vtkExodusIIReader::GetSIL()
6243 {
6244   return this->Metadata->GetSIL();
6245 }
6246 
6247 //-----------------------------------------------------------------------------
SetDisplayType(int typ)6248 void vtkExodusIIReader::SetDisplayType( int typ )
6249 {
6250   if ( typ == this->DisplayType || typ < 0 || typ > 2 )
6251     return;
6252 
6253   this->DisplayType = typ;
6254   this->Modified();
6255 }
6256 
6257 //-----------------------------------------------------------------------------
IsValidVariable(const char * type,const char * name)6258 int vtkExodusIIReader::IsValidVariable( const char *type, const char *name )
6259 {
6260   return (this->GetVariableID( type, name ) >= 0);
6261 }
6262 
6263 //-----------------------------------------------------------------------------
GetVariableID(const char * type,const char * name)6264 int vtkExodusIIReader::GetVariableID( const char *type, const char *name )
6265 {
6266   int otyp = this->GetObjectTypeFromName( type );
6267   if ( otyp < 0 )
6268   {
6269     return 0;
6270   }
6271   switch ( otyp )
6272   {
6273   case NODAL:
6274   case EDGE_BLOCK:
6275   case FACE_BLOCK:
6276   case ELEM_BLOCK:
6277   case NODE_SET:
6278   case EDGE_SET:
6279   case FACE_SET:
6280   case SIDE_SET:
6281   case ELEM_SET:
6282     return this->GetObjectArrayIndex( otyp, name );
6283   case ASSEMBLY:
6284     return this->GetAssemblyArrayID( name );
6285   case HIERARCHY:
6286     return -1; // FIXME: There is no this->GetHierarchyArrayID( name ) and it's not clear there should be.
6287   case MATERIAL:
6288     return this->GetMaterialArrayID( name );
6289   case PART:
6290     return this->GetPartArrayID( name );
6291   default:
6292     return -1;
6293   }
6294 }
6295 
GetTimeSeriesData(int ID,const char * vName,const char * vType,vtkFloatArray * result)6296 int vtkExodusIIReader::GetTimeSeriesData( int ID, const char* vName, const char* vType, vtkFloatArray* result )
6297 {
6298   (void)ID;
6299   (void)vName;
6300   (void)vType;
6301   (void)result;
6302   return -1;
6303 }
6304 
SetAllArrayStatus(int otyp,int status)6305 void vtkExodusIIReader::SetAllArrayStatus( int otyp, int status )
6306 {
6307   int numObj;
6308   int i;
6309   switch ( otyp )
6310   {
6311   case EDGE_BLOCK_CONN:
6312   case FACE_BLOCK_CONN:
6313   case ELEM_BLOCK_ELEM_CONN:
6314   case NODE_SET_CONN:
6315   case EDGE_SET_CONN:
6316   case FACE_SET_CONN:
6317   case SIDE_SET_CONN:
6318   case ELEM_SET_CONN:
6319   { // Convert the "connectivity" type into an "object" type:
6320       int ctypidx = this->Metadata->GetConnTypeIndexFromConnType(otyp);
6321       int otypidx = conn_obj_idx_cvt[ctypidx];
6322       otyp = obj_types[otypidx];
6323       // Now set the status
6324       numObj = this->GetNumberOfObjects( otyp );
6325       for ( i = 0; i < numObj; ++i )
6326       {
6327         this->SetObjectStatus( otyp, i, status );
6328       }
6329   }
6330     break;
6331   case NODAL:
6332   case GLOBAL:
6333   case EDGE_BLOCK:
6334   case FACE_BLOCK:
6335   case ELEM_BLOCK:
6336   case NODE_SET:
6337   case EDGE_SET:
6338   case FACE_SET:
6339   case SIDE_SET:
6340   case ELEM_SET:
6341     numObj = this->GetNumberOfObjectArrays( otyp );
6342     for ( i = 0; i < numObj; ++i )
6343     {
6344       this->SetObjectArrayStatus( otyp, i, status );
6345     }
6346     break;
6347   // ---------------------
6348   case ASSEMBLY:
6349     numObj = this->GetNumberOfAssemblyArrays();
6350     for ( i = 0; i < numObj; ++i )
6351     {
6352       this->SetAssemblyArrayStatus( i, status );
6353     }
6354     VTK_FALLTHROUGH;
6355   case PART:
6356     numObj = this->GetNumberOfPartArrays();
6357     for ( i = 0; i < numObj; ++i )
6358     {
6359       this->SetPartArrayStatus( i, status );
6360     }
6361     VTK_FALLTHROUGH;
6362   case MATERIAL:
6363     numObj = this->GetNumberOfMaterialArrays();
6364     for ( i = 0; i < numObj; ++i )
6365     {
6366       this->SetMaterialArrayStatus( i, status );
6367     }
6368     VTK_FALLTHROUGH;
6369   case HIERARCHY:
6370     numObj = this->GetNumberOfHierarchyArrays();
6371     for ( i = 0; i < numObj; ++i )
6372     {
6373       this->SetHierarchyArrayStatus( i, status );
6374     }
6375     break;
6376   default:
6377     break;
6378   }
6379 }
6380 
Dump()6381 void vtkExodusIIReader::Dump()
6382 {
6383   vtkIndent indent;
6384   this->PrintSelf( cout, indent );
6385 }
6386 
6387 
FindXMLFile()6388 bool vtkExodusIIReader::FindXMLFile()
6389 {
6390   // If the XML filename exists and is newer than any existing parser (or there is no parser), reread XML file.
6391   if (
6392     ( this->Metadata->Parser && this->Metadata->Parser->GetMTime() < this->XMLFileNameMTime && this->XMLFileName ) ||
6393     ( ! Metadata->Parser ) )
6394   {
6395     if ( Metadata->Parser )
6396     {
6397       Metadata->Parser->Delete();
6398       Metadata->Parser = nullptr;
6399     }
6400 
6401     if ( ! this->XMLFileName || ! vtksys::SystemTools::FileExists( this->XMLFileName ) )
6402     {
6403       if ( this->FileName )
6404       {
6405         // Catch the case where filename was non-nullptr but didn't exist.
6406         this->SetXMLFileName( nullptr );
6407       }
6408     }
6409     else
6410     {
6411       return true;
6412     }
6413   }
6414 
6415   return false;
6416 }
6417 
AdvertiseTimeSteps(vtkInformation * outInfo)6418 void vtkExodusIIReader::AdvertiseTimeSteps( vtkInformation* outInfo )
6419 {
6420   // This method is called in vtkExodusIIReader::RequestInformation() to update
6421   // information about timesteps. Since this gets called after this->Metadata
6422   // has processed the file meta-data it's a good place to update iVars that
6423   // reflect the meta-data read from the file about timesteps/mode shapes.
6424 
6425   int nTimes = static_cast<int>(this->Metadata->Times.size());
6426   this->TimeStepRange[0] = 0;
6427   this->TimeStepRange[1] = (nTimes > 0)? (nTimes-1) : 0;
6428 
6429   // Since modeshape range is 1 indexed.
6430   this->ModeShapesRange[0] = this->TimeStepRange[0] + 1;
6431   this->ModeShapesRange[1] = this->TimeStepRange[1] + 1;
6432 
6433   if ( ! this->GetHasModeShapes() )
6434   {
6435     if (this->GetIgnoreFileTime())
6436     {
6437       std::vector<double> times(nTimes);
6438       for (size_t i = 0; i < times.size(); ++i)
6439       {
6440         times[i] = i;
6441       }
6442       double timeRange[2];
6443       timeRange[0] = 0;
6444       timeRange[1] = nTimes - 1;
6445       outInfo->Set(vtkStreamingDemandDrivenPipeline::TIME_STEPS(), &times[0], nTimes);
6446       outInfo->Set(vtkStreamingDemandDrivenPipeline::TIME_RANGE(), timeRange, 2);
6447     }
6448     else
6449     {
6450       if ( nTimes )
6451       {
6452         double timeRange[2];
6453         timeRange[0] = this->Metadata->Times[0];
6454         timeRange[1] = this->Metadata->Times[nTimes - 1];
6455         outInfo->Set( vtkStreamingDemandDrivenPipeline::TIME_STEPS(), &this->Metadata->Times[0], nTimes );
6456         outInfo->Set( vtkStreamingDemandDrivenPipeline::TIME_RANGE(), timeRange, 2 );
6457       }
6458     }
6459   }
6460   else if (this->GetAnimateModeShapes())
6461   {
6462     outInfo->Remove( vtkStreamingDemandDrivenPipeline::TIME_STEPS() );
6463     static double timeRange[] = { 0, 1 };
6464     outInfo->Set( vtkStreamingDemandDrivenPipeline::TIME_RANGE(), timeRange, 2 );
6465   }
6466   else
6467   {
6468     outInfo->Remove(vtkStreamingDemandDrivenPipeline::TIME_STEPS());
6469     outInfo->Remove(vtkStreamingDemandDrivenPipeline::TIME_RANGE());
6470   }
6471 }
6472 
Reset()6473 void vtkExodusIIReader::Reset()
6474 {
6475   this->Metadata->Reset();
6476   this->Metadata->ResetSettings();
6477 }
6478 
ResetSettings()6479 void vtkExodusIIReader::ResetSettings()
6480 {
6481   this->Metadata->ResetSettings();
6482 }
6483 
SetCacheSize(double CacheSize)6484 void vtkExodusIIReader::SetCacheSize(double CacheSize)
6485 {
6486   this->Metadata->SetCacheSize(CacheSize);
6487 }
6488 
GetCacheSize()6489 double vtkExodusIIReader::GetCacheSize()
6490 {
6491   return this->Metadata->GetCacheSize();
6492 }
6493 
SetSqueezePoints(bool sp)6494 void vtkExodusIIReader::SetSqueezePoints(bool sp)
6495 {
6496   this->Metadata->SetSqueezePoints(sp ? 1 : 0);
6497 }
6498 
GetSqueezePoints()6499 bool vtkExodusIIReader::GetSqueezePoints()
6500 {
6501   return this->Metadata->GetSqueezePoints() != 0;
6502 }
6503 
ResetCache()6504 void vtkExodusIIReader::ResetCache()
6505 {
6506   this->Metadata->ResetCache();
6507 }
6508