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