/*========================================================================= Program: Visualization Toolkit Module: vtkExodusIIReader.cxx Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen All rights reserved. See Copyright.txt or http://www.kitware.com/Copyright.htm for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notice for more information. =========================================================================*/ /*---------------------------------------------------------------------------- Copyright (c) Sandia Corporation See Copyright.txt or http://www.paraview.org/HTML/Copyright.html for details. ----------------------------------------------------------------------------*/ #include "vtkExodusIIReader.h" #include "vtkExodusIICache.h" #include "vtkCellArray.h" #include "vtkCellData.h" #include "vtkCellType.h" #include "vtkCharArray.h" #include "vtkDoubleArray.h" #include "vtkExodusIIReaderParser.h" #include "vtkFloatArray.h" #include "vtkIdTypeArray.h" #include "vtkInformation.h" #include "vtkInformationIntegerKey.h" #include "vtkInformationVector.h" #include "vtkIntArray.h" #include "vtkLogger.h" #include "vtkMath.h" #include "vtkMultiBlockDataSet.h" #include "vtkMutableDirectedGraph.h" #include "vtkNew.h" #include "vtkObjectFactory.h" #include "vtkPointData.h" #include "vtkPoints.h" #include "vtkPolyData.h" #include "vtkSmartPointer.h" #include "vtkSortDataArray.h" #include "vtkStdString.h" #include "vtkStreamingDemandDrivenPipeline.h" #include "vtkStringArray.h" #include "vtkTypeInt64Array.h" #include "vtkUnsignedCharArray.h" #include "vtkUnstructuredGrid.h" #include "vtkVariantArray.h" #include "vtkXMLParser.h" #include "vtksys/SystemTools.hxx" #include #include #include #include #include #include #include "vtksys/RegularExpression.hxx" #include "vtk_exodusII.h" #include /* for toupper(), isgraph() */ #include /* for cos() */ #include #include /* for free() */ #include /* for memset() */ #ifdef EXODUSII_HAVE_MALLOC_H #include #endif /* EXODUSII_HAVE_MALLOC_H */ /// Define this to get printouts summarizing array glomming process #undef VTK_DBG_GLOM #define VTK_EXO_FUNC(funcall, errmsg) \ if ((funcall) < 0) \ { \ vtkErrorMacro(errmsg); \ return 1; \ } // ------------------------------------------------------------------- CONSTANTS static int obj_types[] = { EX_EDGE_BLOCK, EX_FACE_BLOCK, EX_ELEM_BLOCK, EX_NODE_SET, EX_EDGE_SET, EX_FACE_SET, EX_SIDE_SET, EX_ELEM_SET, EX_NODE_MAP, EX_EDGE_MAP, EX_FACE_MAP, EX_ELEM_MAP, EX_NODAL }; static int num_obj_types = (int)(sizeof(obj_types) / sizeof(obj_types[0])); static ex_inquiry obj_sizes[] = { EX_INQ_EDGE_BLK, EX_INQ_FACE_BLK, EX_INQ_ELEM_BLK, EX_INQ_NODE_SETS, EX_INQ_EDGE_SETS, EX_INQ_FACE_SETS, EX_INQ_SIDE_SETS, EX_INQ_ELEM_SETS, EX_INQ_NODE_MAP, EX_INQ_EDGE_MAP, EX_INQ_FACE_MAP, EX_INQ_ELEM_MAP, EX_INQ_NODES }; static const char* objtype_names[] = { "Edge block", "Face block", "Element block", "Node set", "Edge set", "Face set", "Side set", "Element set", "Node map", "Edge map", "Face map", "Element map", "Nodal" }; static const char* obj_typestr[] = { "L", "F", "E", "M", "D", "A", "S", "T", nullptr, /* maps have no result variables */ nullptr, nullptr, nullptr, "N" }; #define OBJTYPE_IS_BLOCK(i) (((i) >= 0) && ((i) < 3)) #define OBJTYPE_IS_SET(i) (((i) > 2) && ((i) < 8)) #define OBJTYPE_IS_MAP(i) (((i) > 7) && ((i) < 12)) #define OBJTYPE_IS_NODAL(i) ((i) == 12) // Unlike obj* items above: // - conn* arrays only reference objects that generate connectivity information // - conn* arrays are ordered the way users expect the output (*not* the same as above) static int conn_types[] = { vtkExodusIIReader::ELEM_BLOCK_ELEM_CONN, vtkExodusIIReader::FACE_BLOCK_CONN, vtkExodusIIReader::EDGE_BLOCK_CONN, vtkExodusIIReader::ELEM_SET_CONN, vtkExodusIIReader::SIDE_SET_CONN, vtkExodusIIReader::FACE_SET_CONN, vtkExodusIIReader::EDGE_SET_CONN, vtkExodusIIReader::NODE_SET_CONN }; static const char* conn_types_names[] = { "Element Blocks", "Face Blocks", "Edge Blocks", "Element Sets", "Side Sets", "Face Sets", "Edge Sets", "Node Sets" }; static int num_conn_types = (int)(sizeof(conn_types) / sizeof(conn_types[0])); // Given a conn_type index, what is its matching obj_type index? static int conn_obj_idx_cvt[] = { 2, 1, 0, 7, 6, 5, 4, 3 }; #define CONNTYPE_IS_BLOCK(i) (((i) >= 0) && ((i) < 3)) #define CONNTYPE_IS_SET(i) (((i) > 2) && ((i) < 8)) static const char* glomTypeNames[] = { "Scalar", "Vector2", "Vector3", "Symmetric Tensor", "Integration Point Values" }; // used to store pointer to ex_get_node_num_map or ex_get_elem_num_map: extern "C" { typedef int (*vtkExodusIIGetMapFunc)(int, int*); } // --------------------------------------------------- PRIVATE CLASS DECLARATION #include "vtkExodusIIReaderPrivate.h" #include "vtkExodusIIReaderVariableCheck.h" // --------------------------------------------------- PRIVATE CLASS Implementations vtkExodusIIReaderPrivate::BlockSetInfoType::BlockSetInfoType( const vtkExodusIIReaderPrivate::BlockSetInfoType& block) : vtkExodusIIReaderPrivate::ObjectInfoType(block) , FileOffset(block.FileOffset) , PointMap(block.PointMap) , ReversePointMap(block.ReversePointMap) , CachedConnectivity(nullptr) { // this is needed to properly manage memory. // when vectors are resized or reserved the container // might be copied to a memory spot, so we need a proper copy constructor // so that the cache remains valid this->CachedConnectivity = block.CachedConnectivity; } vtkExodusIIReaderPrivate::BlockSetInfoType::~BlockSetInfoType() { if (this->CachedConnectivity) { this->CachedConnectivity->Delete(); } } vtkExodusIIReaderPrivate::BlockSetInfoType& vtkExodusIIReaderPrivate::BlockSetInfoType::operator=( const vtkExodusIIReaderPrivate::BlockSetInfoType& block) { // protect against invalid self-assignment if (this != &block) { // superclass this->ObjectInfoType::operator=(static_cast(block)); // delete existing if (this->CachedConnectivity) { this->CachedConnectivity->Delete(); this->CachedConnectivity = nullptr; } this->FileOffset = block.FileOffset; this->PointMap = block.PointMap; this->ReversePointMap = block.ReversePointMap; this->NextSqueezePoint = block.NextSqueezePoint; if (block.CachedConnectivity) { this->CachedConnectivity = vtkUnstructuredGrid::New(); this->CachedConnectivity->ShallowCopy(block.CachedConnectivity); } } return *this; } // ----------------------------------------------------------- UTILITY ROUTINES // This function exists because FORTRAN ordering sucks. static void extractTruthForVar( int num_obj, int num_vars, const int* truth_tab, int var, std::vector& truth) { truth.clear(); int obj; int ttObj; // truth table entry for variable var on object obj. for (obj = 0; obj < num_obj; ++obj) { ttObj = truth_tab[var + obj * num_vars]; truth.push_back(ttObj); } } static void printBlock( ostream& os, vtkIndent indent, int btyp, vtkExodusIIReaderPrivate::BlockInfoType& binfo) { int b = 0; while (obj_types[b] >= 0 && obj_types[b] != btyp) ++b; const char* btypnam = objtype_names[b]; os << indent << btypnam << " " << binfo.Id << " \"" << binfo.Name.c_str() << "\" (" << binfo.Size << ")\n"; os << indent << " FileOffset: " << binfo.FileOffset << "\n"; os << indent << " CachedConn: " << binfo.CachedConnectivity << " (" << binfo.Status << ")\n"; os << indent << " PointMap: " << binfo.PointMap.size() << " entries, " << "ReversePointMap: " << binfo.ReversePointMap.size() << " entries\n"; os << indent << " Type: " << binfo.TypeName.c_str() << "\n"; os << indent << " Bounds per entry, Node: " << binfo.BdsPerEntry[0] << " Edge: " << binfo.BdsPerEntry[1] << " Face: " << binfo.BdsPerEntry[2] << "\n"; os << indent << " Attributes (" << binfo.AttributesPerEntry << "):"; int a; for (a = 0; a < binfo.AttributesPerEntry; ++a) { os << " \"" << binfo.AttributeNames[a].c_str() << "\"(" << binfo.AttributeStatus[a] << ")"; } os << "\n"; } static void printSet( ostream& os, vtkIndent indent, int styp, vtkExodusIIReaderPrivate::SetInfoType& sinfo) { int s = 0; while (obj_types[s] >= 0 && obj_types[s] != styp) ++s; const char* stypnam = objtype_names[s]; os << indent << stypnam << " " << sinfo.Id << " \"" << sinfo.Name.c_str() << "\" (" << sinfo.Size << ")\n"; os << indent << " FileOffset: " << sinfo.FileOffset << "\n"; os << indent << " CachedConn: " << sinfo.CachedConnectivity << " (" << sinfo.Status << ")\n"; os << indent << " PointMap: " << sinfo.PointMap.size() << " entries, " << "ReversePointMap: " << sinfo.ReversePointMap.size() << " entries\n"; os << indent << " DistFact: " << sinfo.DistFact << "\n"; } static void printMap( ostream& os, vtkIndent indent, int mtyp, vtkExodusIIReaderPrivate::MapInfoType& minfo) { int m = 0; while (obj_types[m] >= 0 && obj_types[m] != mtyp) ++m; const char* mtypnam = objtype_names[m]; os << indent << mtypnam << " " << minfo.Id << " \"" << minfo.Name.c_str() << "\" (" << minfo.Size << ")\n"; os << indent << " Status: " << minfo.Status << "\n"; } static void printArray( ostream& os, vtkIndent indent, int atyp, vtkExodusIIReaderPrivate::ArrayInfoType& ainfo) { (void)atyp; os << indent << " " << ainfo.Name.c_str() << " [" << ainfo.Status << "] ( " << ainfo.Components << " = { "; os << ainfo.OriginalIndices[0] << " \"" << ainfo.OriginalNames[0] << "\""; int i; for (i = 1; i < (int)ainfo.OriginalIndices.size(); ++i) { os << ", " << ainfo.OriginalIndices[i] << " \"" << ainfo.OriginalNames[i] << "\""; } os << " } )\n"; os << indent << " " << glomTypeNames[ainfo.GlomType] << " Truth:"; for (i = 0; i < (int)ainfo.ObjectTruth.size(); ++i) { os << " " << ainfo.ObjectTruth[i]; } os << "\n"; } // --------------------------------------------------- PRIVATE SUBCLASS MEMBERS void vtkExodusIIReaderPrivate::ArrayInfoType::Reset() { if (!this->Name.empty()) { this->Name.erase(this->Name.begin(), this->Name.end()); } this->Components = 0; this->GlomType = -1; this->Status = 0; this->Source = -1; this->OriginalNames.clear(); this->OriginalIndices.clear(); this->ObjectTruth.clear(); } // ------------------------------------------------------- PRIVATE CLASS MEMBERS vtkStandardNewMacro(vtkExodusIIReaderPrivate); //------------------------------------------------------------------------------ vtkExodusIIReaderPrivate::vtkExodusIIReaderPrivate() { this->Exoid = -1; this->ExodusVersion = -1.; this->AppWordSize = 8; this->DiskWordSize = 8; this->Cache = vtkExodusIICache::New(); this->CacheSize = 0; this->HasModeShapes = 0; this->ModeShapeTime = -1.; this->AnimateModeShapes = 1; this->IgnoreFileTime = false; this->GenerateObjectIdArray = 1; this->GenerateGlobalElementIdArray = 0; this->GenerateGlobalNodeIdArray = 0; this->GenerateImplicitElementIdArray = 0; this->GenerateImplicitNodeIdArray = 0; this->GenerateGlobalIdArray = 0; this->GenerateFileIdArray = 0; this->FileId = 0; this->ApplyDisplacements = 1; this->DisplacementMagnitude = 1.; this->SqueezePoints = 1; this->Parser = nullptr; this->SIL = vtkMutableDirectedGraph::New(); this->SkipUpdateTimeInformation = false; memset((void*)&this->ModelParameters, 0, sizeof(this->ModelParameters)); } //------------------------------------------------------------------------------ vtkExodusIIReaderPrivate::~vtkExodusIIReaderPrivate() { this->CloseFile(); this->Cache->Delete(); this->CacheSize = 0; this->ClearConnectivityCaches(); if (this->Parser) { this->Parser->Delete(); this->Parser = nullptr; } this->SIL->Delete(); this->SIL = nullptr; } //------------------------------------------------------------------------------ void vtkExodusIIReaderPrivate::GlomArrayNames( int objtyp, int num_obj, int num_vars, char** var_names, int* truth_tab) { // Clear out existing array names since we are re-reading them in. this->ArrayInfo[objtyp].clear(); // Create some objects that try to glom names together in different ways. const char endRZ[] = "RZ"; const char endV2[] = "xy"; const char endV3[] = "xYz"; const char endST23[] = "XXYYZZXYXZYZ"; const char endST34[] = "XXXYYYZZZWWWXXYXXZXXWXYYXYZXYWXZZXZWXWWYYZYYWYZZYZWYWWZZWZWW"; vtkExodusIIReaderScalarCheck* scalar = new vtkExodusIIReaderScalarCheck; // vtkExodusIIReaderVectorCheck* vecx2 = new vtkExodusIIReaderVectorCheck( endV2, 2 ); // vtkExodusIIReaderVectorCheck* vecx3 = new vtkExodusIIReaderVectorCheck( endV3, 3 ); // vtkExodusIIReaderVectorCheck* vecrz = new vtkExodusIIReaderVectorCheck( endRZ, 2 ); vtkExodusIIReaderTensorCheck* vecx2 = new vtkExodusIIReaderTensorCheck(endV2, 2, 1, 2); vtkExodusIIReaderTensorCheck* vecx3 = new vtkExodusIIReaderTensorCheck(endV3, 3, 1, 3); vtkExodusIIReaderTensorCheck* vecrz = new vtkExodusIIReaderTensorCheck(endRZ, 2, 1, 2); vtkExodusIIReaderTensorCheck* ten23 = new vtkExodusIIReaderTensorCheck(endST23, 6, 2, 3); vtkExodusIIReaderTensorCheck* ten34 = new vtkExodusIIReaderTensorCheck(endST34, 20, 3, 4); vtkExodusIIReaderIntPointCheck* intpt = new vtkExodusIIReaderIntPointCheck; typedef std::vector glomVec; glomVec glommers; glommers.push_back(scalar); glommers.push_back(vecx2); glommers.push_back(vecx3); glommers.push_back(vecrz); glommers.push_back(ten23); glommers.push_back(ten34); glommers.push_back(intpt); glomVec::iterator glommer; std::vector tmpTruth; // Advance through the variable names. for (int i = 0; i < num_vars; ++i) { // Prepare all the glommers with the next unused variable name extractTruthForVar(num_obj, num_vars, truth_tab, i, tmpTruth); bool stop = true; for (glommer = glommers.begin(); glommer != glommers.end(); ++glommer) { if ((*glommer)->Start(var_names[i], &tmpTruth[0], num_obj)) { stop = false; } } int j = i + 1; // If any glommers can continue accepting names, give them more names until no more can accept // names while (j < num_vars && !stop) { stop = true; for (glommer = glommers.begin(); glommer != glommers.end(); ++glommer) { if ((*glommer)->Add(var_names[j], &tmpTruth[0])) { stop = false; } } ++j; } // Find longest glom that worked. (The scalar glommer always works with Length() 1.) unsigned int longestGlom = 0; glomVec::iterator longestGlommer = glommers.end(); for (glommer = glommers.begin(); glommer != glommers.end(); ++glommer) { if ((*glommer)->Length() > longestGlom) { longestGlom = static_cast((*glommer)->Length()); longestGlommer = glommer; } } if (longestGlommer != glommers.end()) { i += (*longestGlommer)->Accept(this->ArrayInfo[objtyp], i, this, objtyp) - 1; // the ++i takes care of length 1 } } // Now see what the gloms were. /* typedef std::vector varVec; for ( varVec::iterator it = this->ArrayInfo[objtyp].begin(); it != this->ArrayInfo[objtyp].end(); ++ it ) { cout << "Name: \"" << it->Name.c_str() << "\" (" << it->Components << ")\n"; } */ delete scalar; delete vecx2; delete vecx3; delete vecrz; delete ten23; delete ten34; delete intpt; } //------------------------------------------------------------------------------ int vtkExodusIIReaderPrivate::AssembleOutputConnectivity(vtkIdType timeStep, int otyp, int oidx, int conntypidx, BlockSetInfoType* bsinfop, vtkUnstructuredGrid* output) { // FIXME: Don't think I need this, since we ShallowCopy over it... right? output->Reset(); if (bsinfop->CachedConnectivity) { output->ShallowCopy(bsinfop->CachedConnectivity); return 1; } // OK, we needed to remake the cache... bsinfop->CachedConnectivity = vtkUnstructuredGrid::New(); bsinfop->CachedConnectivity->Allocate(bsinfop->Size); if (this->SqueezePoints) { bsinfop->NextSqueezePoint = 0; bsinfop->PointMap.clear(); bsinfop->ReversePointMap.clear(); } // Need to assemble connectivity array from smaller ones. // Call GetCacheOrRead() for each smaller array // Might want to experiment with the effectiveness of caching connectivity... // set up the ExodusIICache class with the ability to never cache some // key types. // Might also want to experiment with policies other than LRU, especially // applied to arrays that are not time-varying. During animations, they // will most likely get dropped even though that might not be wise. if (CONNTYPE_IS_BLOCK(conntypidx)) { this->InsertBlockCells( otyp, oidx, conn_types[conntypidx], timeStep, static_cast(bsinfop)); } else if (CONNTYPE_IS_SET(conntypidx)) { this->InsertSetCells( otyp, oidx, conn_types[conntypidx], timeStep, static_cast(bsinfop)); } else { vtkErrorMacro("Bad connectivity object type. Harass the responsible programmer."); } // OK, now copy our cache to the output... output->ShallowCopy(bsinfop->CachedConnectivity); // this->CachedConnectivity->ShallowCopy( output ); if (this->SqueezePoints) { vtkDebugMacro(<< "Squeezed down to " << bsinfop->NextSqueezePoint << " points\n"); } return 0; } int vtkExodusIIReaderPrivate::AssembleOutputPoints( vtkIdType timeStep, BlockSetInfoType* bsinfop, vtkUnstructuredGrid* output) { (void)timeStep; vtkPoints* pts = output->GetPoints(); if (!pts) { pts = vtkPoints::New(); output->SetPoints(pts); pts->FastDelete(); } else { pts->Reset(); } int ts = -1; // If we don't have displacements, only cache the array under one key. if (this->ApplyDisplacements && this->FindDisplacementVectors(timeStep)) { // Otherwise, each time step's array will be different. ts = timeStep; } vtkDataArray* arr = this->GetCacheOrRead(vtkExodusIICacheKey(ts, vtkExodusIIReader::NODAL_COORDS, 0, 0)); if (!arr) { vtkErrorMacro("Unable to read points from file."); return 0; } if (this->SqueezePoints) { pts->SetNumberOfPoints(bsinfop->NextSqueezePoint); std::map::iterator it; for (it = bsinfop->PointMap.begin(); it != bsinfop->PointMap.end(); ++it) { pts->SetPoint(it->second, arr->GetTuple(it->first)); } } else { pts->SetData(arr); } return 1; } //------------------------------------------------------------------------------ int vtkExodusIIReaderPrivate::AssembleOutputPointArrays( vtkIdType timeStep, BlockSetInfoType* bsinfop, vtkUnstructuredGrid* output) { int status = 1; std::vector::iterator ai; int aidx = 0; for (ai = this->ArrayInfo[vtkExodusIIReader::NODAL].begin(); ai != this->ArrayInfo[vtkExodusIIReader::NODAL].end(); ++ai, ++aidx) { if (!ai->Status) continue; // Skip arrays we don't want. vtkExodusIICacheKey key(timeStep, vtkExodusIIReader::NODAL, 0, aidx); vtkDataArray* src = this->GetCacheOrRead(key); if (!src) { vtkDebugMacro( "Unable to read point array " << ai->Name.c_str() << " at time step " << timeStep); status = 0; continue; } this->AddPointArray(src, bsinfop, output); } return status; } //------------------------------------------------------------------------------ #if 0 // Copy tuples from one array to another, possibly with a different number of components per tuple. static void vtkEmbedTuplesInLargerArray( vtkDataSetAttributes* attr, vtkDataArray* dst, vtkDataArray* src, vtkIdType numTuples, vtkIdType offset ) { vtkIdType i; int srcNumComp = src->GetNumberOfComponents(); int dstNumComp = dst->GetNumberOfComponents(); if ( dstNumComp != srcNumComp ) { // We've promoted the array from 2-D to 3-D... can't use CopyTuple if ( dst->GetDataType() != src->GetDataType() ) { return; } vtkIdType sid = 0; vtkIdType did = offset * dstNumComp; int minNumComp = dstNumComp < srcNumComp ? dstNumComp : srcNumComp; switch( dst->GetDataType() ) { vtkTemplateMacro( { VTK_TT* srcTuple = (VTK_TT*) src->GetVoidPointer( sid ); VTK_TT* dstTuple = (VTK_TT*) dst->GetVoidPointer( did ); for ( i = 0; i < numTuples; ++i, srcTuple += srcNumComp, dstTuple += dstNumComp ) { for ( int j = 0; j < minNumComp; ++j ) { dstTuple[j] = srcTuple[j]; } } } ); } } else { for ( i = 0; i < numTuples; ++i ) { attr->CopyTuple( src, dst, i, i + offset ); } } } #endif // 0 //------------------------------------------------------------------------------ int vtkExodusIIReaderPrivate::AssembleOutputCellArrays( vtkIdType timeStep, int otyp, int obj, BlockSetInfoType* bsinfop, vtkUnstructuredGrid* output) { // Don't create arrays for deselected objects if (!output || !bsinfop->Status) { return 1; } vtkCellData* cd = output->GetCellData(); // Load (time-constant) attributes first because their status is in the block info. if (otyp == vtkExodusIIReader::ELEM_BLOCK || otyp == vtkExodusIIReader::EDGE_BLOCK || otyp == vtkExodusIIReader::FACE_BLOCK) { BlockInfoType* binfop = (BlockInfoType*)bsinfop; std::vector::iterator atit; vtkIdType a = 0; for (atit = binfop->AttributeStatus.begin(); atit != binfop->AttributeStatus.end(); ++atit, ++a) { if (*atit) { vtkDataArray* arr = this->GetCacheOrRead( vtkExodusIICacheKey(timeStep, vtkExodusIIReader::ELEM_BLOCK_ATTRIB, obj, a)); if (arr) { cd->AddArray(arr); } } } } // Panic if we're given a bad otyp. std::map>::iterator ami = this->ArrayInfo.find(otyp); if (ami == this->ArrayInfo.end()) { #if 0 vtkErrorMacro( "Unknown block or set type \"" << otyp << "\" encountered." ); for ( ami = this->ArrayInfo.begin(); ami != this->ArrayInfo.end(); ++ ami ) { cerr << " Have type: \"" << ami->first << "\"\n"; } return 0; #else return 1; #endif // 0 } // For each array defined on objects of the same type as our output, // look for ones that are turned on (Status != 0) and have a truth // table indicating values are present for object obj in the file. std::vector::iterator ai; int aidx = 0; for (ai = ami->second.begin(); ai != ami->second.end(); ++ai, ++aidx) { if (!ai->Status) continue; if (!ai->ObjectTruth[obj]) continue; vtkDataArray* arr = this->GetCacheOrRead(vtkExodusIICacheKey(timeStep, ami->first, obj, aidx)); if (arr) { cd->AddArray(arr); } } return 1; } //------------------------------------------------------------------------------ int vtkExodusIIReaderPrivate::AssembleOutputProceduralArrays( vtkIdType timeStep, int otyp, int obj, vtkUnstructuredGrid* output) { (void)timeStep; int status = 7; vtkCellData* cd = output->GetCellData(); if (this->GenerateObjectIdArray) { vtkExodusIICacheKey key(-1, vtkExodusIIReader::OBJECT_ID, otyp, obj); vtkDataArray* arr = this->GetCacheOrRead(key); if (arr) { cd->AddArray(arr); status -= 1; } } if (this->GenerateGlobalElementIdArray && (otyp == vtkExodusIIReader::SIDE_SET_CONN || otyp == vtkExodusIIReader::SIDE_SET)) { vtkExodusIICacheKey ckey(-1, vtkExodusIIReader::ELEMENT_ID, 0, 0); vtkIdTypeArray* src = nullptr; if (vtkDataArray* elems = this->GetCacheOrRead(ckey)) { src = vtkIdTypeArray::New(); src->DeepCopy(elems); } vtkExodusIICacheKey key(-1, vtkExodusIIReader::SIDE_SET_CONN, obj, 1); if (vtkDataArray* arr = this->GetCacheOrRead(key)) { vtkIdTypeArray* idarray = vtkArrayDownCast(arr); vtkIdTypeArray* elementid = vtkIdTypeArray::New(); elementid->SetNumberOfTuples(idarray->GetNumberOfTuples()); elementid->SetName(vtkExodusIIReader::GetSideSetSourceElementIdArrayName()); vtkIntArray* elementside = vtkIntArray::New(); elementside->SetNumberOfTuples(idarray->GetNumberOfTuples()); elementside->SetName(vtkExodusIIReader::GetSideSetSourceElementSideArrayName()); vtkIdType values[2]; for (vtkIdType i = 0; i < idarray->GetNumberOfTuples(); i++) { idarray->GetTypedTuple(i, values); if (src == nullptr || src->GetValue(values[0] - 1) <= 0) { elementid->SetValue(i, values[0] - 1); } else { elementid->SetValue(i, src->GetValue(values[0] - 1) - 1); // find the global element id } // now we have to worry about mapping from exodus canonical side // ordering to vtk canonical side ordering for wedges and hexes. // Even if the element block isn't loaded that we still know what // types of cells it would have contained since all elements // in a block are of the same type. BlockInfoType* type = this->GetBlockFromFileGlobalId(vtkExodusIIReader::ELEM_BLOCK, values[0]); switch (type->CellType) { case VTK_WEDGE: { int wedgeMapping[5] = { 2, 3, 4, 0, 1 }; elementside->SetValue(i, wedgeMapping[values[1] - 1]); break; } case VTK_HEXAHEDRON: { int hexMapping[6] = { 2, 1, 3, 0, 4, 5 }; elementside->SetValue(i, hexMapping[values[1] - 1]); break; } default: { // switch to 0-based indexing elementside->SetValue(i, values[1] - 1); } } } cd->AddArray(elementid); cd->AddArray(elementside); elementid->FastDelete(); elementside->FastDelete(); status -= 2; } if (src != nullptr) { src->Delete(); } } if (this->GenerateGlobalElementIdArray && !OBJTYPE_IS_SET(otyp)) { // This retrieves the first new-style map, or if that is not present, // the solitary old-style map (which always exists but may be // procedurally generated if it is not stored with the file). vtkExodusIICacheKey key(-1, vtkExodusIIReader::GLOBAL_ELEMENT_ID, otyp, obj); vtkDataArray* arr = this->GetCacheOrRead(key); if (arr) { vtkDataArray* ped = vtkIdTypeArray::New(); ped->DeepCopy(arr); ped->SetName(vtkExodusIIReader::GetPedigreeElementIdArrayName()); cd->SetGlobalIds(arr); cd->SetPedigreeIds(ped); ped->FastDelete(); status -= 2; } } if (this->GenerateGlobalNodeIdArray) { // This retrieves the first new-style map, or if that is not present, // the solitary old-style map (which always exists but may be // procedurally generated if it is not stored with the file). vtkExodusIICacheKey key(-1, vtkExodusIIReader::GLOBAL_NODE_ID, otyp, obj); vtkDataArray* arr = this->GetCacheOrRead(key); vtkPointData* pd = output->GetPointData(); if (arr) { vtkDataArray* ped = vtkIdTypeArray::New(); ped->DeepCopy(arr); ped->SetName(vtkExodusIIReader::GetPedigreeNodeIdArrayName()); pd->SetGlobalIds(arr); pd->SetPedigreeIds(ped); ped->FastDelete(); status -= 4; } } if (this->GenerateImplicitElementIdArray) { // This retrieves the old style map if it is a parallel data set. The old // style map stores the global implicit id if parallel. Otherwise it // generates the implicit id. vtkExodusIICacheKey key(-1, vtkExodusIIReader::IMPLICIT_ELEMENT_ID, otyp, obj); vtkDataArray* arr = this->GetCacheOrRead(key); if (arr) { cd->AddArray(arr); } } if (this->GenerateImplicitNodeIdArray) { // This retrieves the old style map if it is a parallel data set. The old // style map stores the global implicit id if parallel. Otherwise it // generates the implicit id. vtkExodusIICacheKey key(-1, vtkExodusIIReader::IMPLICIT_NODE_ID, otyp, obj); vtkDataArray* arr = this->GetCacheOrRead(key); vtkPointData* pd = output->GetPointData(); if (arr) { pd->AddArray(arr); } } if (this->GenerateFileIdArray) { // Don't cache this... it's not worth it. vtkIdType numCells = output->GetNumberOfCells(); vtkIntArray* iarr = vtkIntArray::New(); iarr->SetNumberOfComponents(1); iarr->SetNumberOfTuples(numCells); iarr->SetName(vtkExodusIIReaderPrivate::GetFileIdArrayName()); cd->AddArray(iarr); iarr->FastDelete(); for (vtkIdType i = 0; i < numCells; ++i) { iarr->SetValue(i, this->FileId); } } return status; } //------------------------------------------------------------------------------ int vtkExodusIIReaderPrivate::AssembleOutputGlobalArrays( vtkIdType timeStep, int otyp, int obj, BlockSetInfoType* bsinfop, vtkUnstructuredGrid* output) { (void)obj; vtkFieldData* ofieldData = output->GetFieldData(); int status = 1; std::vector::iterator ai; int aidx = 0; for (ai = this->ArrayInfo[vtkExodusIIReader::GLOBAL].begin(); ai != this->ArrayInfo[vtkExodusIIReader::GLOBAL].end(); ++ai, ++aidx) { if (!ai->Status) { continue; } // Add time-varying global data vtkExodusIICacheKey tdKey(-1, vtkExodusIIReader::GLOBAL_TEMPORAL, -1, aidx); vtkDataArray* temporalData = this->GetCacheOrRead(tdKey); if (!temporalData) { vtkDebugMacro("Unable to read array " << ai->Name.c_str()); status = 0; continue; } ofieldData->AddArray(temporalData); } // Add block id information for the exodus writer (if we're an element block) if (otyp == vtkExodusIIReader::ELEM_BLOCK) { vtkIntArray* elemBlockIdArray = vtkIntArray::New(); elemBlockIdArray->SetNumberOfComponents(1); elemBlockIdArray->SetNumberOfValues(1); // one elem block per unstructured grid elemBlockIdArray->SetName("ElementBlockIds"); elemBlockIdArray->SetValue(0, bsinfop->Id); ofieldData->AddArray(elemBlockIdArray); elemBlockIdArray->Delete(); } // Add QA record, title, and INFO record metadata from the Exodus II file vtkExodusIICacheKey qakey(-1, vtkExodusIIReader::QA_RECORDS, 0, 0); vtkDataArray* arr = this->GetCacheOrRead(qakey); if (arr) { ofieldData->AddArray(arr); } // Add the title { vtkStringArray* sarr = vtkStringArray::New(); sarr->SetName("Title"); sarr->SetNumberOfComponents(1); sarr->SetNumberOfTuples(1); sarr->SetValue(0, this->ModelParameters.title); ofieldData->AddArray(sarr); sarr->Delete(); } // Add mode_shape/time_step if (this->HasModeShapes) { vtkNew dataIndexArray; dataIndexArray->SetName("mode_shape"); dataIndexArray->SetNumberOfComponents(1); dataIndexArray->SetNumberOfTuples(1); // mode-shape == (timestep + 1). See vtkExodusIIReader::SetModeShape(). dataIndexArray->SetValue(0, (timeStep + 1)); ofieldData->AddArray(dataIndexArray); vtkNew modeShapeRange; modeShapeRange->SetName("mode_shape_range"); modeShapeRange->SetNumberOfComponents(2); modeShapeRange->SetNumberOfTuples(1); modeShapeRange->SetValue(0, this->Parent->GetModeShapesRange()[0]); modeShapeRange->SetValue(1, this->Parent->GetModeShapesRange()[1]); ofieldData->AddArray(modeShapeRange); } vtkExodusIICacheKey infokey(-1, vtkExodusIIReader::INFO_RECORDS, 0, 0); arr = this->GetCacheOrRead(infokey); if (arr) { ofieldData->AddArray(arr); } return status; } //------------------------------------------------------------------------------ int vtkExodusIIReaderPrivate::AssembleOutputPointMaps( vtkIdType timeStep, BlockSetInfoType* bsinfop, vtkUnstructuredGrid* output) { (void)timeStep; int status = 1; std::vector::iterator mi; int midx = 0; for (mi = this->MapInfo[vtkExodusIIReader::NODE_MAP].begin(); mi != this->MapInfo[vtkExodusIIReader::NODE_MAP].end(); ++mi, ++midx) { if (!mi->Status) continue; // Skip arrays we don't want. vtkIdTypeArray* src = vtkArrayDownCast( this->GetCacheOrRead(vtkExodusIICacheKey(-1, vtkExodusIIReader::NODE_MAP, 0, midx))); if (!src) { vtkDebugMacro( "Unable to read point map array \"" << mi->Name.c_str() << "\" (" << midx << ")"); status = 0; continue; } this->AddPointArray(src, bsinfop, output); } return status; } //------------------------------------------------------------------------------ int vtkExodusIIReaderPrivate::AssembleOutputCellMaps(vtkIdType vtkNotUsed(timeStep), int otyp, int obj, BlockSetInfoType* bsinfop, vtkUnstructuredGrid* output) { (void)obj; // Don't create arrays for deselected objects if (!output || !bsinfop->Status) { return 1; } // Ignore invalid otyp values (sets cannot have maps, only blocks). int mtyp = this->GetMapTypeFromObjectType(otyp); std::map>::iterator mmi = this->MapInfo.find(mtyp); if (mmi == this->MapInfo.end()) { return 1; } vtkCellData* cd = output->GetCellData(); // For each map defined on objects of the same type as our output, // look for ones that are turned on (Status != 0). std::vector::iterator mi; int midx = 0; for (mi = mmi->second.begin(); mi != mmi->second.end(); ++mi, ++midx) { if (!mi->Status) continue; vtkDataArray* src = this->GetCacheOrRead(vtkExodusIICacheKey(-1, mmi->first, 0, midx)); if (!src) continue; if (otyp == vtkExodusIIReader::ELEM_BLOCK) { if (bsinfop->Size == src->GetNumberOfTuples() && bsinfop->FileOffset == 1 && this->BlockInfo[otyp].size() == 1) { cd->AddArray(src); } else { // Create the array and copy the applicable subset from the map vtkIdTypeArray* arr = vtkIdTypeArray::New(); arr->SetName(mi->Name.c_str()); arr->SetNumberOfComponents(1); arr->SetNumberOfTuples(bsinfop->Size); memcpy(arr->GetVoidPointer(0), src->GetVoidPointer(bsinfop->FileOffset - 1), bsinfop->Size * sizeof(vtkIdType)); cd->AddArray(arr); arr->FastDelete(); } } else { // FIXME: We have a set (no maps are defined on sets but we could determine // map values given the set generators) or an edge/face block (unclear // whether maps are useful/possible on these block types). } } return 1; } //------------------------------------------------------------------------------ vtkIdType vtkExodusIIReaderPrivate::GetPolyhedronFaceConnectivity( vtkIdType fileLocalFaceId, vtkIdType*& facePtIds) { // I. Find the face block containing \a fileLocalFaceId. // An element may refer to faces anywhere in the file, not just in // a corresponding face block, so each face of an element may be // in a different face block. if (this->BlockInfo.find(EX_FACE_BLOCK) == this->BlockInfo.end()) { vtkWarningMacro("No face blocks in exodus file, but polyhedral cell requires at least 1"); return -1; } std::vector& faceBlocks(this->BlockInfo[EX_FACE_BLOCK]); std::vector::const_iterator fbit; int fbidx = 0; vtkIdType blockLocalFaceId = -1; for (fbit = faceBlocks.begin(); fbit != faceBlocks.end() && (blockLocalFaceId = fileLocalFaceId + 1 - fbit->FileOffset) > fbit->Size; ++fbit) { ++fbidx; // std::cout << "Skipping block " << fbit->Id << " (" << fbit->Name << ") offset " << // fbit->FileOffset << "\n"; } if (fbit == faceBlocks.end() || blockLocalFaceId < 0) { vtkWarningMacro("Could not find a face block containing face " << fileLocalFaceId << " (block-relative " << blockLocalFaceId << ")."); return -1; } std::map>>::iterator fcit = this->PolyhedralFaceConnArrays.find(fbidx); if (fcit == this->PolyhedralFaceConnArrays.end()) { // Add faces for the entire face-block to the cache (because // the connectivity is run-length encoded). Hopefully each // polyhedral element block will use many faces from each // face block so the cost is amortized. vtkSmartPointer fconn = vtkArrayDownCast( this->GetCacheOrRead(vtkExodusIICacheKey(-1, vtkExodusIIReader::FACE_BLOCK_CONN, fbidx, 0))); if (!fconn) { vtkWarningMacro( "Face block " << fbidx << " (id " << fbit->Id << ") missing its connectivity array."); return -1; } vtkSmartPointer ptsPerFace = vtkArrayDownCast( this->GetCacheOrRead(vtkExodusIICacheKey(-1, vtkExodusIIReader::ENTITY_COUNTS, fbidx, /* get counts for face-block as opposed to element-block: */ 1))); if (!ptsPerFace) { vtkWarningMacro( "Face block " << fbidx << " (id " << fbit->Id << ") missing its points-per-face array."); return -1; } // Decompose the whole face block into a ragged // array (vector of vectors) to future lookups // are fast: static std::vector> blank; this->PolyhedralFaceConnArrays[fbidx] = blank; fcit = this->PolyhedralFaceConnArrays.find(fbidx); vtkIdType numFaces = ptsPerFace->GetNumberOfTuples(); fcit->second.resize(numFaces); vtkIdType cc = 0; for (vtkIdType ii = 0; ii < numFaces; ++ii) { int numPts = ptsPerFace->GetValue(ii); std::vector& facePts(fcit->second[ii]); facePts.resize(numPts); for (int jj = 0; jj < numPts; ++jj) { facePts[jj] = fconn->GetValue(cc++); } } } // II. Now that we have a cache for the face block, look up the // one face in the block we currently need: vtkIdType numPoints = static_cast(fcit->second[blockLocalFaceId].size()); facePtIds = &fcit->second[blockLocalFaceId][0]; return numPoints; } //------------------------------------------------------------------------------ void vtkExodusIIReaderPrivate::FreePolyhedronFaceArrays() { this->PolyhedralFaceConnArrays.clear(); } //------------------------------------------------------------------------------ void vtkExodusIIReaderPrivate::InsertBlockPolyhedra( BlockInfoType* binfo, vtkIntArray* facesPerCell, vtkIdTypeArray* exoCellConn) { vtkIdType numCells = facesPerCell->GetMaxId() + 1; // The Exodus file format is more compact than VTK's; it // allows multiple elements(cells) to refer to the same face so // that no face->point connectivity needs to be repeated. // VTK's polyhedral cells unpacks each element's faces // into a contiguous list for fast access to each element's // face->point connectivity. // So, we cannot use the arrays we are given as-is. // Also, VTK requires a list, without duplicates, of all the // points per cell (across all its faces), which Exodus does // not provide. // II. Insert cells using face-point connectivity. vtkIdType curCell = 0; vtkIdType curCellCurFace = 0; std::vector vtkCellPts; for (vtkIdType i = 0; i < numCells; ++i) { vtkCellPts.clear(); int numFacesThisCell = facesPerCell->GetValue(curCell++); for (vtkIdType j = 0; j < numFacesThisCell; ++j) { vtkIdType curFace = exoCellConn->GetValue(curCellCurFace++); // std::vector& curFacePts(facePointLists[curFace]); vtkIdType* facePtsRaw; vtkIdType numFacePts = this->GetPolyhedronFaceConnectivity(curFace, facePtsRaw); // Copy face connectivity, optionally (and usually) mapping to squeezed-points for the block vtkCellPts.push_back(numFacePts); for (vtkIdType pp = 0; pp < numFacePts; ++pp) { vtkCellPts.push_back( this->SqueezePoints ? this->GetSqueezePointId(binfo, facePtsRaw[pp]) : facePtsRaw[pp]); } } binfo->CachedConnectivity->InsertNextCell(VTK_POLYHEDRON, numFacesThisCell, &vtkCellPts[0]); } this->FreePolyhedronFaceArrays(); } //------------------------------------------------------------------------------ void vtkExodusIIReaderPrivate::InsertBlockCells( int otyp, int obj, int conn_type, int timeStep, BlockInfoType* binfo) { (void)timeStep; (void)otyp; if (binfo->Size == 0) { // No entries in this block. // This happens in parallel filesets when all // elements are distributed to other files. // Silently ignore. return; } vtkSmartPointer ent; if (binfo->PointsPerCell == 0) { int arrId = (conn_type == vtkExodusIIReader::ELEM_BLOCK_ELEM_CONN ? 0 : 1); ent = vtkArrayDownCast( this->GetCacheOrRead(vtkExodusIICacheKey(-1, vtkExodusIIReader::ENTITY_COUNTS, obj, arrId))); if (!ent) { vtkErrorMacro("Entity used 0 points per cell, " "but didn't return polyhedra correctly"); binfo->Status = 0; return; } } // Handle 3-D polyhedra (not 2-D polygons) separately // from other cell types for simplicity. // In addition to the element block connectivity (which // lists faces bounding the polyhedra, we must load face // block connectivity (which lists corner nodes for each // face). if (binfo->CellType == VTK_POLYHEDRON) { vtkSmartPointer efconn = vtkArrayDownCast(this->GetCacheOrRead( vtkExodusIICacheKey(-1, vtkExodusIIReader::ELEM_BLOCK_FACE_CONN, obj, 0))); if (!efconn || !ent) { vtkWarningMacro(<< "Element block (" << efconn.GetPointer() << ") and " << "number of faces per poly (" << ent.GetPointer() << ") arrays are both required. " << "Skipping block id " << binfo->Id << "; expect trouble."); binfo->Status = 0; return; } this->InsertBlockPolyhedra(binfo, ent, efconn); return; } vtkIdTypeArray* arr = vtkArrayDownCast( this->GetCacheOrRead(vtkExodusIICacheKey(-1, conn_type, obj, 0))); if (!arr) { vtkWarningMacro("Block wasn't present in file? Working around it. Expect trouble."); binfo->Status = 0; return; } if (this->SqueezePoints) { std::vector cellIds; cellIds.resize(binfo->PointsPerCell); auto srcIds = arr->GetPointer(0); for (int i = 0; i < binfo->Size; ++i) { int entitiesPerCell; if (ent) { entitiesPerCell = ent->GetValue(i); cellIds.resize(entitiesPerCell); } else { entitiesPerCell = binfo->PointsPerCell; } for (int p = 0; p < entitiesPerCell; ++p) { cellIds[p] = this->GetSqueezePointId(binfo, srcIds[p]); // cout << " " << srcIds[p] << "(" << cellIds[p] << ")"; } // cout << "\n"; // cout << " " << binfo->CachedConnectivity->InsertNextCell(binfo->CellType, entitiesPerCell, &cellIds[0]); srcIds += entitiesPerCell; } // cout << "\n"; } else { // The id type size used by exodus should match VTK_USE_64BIT_IDS length vtkIdType* srcIds = (vtkIdType*)arr->GetPointer(0); for (int i = 0; i < binfo->Size; ++i) { int entitiesPerCell = binfo->PointsPerCell; if (ent != nullptr) { entitiesPerCell = ent->GetValue(i); } binfo->CachedConnectivity->InsertNextCell(binfo->CellType, entitiesPerCell, srcIds); srcIds += entitiesPerCell; // for ( int k = 0; k < binfo->PointsPerCell; ++k ) // cout << " " << srcIds[k]; // cout << "\n"; } } } //------------------------------------------------------------------------------ void vtkExodusIIReaderPrivate::InsertSetCells( int otyp, int obj, int conn_type, int timeStep, SetInfoType* sinfo) { (void)timeStep; if (sinfo->Size == 0) { // No entries in this set. // This happens in parallel filesets when all elements are distributed to other files. // Silently ignore. return; } auto* arr = vtkArrayDownCast( this->GetCacheOrRead(vtkExodusIICacheKey(-1, conn_type, obj, 0))); if (!arr) { vtkWarningMacro("Set wasn't present in file? Working around it. Expect trouble."); sinfo->Status = 0; return; } switch (otyp) { case vtkExodusIIReader::NODE_SET: // Easy this->InsertSetNodeCopies(arr, otyp, obj, sinfo); break; case vtkExodusIIReader::EDGE_SET: // Not so fun. We must copy cells from possibly many edge blocks. this->InsertSetCellCopies(arr, vtkExodusIIReader::EDGE_BLOCK, obj, sinfo); break; case vtkExodusIIReader::FACE_SET: // Not so fun. We must copy cells from possibly many face blocks. this->InsertSetCellCopies(arr, vtkExodusIIReader::FACE_BLOCK, obj, sinfo); break; case vtkExodusIIReader::SIDE_SET: // Way hard even when we let Exodus do a lot for us. this->InsertSetSides(arr, otyp, obj, sinfo); break; case vtkExodusIIReader::ELEM_SET: // Not so fun. We must copy cells from possibly many element blocks. this->InsertSetCellCopies(arr, vtkExodusIIReader::ELEM_BLOCK, obj, sinfo); break; } } //------------------------------------------------------------------------------ void vtkExodusIIReaderPrivate::AddPointArray( vtkDataArray* src, BlockSetInfoType* bsinfop, vtkUnstructuredGrid* output) { vtkPointData* pd = output->GetPointData(); if (this->SqueezePoints) { // subset the array using PointMap vtkDataArray* dest = vtkDataArray::CreateDataArray(src->GetDataType()); dest->SetName(src->GetName()); dest->SetNumberOfComponents(src->GetNumberOfComponents()); dest->SetNumberOfTuples(bsinfop->NextSqueezePoint); std::map::iterator it, itEnd; // // I moved the end condition of the loop out of the for(;;) loop. // Assuming it doesn't change within the loop itself! // The reason is that the code was making the call every loop. // itEnd = bsinfop->PointMap.end(); for (it = bsinfop->PointMap.begin(); it != itEnd; ++it) { pd->CopyTuple(src, dest, it->first, it->second); } pd->AddArray(dest); dest->FastDelete(); } else { pd->AddArray(src); } } //------------------------------------------------------------------------------ void vtkExodusIIReaderPrivate::InsertSetNodeCopies( vtkIdTypeArray* refs, int otyp, int obj, SetInfoType* sinfo) { (void)otyp; (void)obj; // Insert a "VERTEX" cell for each node in the set. vtkIdType ref; vtkIdType tmp; auto* iptr = refs->GetPointer(0); if (this->SqueezePoints) { // this loop is separated out to handle case (stride > 1 && pref[1] < 0 && this->SqueezePoints) for (ref = 0; ref < refs->GetNumberOfTuples(); ++ref, ++iptr) { tmp = *iptr; vtkIdType x = this->GetSqueezePointId(sinfo, tmp); sinfo->CachedConnectivity->InsertNextCell(VTK_VERTEX, 1, &x); } } else { for (ref = 0; ref < refs->GetNumberOfTuples(); ++ref, ++iptr) { tmp = *iptr; sinfo->CachedConnectivity->InsertNextCell(VTK_VERTEX, 1, &tmp); } } } //------------------------------------------------------------------------------ void vtkExodusIIReaderPrivate::InsertSetCellCopies( vtkIdTypeArray* refs, int otyp, int obj, SetInfoType* sinfo) { (void)obj; // First, sort the set by entry number (element, face, or edge ID) // so that we can refer to each block just once as we process cells. vtkSortDataArray::SortArrayByComponent(refs, 0); refs->Register(this); // Don't let the cache delete this array when we fetch others... vtkIdType nrefs = refs->GetNumberOfTuples(); vtkIdType ref = 0; vtkIdType bnum = -1; vtkIdType lastBlockEntry = -1; auto* pref = refs->GetPointer(0); int stride = refs->GetNumberOfComponents(); BlockInfoType* binfop = nullptr; //&this->BlockInfo[otyp][bnum]; int* nodeconn = nullptr; vtkIdType* cellConn; int nnpe = 0; vtkIntArray* nconn; std::vector tmpTuple; while (ref < nrefs) { int loadNewBlk = 0; while (pref[0] >= lastBlockEntry) { // advance to the next block (always true first time through parent loop) ++bnum; if (bnum >= (int)this->BlockInfo[otyp].size()) return; binfop = &this->BlockInfo[otyp][bnum]; lastBlockEntry = binfop->FileOffset + binfop->Size - 1; loadNewBlk = 1; } if (loadNewBlk) { nconn = vtkArrayDownCast(this->GetCacheOrRead( vtkExodusIICacheKey(-1, this->GetBlockConnTypeFromBlockType(otyp), bnum, 0))); if (!nconn) { vtkErrorMacro( "Unable to read block \"" << binfop->Name.c_str() << "\" (" << binfop->Id << ")"); break; } nodeconn = nconn->GetPointer(0); nnpe = nconn->GetNumberOfComponents(); if (stride > 1 || this->SqueezePoints) { tmpTuple.resize(nnpe); } } if (stride > 1 && pref[1] < 0) { // negative orientation => reverse cell connectivity vtkIdType off = (pref[0] + 2 - binfop->FileOffset) * nnpe - 1; for (int k = 0; k < nnpe; ++k) tmpTuple[k] = nodeconn[off - k]; cellConn = &tmpTuple[0]; } else #ifndef VTK_USE_64BIT_IDS if (this->SqueezePoints) #endif // VTK_USE_64BIT_IDS { vtkIdType off = (pref[0] + 1 - binfop->FileOffset) * nnpe; for (int k = 0; k < nnpe; ++k) tmpTuple[k] = nodeconn[off + k]; cellConn = &tmpTuple[0]; } #ifndef VTK_USE_64BIT_IDS else { cellConn = (int*)nodeconn + (pref[0] + 1 - binfop->FileOffset) * nnpe; } #endif // VTK_USE_64BIT_IDS if (this->SqueezePoints) { // this loop is separated out to handle case (stride > 1 && pref[1] < 0 && // this->SqueezePoints) for (int k = 0; k < nnpe; ++k) { // FIXME: Double-check that cellConn[k] should be in-place re-assigned. cellConn[k] = this->GetSqueezePointId(sinfo, cellConn[k]); } } sinfo->CachedConnectivity->InsertNextCell(binfop->CellType, nnpe, cellConn); pref += stride; ++ref; } refs->UnRegister(this); } //------------------------------------------------------------------------------ void vtkExodusIIReaderPrivate::InsertSetSides( vtkIdTypeArray* refs, int otyp, int obj, SetInfoType* sinfo) { static const int sideCellTypes[] = { VTK_EMPTY_CELL, // don't support any cells with 0 nodes per side VTK_VERTEX, VTK_LINE, VTK_TRIANGLE, VTK_QUAD, VTK_EMPTY_CELL, // don't support any cells with 5 nodes per side VTK_QUADRATIC_TRIANGLE, VTK_EMPTY_CELL, // don't support any cells with 7 nodes per side VTK_QUADRATIC_QUAD, VTK_BIQUADRATIC_QUAD }; int numSides = this->SetInfo[otyp][obj].Size; auto* nodesPerSide = refs->GetPointer(0); auto* sideNodes = nodesPerSide + numSides; std::vector cellConn; cellConn.resize(9); if (this->SqueezePoints) { int nnpe; for (int side = 0; side < numSides; ++side) { nnpe = nodesPerSide[side]; for (int k = 0; k < nnpe; ++k) { cellConn[k] = this->GetSqueezePointId(sinfo, sideNodes[k]); } sinfo->CachedConnectivity->InsertNextCell(sideCellTypes[nnpe], nnpe, &cellConn[0]); sideNodes += nnpe; } } else { int nnpe; for (int side = 0; side < numSides; ++side) { nnpe = nodesPerSide[side]; #ifdef VTK_USE_64BIT_IDS for (int k = 0; k < nnpe; ++k) { cellConn[k] = sideNodes[k]; } sinfo->CachedConnectivity->InsertNextCell(sideCellTypes[nnpe], nnpe, &cellConn[0]); #else // VTK_USE_64BIT_IDS sinfo->CachedConnectivity->InsertNextCell(sideCellTypes[nnpe], nnpe, sideNodes); #endif // VTK_USE_64BIT_IDS sideNodes += nnpe; } } } //------------------------------------------------------------------------------ vtkDataArray* vtkExodusIIReaderPrivate::GetCacheOrRead(vtkExodusIICacheKey key) { vtkDataArray* arr; // Never cache points deflected for a mode shape animation... doubles don't make good keys. if (this->HasModeShapes && key.ObjectType == vtkExodusIIReader::NODAL_COORDS) { arr = nullptr; } else { arr = this->Cache->Find(key); } if (arr) { // return arr; } int exoid = this->Exoid; int maxNameLength = this->Parent->GetMaxNameLength(); // If array is nullptr, try reading it from file. if (key.ObjectType == vtkExodusIIReader::GLOBAL) { // need to assemble result array from smaller ones. // call GetCacheOrRead() for each smaller array // pay attention to SqueezePoints // ArrayInfoType* ainfop = &this->ArrayInfo[vtkExodusIIReader::GLOBAL][key.ArrayId]; arr = vtkDataArray::CreateDataArray(VTK_DOUBLE); arr->SetName(vtkExodusIIReaderPrivate::GetGlobalVariableValuesArrayName()); arr->SetNumberOfComponents(1); arr->SetNumberOfTuples( static_cast(this->ArrayInfo[vtkExodusIIReader::GLOBAL].size())); if (ex_get_glob_vars(exoid, key.Time + 1, arr->GetNumberOfTuples(), arr->GetVoidPointer(0)) < 0) { vtkErrorMacro( "Could not read global variable " << this->GetGlobalVariableValuesArrayName() << "."); arr->Delete(); arr = nullptr; } auto info = arr->GetInformation(); // add the `GLOBAL_VARIABLE` key so filters may use it. info->Set(vtkExodusIIReader::GLOBAL_VARIABLE(), 1); } else if (key.ObjectType == vtkExodusIIReader::NODAL) { // read nodal array ArrayInfoType* ainfop = &this->ArrayInfo[vtkExodusIIReader::NODAL][key.ArrayId]; int ncomps = (this->ModelParameters.num_dim == 2 && ainfop->Components == 2) ? 3 : ainfop->Components; arr = vtkDataArray::CreateDataArray(ainfop->StorageType); arr->SetName(ainfop->Name.c_str()); arr->SetNumberOfComponents(ncomps); arr->SetNumberOfTuples(this->ModelParameters.num_nodes); if (ncomps != ainfop->Components) { arr->FillComponent(2, 0.); } if (ncomps == 1) { if (ex_get_var(exoid, key.Time + 1, static_cast(key.ObjectType), ainfop->OriginalIndices[0], 0, arr->GetNumberOfTuples(), arr->GetVoidPointer(0)) < 0) { vtkErrorMacro("Could not read nodal result variable " << ainfop->Name.c_str() << "."); arr->Delete(); arr = nullptr; } } else { // Exodus doesn't support reading with a stride, so we have to manually interleave the arrays. // Bleh. std::vector> tmpVal; tmpVal.resize(ainfop->Components); int c; for (c = 0; c < ainfop->Components; ++c) { vtkIdType N = this->ModelParameters.num_nodes; tmpVal[c].resize(N); if (ex_get_var(exoid, key.Time + 1, static_cast(key.ObjectType), ainfop->OriginalIndices[c], 0, arr->GetNumberOfTuples(), &tmpVal[c][0]) < 0) { vtkErrorMacro( "Could not read nodal result variable " << ainfop->OriginalNames[c].c_str() << "."); arr->Delete(); arr = nullptr; return nullptr; } } int t; std::vector tmpTuple; tmpTuple.resize(ncomps); tmpTuple[ncomps - 1] = 0.; // In case we're embedding a 2-D vector in 3-D // // Lets unroll the most common case - components == 3. // if (ainfop->Components == 3) { int maxTuples = arr->GetNumberOfTuples(); for (t = 0; t < maxTuples; ++t) { tmpTuple[0] = tmpVal[0][t]; tmpTuple[1] = tmpVal[1][t]; tmpTuple[2] = tmpVal[2][t]; arr->SetTuple(t, &tmpTuple[0]); } } else { for (t = 0; t < arr->GetNumberOfTuples(); ++t) { for (c = 0; c < ainfop->Components; ++c) { tmpTuple[c] = tmpVal[c][t]; } arr->SetTuple(t, &tmpTuple[0]); } } } } else if (key.ObjectType == vtkExodusIIReader::GLOBAL_TEMPORAL) { // read temporal nodal array ArrayInfoType* ainfop = &this->ArrayInfo[vtkExodusIIReader::GLOBAL][key.ArrayId]; arr = vtkDataArray::CreateDataArray(ainfop->StorageType); // vtkStdString newArrayName = ainfop->Name + "OverTime"; arr->SetName(ainfop->Name); arr->SetNumberOfComponents(ainfop->Components); arr->SetNumberOfTuples(this->GetNumberOfTimeSteps()); if (ainfop->Components != 1) { // Exodus doesn't support reading with a stride, so we have to manually interleave the arrays. // Bleh. std::vector> tmpVal; tmpVal.resize(ainfop->Components); int c; for (c = 0; c < ainfop->Components; ++c) { vtkIdType N = this->GetNumberOfTimeSteps(); tmpVal[c].resize(N); if (ex_get_var_time(exoid, EX_GLOBAL, ainfop->OriginalIndices[c], key.ObjectId, 1, this->GetNumberOfTimeSteps(), &tmpVal[c][0]) < 0) { vtkErrorMacro("Could not read temporal global result variable " << ainfop->OriginalNames[c].c_str() << "."); arr->Delete(); arr = nullptr; return nullptr; } } int t; std::vector tmpTuple; tmpTuple.resize(ainfop->Components); for (t = 0; t < arr->GetNumberOfTuples(); ++t) { for (c = 0; c < ainfop->Components; ++c) { tmpTuple[c] = tmpVal[c][t]; } arr->SetTuple(t, &tmpTuple[0]); } } else if (ex_get_var_time(exoid, EX_GLOBAL, ainfop->OriginalIndices[0], key.ObjectId, 1, this->GetNumberOfTimeSteps(), arr->GetVoidPointer(0)) < 0) { vtkErrorMacro("Could not read global result variable " << ainfop->Name.c_str() << "."); arr->Delete(); arr = nullptr; } auto info = arr->GetInformation(); // add the `GLOBAL_TEMPORAL_VARIABLE` key so filters may use it. info->Set(vtkExodusIIReader::GLOBAL_TEMPORAL_VARIABLE(), 1); } else if (key.ObjectType == vtkExodusIIReader::NODAL_TEMPORAL) { // read temporal nodal array ArrayInfoType* ainfop = &this->ArrayInfo[vtkExodusIIReader::NODAL][key.ArrayId]; arr = vtkDataArray::CreateDataArray(ainfop->StorageType); vtkStdString newArrayName = ainfop->Name + "OverTime"; arr->SetName(newArrayName.c_str()); arr->SetNumberOfComponents(ainfop->Components); arr->SetNumberOfTuples(this->GetNumberOfTimeSteps()); if (ainfop->Components == 1) { if (ex_get_var_time(exoid, EX_NODAL, ainfop->OriginalIndices[0], key.ObjectId, 1, this->GetNumberOfTimeSteps(), arr->GetVoidPointer(0)) < 0) { vtkErrorMacro("Could not read nodal result variable " << ainfop->Name.c_str() << "."); arr->Delete(); arr = nullptr; } } else { // Exodus doesn't support reading with a stride, so we have to manually interleave the arrays. // Bleh. std::vector> tmpVal; tmpVal.resize(ainfop->Components); int c; for (c = 0; c < ainfop->Components; ++c) { vtkIdType N = this->GetNumberOfTimeSteps(); tmpVal[c].resize(N); if (ex_get_var_time(exoid, EX_NODAL, ainfop->OriginalIndices[c], key.ObjectId, 1, this->GetNumberOfTimeSteps(), &tmpVal[c][0]) < 0) { vtkErrorMacro("Could not read temporal nodal result variable " << ainfop->OriginalNames[c].c_str() << "."); arr->Delete(); arr = nullptr; return nullptr; } } int t; std::vector tmpTuple; tmpTuple.resize(ainfop->Components); for (t = 0; t < arr->GetNumberOfTuples(); ++t) { for (c = 0; c < ainfop->Components; ++c) { tmpTuple[c] = tmpVal[c][t]; } arr->SetTuple(t, &tmpTuple[0]); } } } else if (key.ObjectType == vtkExodusIIReader::ELEM_BLOCK_TEMPORAL) { // read temporal element array ArrayInfoType* ainfop = &this->ArrayInfo[vtkExodusIIReader::ELEM_BLOCK][key.ArrayId]; arr = vtkDataArray::CreateDataArray(ainfop->StorageType); vtkStdString newArrayName = ainfop->Name + "OverTime"; arr->SetName(newArrayName.c_str()); arr->SetNumberOfComponents(ainfop->Components); arr->SetNumberOfTuples(this->GetNumberOfTimeSteps()); if (ainfop->Components == 1) { if (ex_get_var_time(exoid, EX_ELEM_BLOCK, ainfop->OriginalIndices[0], key.ObjectId, 1, this->GetNumberOfTimeSteps(), arr->GetVoidPointer(0)) < 0) { vtkErrorMacro("Could not read element result variable " << ainfop->Name.c_str() << "."); arr->Delete(); arr = nullptr; } } else { // Exodus doesn't support reading with a stride, so we have to manually interleave the arrays. // Bleh. std::vector> tmpVal; tmpVal.resize(ainfop->Components); int c; for (c = 0; c < ainfop->Components; ++c) { vtkIdType N = this->GetNumberOfTimeSteps(); tmpVal[c].resize(N); if (ex_get_var_time(exoid, EX_ELEM_BLOCK, ainfop->OriginalIndices[c], key.ObjectId, 1, this->GetNumberOfTimeSteps(), &tmpVal[c][0]) < 0) { vtkErrorMacro("Could not read temporal element result variable " << ainfop->OriginalNames[c].c_str() << "."); arr->Delete(); arr = nullptr; return nullptr; } } int t; std::vector tmpTuple; tmpTuple.resize(ainfop->Components); for (t = 0; t < arr->GetNumberOfTuples(); ++t) { for (c = 0; c < ainfop->Components; ++c) { tmpTuple[c] = tmpVal[c][t]; } arr->SetTuple(t, &tmpTuple[0]); } } } else if (key.ObjectType == vtkExodusIIReader::EDGE_BLOCK || key.ObjectType == vtkExodusIIReader::FACE_BLOCK || key.ObjectType == vtkExodusIIReader::ELEM_BLOCK || key.ObjectType == vtkExodusIIReader::NODE_SET || key.ObjectType == vtkExodusIIReader::EDGE_SET || key.ObjectType == vtkExodusIIReader::FACE_SET || key.ObjectType == vtkExodusIIReader::SIDE_SET || key.ObjectType == vtkExodusIIReader::ELEM_SET) { int otypidx = this->GetObjectTypeIndexFromObjectType(key.ObjectType); ArrayInfoType* ainfop = &this->ArrayInfo[key.ObjectType][key.ArrayId]; ObjectInfoType* oinfop = this->GetObjectInfo(otypidx, key.ObjectId); arr = vtkDataArray::CreateDataArray(ainfop->StorageType); arr->SetName(ainfop->Name.c_str()); if (ainfop->Components == 2 && this->ModelParameters.num_dim == 2) { // Promote 2-component arrays to 3-component arrays when we have 2-D coordinates arr->SetNumberOfComponents(3); } else { arr->SetNumberOfComponents(ainfop->Components); } arr->SetNumberOfTuples(oinfop->Size); if (ainfop->Components == 1) { if (ex_get_var(exoid, key.Time + 1, static_cast(key.ObjectType), ainfop->OriginalIndices[0], oinfop->Id, arr->GetNumberOfTuples(), arr->GetVoidPointer(0)) < 0) { vtkErrorMacro("Could not read result variable " << ainfop->Name.c_str() << " for " << objtype_names[otypidx] << " " << oinfop->Id << "."); arr->Delete(); arr = nullptr; } } else { // Exodus doesn't support reading with a stride, so we have to manually interleave the arrays. // Bleh. std::vector> tmpVal; tmpVal.resize(ainfop->Components); int c; for (c = 0; c < ainfop->Components; ++c) { vtkIdType N = arr->GetNumberOfTuples(); tmpVal[c].resize(N + 1); // + 1 to avoid errors when N == 0. // BUG #8746. if (ex_get_var(exoid, key.Time + 1, static_cast(key.ObjectType), ainfop->OriginalIndices[c], oinfop->Id, arr->GetNumberOfTuples(), &tmpVal[c][0]) < 0) { vtkErrorMacro("Could not read result variable " << ainfop->OriginalNames[c].c_str() << " for " << objtype_names[otypidx] << " " << oinfop->Id << "."); arr->Delete(); arr = nullptr; } } // Carefully use arr->GetNumberOfComponents() when sizing // output as we may have promoted 2-D arrays to 3-D. int t = arr->GetNumberOfComponents(); std::vector tmpTuple; tmpTuple.resize(t); tmpTuple[t - 1] = 0.; for (t = 0; t < arr->GetNumberOfTuples(); ++t) { for (c = 0; c < ainfop->Components; ++c) { tmpTuple[c] = tmpVal[c][t]; } arr->SetTuple(t, &tmpTuple[0]); } } } else if (key.ObjectType == vtkExodusIIReader::NODE_MAP || key.ObjectType == vtkExodusIIReader::EDGE_MAP || key.ObjectType == vtkExodusIIReader::FACE_MAP || key.ObjectType == vtkExodusIIReader::ELEM_MAP) { MapInfoType* minfop = &this->MapInfo[key.ObjectType][key.ArrayId]; vtkIdTypeArray* iarr = vtkIdTypeArray::New(); arr = iarr; arr->SetName(minfop->Name.c_str()); arr->SetNumberOfComponents(1); switch (key.ObjectType) { case vtkExodusIIReader::NODE_MAP: arr->SetNumberOfTuples(this->ModelParameters.num_nodes); break; case vtkExodusIIReader::EDGE_MAP: arr->SetNumberOfTuples(this->ModelParameters.num_edge); break; case vtkExodusIIReader::FACE_MAP: arr->SetNumberOfTuples(this->ModelParameters.num_face); break; case vtkExodusIIReader::ELEM_MAP: arr->SetNumberOfTuples(this->ModelParameters.num_elem); break; } if (ex_get_num_map(exoid, static_cast(key.ObjectType), minfop->Id, (vtkIdType*)arr->GetVoidPointer(0)) < 0) { vtkErrorMacro("Could not read nodal map variable " << minfop->Name.c_str() << "."); arr->Delete(); arr = nullptr; } } else if (key.ObjectType == vtkExodusIIReader::GLOBAL_ELEMENT_ID) { // Yes, the next 2 statements are an intentional misuse of key // fields reserved for the ObjectId and ArrayId (since ObjectType // is used to signal that we want IDs instead of a field value). int otypidx = this->GetObjectTypeIndexFromObjectType(key.ObjectId); int obj = key.ArrayId; BlockSetInfoType* bsinfop = (BlockSetInfoType*)this->GetObjectInfo(otypidx, obj); vtkExodusIICacheKey ckey(-1, -1, 0, 0); switch (key.ObjectId) { case vtkExodusIIReader::EDGE_BLOCK: ckey.ObjectType = vtkExodusIIReader::EDGE_ID; break; case vtkExodusIIReader::FACE_BLOCK: ckey.ObjectType = vtkExodusIIReader::FACE_ID; break; case vtkExodusIIReader::ELEM_BLOCK: default: ckey.ObjectType = vtkExodusIIReader::ELEMENT_ID; break; } vtkIdTypeArray* src = vtkArrayDownCast(this->GetCacheOrRead(ckey)); if (!src) { arr = nullptr; return nullptr; } vtkIdTypeArray* iarr = vtkIdTypeArray::New(); iarr->SetName(vtkExodusIIReader::GetGlobalElementIdArrayName()); iarr->SetNumberOfComponents(1); iarr->SetNumberOfTuples(bsinfop->Size); vtkIdType* gloIds = iarr->GetPointer(0); vtkIdType* srcIds = src->GetPointer(bsinfop->FileOffset - 1); memcpy(gloIds, srcIds, sizeof(vtkIdType) * bsinfop->Size); arr = iarr; } else if (key.ObjectType == vtkExodusIIReader::IMPLICIT_ELEMENT_ID) { // Yes, the next 2 statements are an intentional misuse of key // fields reserved for the ObjectId and ArrayId (since ObjectType // is used to signal that we want IDs instead of a field value). int otypidx = this->GetObjectTypeIndexFromObjectType(key.ObjectId); int obj = key.ArrayId; BlockSetInfoType* bsinfop = (BlockSetInfoType*)this->GetObjectInfo(otypidx, obj); vtkExodusIICacheKey ckey(-1, -1, 0, 0); vtkIdType mapSize; int nMaps; switch (key.ObjectId) { case vtkExodusIIReader::EDGE_BLOCK: ckey.ObjectType = vtkExodusIIReader::EDGE_ID; mapSize = this->ModelParameters.num_edge; nMaps = this->ModelParameters.num_edge_maps; break; case vtkExodusIIReader::FACE_BLOCK: ckey.ObjectType = vtkExodusIIReader::FACE_ID; mapSize = this->ModelParameters.num_face; nMaps = this->ModelParameters.num_face_maps; break; case vtkExodusIIReader::ELEM_BLOCK: default: ckey.ObjectType = vtkExodusIIReader::ELEMENT_ID; mapSize = this->ModelParameters.num_elem; nMaps = this->ModelParameters.num_elem_maps; break; } vtkIdTypeArray* src = vtkIdTypeArray::New(); src->SetNumberOfComponents(1); src->SetNumberOfTuples(mapSize); if (nMaps > 0) // FIXME correctly detect parallel { if (ex_get_id_map(exoid, static_cast(ckey.ObjectType), (vtkIdType*)src->GetPointer(0)) < 0) { vtkErrorMacro("Could not read elem num map for global implicit id"); src->Delete(); return nullptr; } } else // single file, just make the implicit index explicit { for (vtkIdType i = 0; i < src->GetNumberOfTuples(); i++) { src->SetValue(i, i + 1); } } vtkIdTypeArray* iarr = vtkIdTypeArray::New(); iarr->SetName(vtkExodusIIReader::GetImplicitElementIdArrayName()); iarr->SetNumberOfComponents(1); iarr->SetNumberOfTuples(bsinfop->Size); vtkIdType* gloIds = iarr->GetPointer(0); vtkIdType* srcIds = src->GetPointer(bsinfop->FileOffset - 1); memcpy(gloIds, srcIds, sizeof(vtkIdType) * bsinfop->Size); arr = iarr; src->Delete(); } else if (key.ObjectType == vtkExodusIIReader::GLOBAL_NODE_ID) { // subset the NODE_ID array choosing only entries for nodes in output grid (using PointMap) // Yes, the next 2 statements are an intentional misuse of key // fields reserved for the ObjectId and ArrayId (since ObjectType // is used to signal that we want IDs instead of a field value). int otypidx = this->GetObjectTypeIndexFromObjectType(key.ObjectId); int obj = key.ArrayId; BlockSetInfoType* bsinfop = (BlockSetInfoType*)this->GetObjectInfo(otypidx, obj); vtkIdTypeArray* src = vtkArrayDownCast( this->GetCacheOrRead(vtkExodusIICacheKey(-1, vtkExodusIIReader::NODE_ID, 0, 0))); if (this->SqueezePoints && src) { vtkIdTypeArray* iarr = vtkIdTypeArray::New(); iarr->SetName(vtkExodusIIReader::GetGlobalNodeIdArrayName()); iarr->SetNumberOfComponents(1); iarr->SetNumberOfTuples(bsinfop->NextSqueezePoint); vtkIdType* gloIds = iarr->GetPointer(0); vtkIdType* srcIds = src->GetPointer(0); std::map::iterator it; for (it = bsinfop->PointMap.begin(); it != bsinfop->PointMap.end(); ++it) { gloIds[it->second] = srcIds[it->first]; } arr = iarr; } else { arr = src; } } else if (key.ObjectType == vtkExodusIIReader::IMPLICIT_NODE_ID) { // subset the NODE_ID array choosing only entries for nodes in output grid (using PointMap) // Yes, the next 2 statements are an intentional misuse of key // fields reserved for the ObjectId and ArrayId (since ObjectType // is used to signal that we want IDs instead of a field value). int otypidx = this->GetObjectTypeIndexFromObjectType(key.ObjectId); int obj = key.ArrayId; BlockSetInfoType* bsinfop = (BlockSetInfoType*)this->GetObjectInfo(otypidx, obj); vtkIdTypeArray* src = vtkIdTypeArray::New(); src->SetNumberOfComponents(1); src->SetNumberOfTuples(this->ModelParameters.num_nodes); if (this->ModelParameters.num_node_maps > 0) // FIXME correctly detect parallel { if (ex_get_id_map(exoid, (ex_entity_type)(vtkExodusIIReader::NODE_MAP), (vtkIdType*)src->GetPointer(0)) < 0) { vtkErrorMacro("Could not node node num map for global implicit id"); src->Delete(); return nullptr; } } else // single file, just make the implicit index explicit { for (vtkIdType i = 0; i < src->GetNumberOfTuples(); i++) { src->SetValue(i, i + 1); } } if (this->SqueezePoints && src) { vtkIdTypeArray* iarr = vtkIdTypeArray::New(); iarr->SetName(vtkExodusIIReader::GetImplicitNodeIdArrayName()); iarr->SetNumberOfComponents(1); iarr->SetNumberOfTuples(bsinfop->NextSqueezePoint); vtkIdType* gloIds = iarr->GetPointer(0); vtkIdType* srcIds = src->GetPointer(0); std::map::iterator it; for (it = bsinfop->PointMap.begin(); it != bsinfop->PointMap.end(); ++it) { gloIds[it->second] = srcIds[it->first]; } arr = iarr; } else { arr = src; } src->Delete(); } else if (key.ObjectType == vtkExodusIIReader::ELEMENT_ID || key.ObjectType == vtkExodusIIReader::EDGE_ID || key.ObjectType == vtkExodusIIReader::FACE_ID || key.ObjectType == vtkExodusIIReader::NODE_ID) { vtkIdTypeArray* iarr; int nMaps; vtkIdType mapSize; vtkExodusIICacheKey ktmp; if (key.ObjectType == vtkExodusIIReader::ELEMENT_ID) { nMaps = this->ModelParameters.num_elem_maps; mapSize = this->ModelParameters.num_elem; ktmp = vtkExodusIICacheKey(-1, vtkExodusIIReader::ELEM_MAP, 0, 0); } else if (key.ObjectType == vtkExodusIIReader::FACE_ID) { nMaps = this->ModelParameters.num_face_maps; mapSize = this->ModelParameters.num_face; ktmp = vtkExodusIICacheKey(-1, vtkExodusIIReader::FACE_MAP, 0, 0); } else if (key.ObjectType == vtkExodusIIReader::EDGE_ID) { nMaps = this->ModelParameters.num_edge_maps; mapSize = this->ModelParameters.num_edge; ktmp = vtkExodusIICacheKey(-1, vtkExodusIIReader::EDGE_MAP, 0, 0); } else // ( key.ObjectType == vtkExodusIIReader::NODE_ID ) { nMaps = this->ModelParameters.num_node_maps; mapSize = this->ModelParameters.num_nodes; ktmp = vtkExodusIICacheKey(-1, vtkExodusIIReader::NODE_MAP, 0, 0); } // If there are no new-style maps, get the old-style map (which creates a default if nothing is // stored on disk). if (nMaps < 1 || !(iarr = vtkArrayDownCast(this->GetCacheOrRead(ktmp)))) { iarr = vtkIdTypeArray::New(); iarr->SetNumberOfComponents(1); iarr->SetNumberOfTuples(mapSize); if (mapSize) { if (ex_get_id_map(exoid, static_cast(ktmp.ObjectType), (vtkIdType*)iarr->GetPointer(0)) < 0) { vtkErrorMacro("Could not read old-style node or element map."); iarr->Delete(); iarr = nullptr; } } } else { // FastDelete will be called below (because we are assumed to have created the array with // New()). So we must reference the array one extra time here to account for the extra // delete... iarr->Register(this); } arr = iarr; } else if (key.ObjectType == vtkExodusIIReader::GLOBAL_CONN) { vtkErrorMacro( "Global connectivity is created in AssembleOutputConnectivity since it can't be cached\n" "with a single vtkDataArray. Who told you to call this routine to get it?"); } else if (key.ObjectType == vtkExodusIIReader::ENTITY_COUNTS) { int ctypidx = (key.ArrayId == 0 ? 0 : 1); int otypidx = conn_obj_idx_cvt[ctypidx]; int otyp = obj_types[otypidx]; BlockInfoType* binfop = (BlockInfoType*)this->GetObjectInfo(otypidx, key.ObjectId); vtkIntArray* iarr = vtkIntArray::New(); iarr->SetNumberOfComponents(1); iarr->SetNumberOfTuples(binfop->Size); if (ex_get_entity_count_per_polyhedra( exoid, static_cast(otyp), binfop->Id, iarr->GetPointer(0)) < 0) { vtkErrorMacro("Unable to read " << binfop->Id << " (index " << key.ObjectId << ") entity count per polyhedra"); iarr->Delete(); iarr = nullptr; } arr = iarr; } else if (key.ObjectType == vtkExodusIIReader::ELEM_BLOCK_ELEM_CONN || key.ObjectType == vtkExodusIIReader::FACE_BLOCK_CONN || key.ObjectType == vtkExodusIIReader::EDGE_BLOCK_CONN) { int ctypidx = this->GetConnTypeIndexFromConnType(key.ObjectType); int otypidx = conn_obj_idx_cvt[ctypidx]; int otyp = obj_types[otypidx]; BlockInfoType* binfop = (BlockInfoType*)this->GetObjectInfo(otypidx, key.ObjectId); auto* iarr = vtkIdTypeArray::New(); if (binfop->CellType == VTK_POLYGON) { iarr->SetNumberOfValues(binfop->BdsPerEntry[0]); } else if (binfop->CellType == VTK_POLYHEDRON) { iarr->SetNumberOfValues(binfop->BdsPerEntry[2]); } else { iarr->SetNumberOfComponents(binfop->BdsPerEntry[0]); iarr->SetNumberOfTuples(binfop->Size); } if (ex_get_conn(exoid, static_cast(otyp), binfop->Id, iarr->GetPointer(0), nullptr, nullptr) < 0) { vtkErrorMacro("Unable to read " << objtype_names[otypidx] << " " << binfop->Id << " (index " << key.ObjectId << ") nodal connectivity."); iarr->Delete(); iarr = nullptr; } vtkIdType c; auto ptr = iarr->GetPointer(0); if (binfop->CellType == VTK_QUADRATIC_HEXAHEDRON || binfop->CellType == VTK_TRIQUADRATIC_HEXAHEDRON) { // Edge order for VTK is different than Exodus edge order. for (c = 0; c < iarr->GetNumberOfTuples(); ++c) { int k; int itmp[4]; for (k = 0; k < 12; ++k, ++ptr) *ptr = *ptr - 1; for (k = 0; k < 4; ++k, ++ptr) { itmp[k] = *ptr; *ptr = ptr[4] - 1; } for (k = 0; k < 4; ++k, ++ptr) *ptr = itmp[k] - 1; if (binfop->CellType == VTK_TRIQUADRATIC_HEXAHEDRON) { // Face/body order for VTK is different than Exodus (Patran) order. for (k = 0; k < 4; ++k, ++ptr) { itmp[k] = *ptr; *ptr = ptr[3] - 1; } *(ptr++) = itmp[1] - 1; *(ptr++) = itmp[2] - 1; *(ptr++) = itmp[0] - 1; } } ptr += binfop->BdsPerEntry[0] - binfop->PointsPerCell; } else if (binfop->CellType == VTK_QUADRATIC_WEDGE) { int k; int itmp[3]; for (c = 0; c < iarr->GetNumberOfTuples(); ++c) { for (k = 0; k < 9; ++k, ++ptr) *ptr = *ptr - 1; for (k = 0; k < 3; ++k, ++ptr) { itmp[k] = *ptr; *ptr = ptr[3] - 1; } for (k = 0; k < 3; ++k, ++ptr) { *ptr = itmp[k] - 1; } } ptr += binfop->BdsPerEntry[0] - binfop->PointsPerCell; } else if ((binfop->CellType == VTK_LAGRANGE_WEDGE && binfop->PointsPerCell == 21) || (binfop->CellType == VTK_BIQUADRATIC_QUADRATIC_WEDGE && binfop->PointsPerCell == 18)) { // Exodus orders edges like so: // r-dir @ -z, 1-r-s-dir @ -z, s-dir @ -z, // t-dir @ +1-r-s, t-dir @ +r, t-dir @ +s, // r-dir @ +z, 1-r-s-dir @ +z, s-dir @ +z, // VTK orders edges like so: // r-dir @ -z, 1-r-s-dir @ -z, s-dir @ -z, // r-dir @ +z, 1-r-s-dir @ +z, s-dir @ +z, // t-dir @ +1-r-s, t-dir @ +r, t-dir @ +s, int k; int itmp[3]; for (c = 0; c < iarr->GetNumberOfTuples(); ++c) { for (k = 0; k < 9; ++k, ++ptr) *ptr = *ptr - 1; for (k = 0; k < 3; ++k, ++ptr) { itmp[k] = *ptr; *ptr = ptr[3] - 1; } for (k = 0; k < 3; ++k, ++ptr) { *ptr = itmp[k] - 1; } // The body-centered node immediately follows the edges in the // Exodus file and is then followed by wedge face nodes, // but not in the same order as VTK or the linear Exodus side-set // ordering: if (binfop->PointsPerCell == 21) { int ftmp[6]; static int wedgeMapping6[6] = { 1, 2, 5, 3, 4, 0 }; for (k = 0; k < 6; ++k) { ftmp[k] = ptr[wedgeMapping6[k]]; } for (k = 0; k < 6; ++k, ++ptr) { *ptr = ftmp[k] - 1; } } else { for (k = 0; k < 3; ++k, ++ptr) *ptr = *ptr - 1; } } ptr += binfop->BdsPerEntry[0] - binfop->PointsPerCell; } else if (binfop->CellType == VTK_LAGRANGE_TETRAHEDRON && binfop->PointsPerCell == 15) { int k; for (c = 0; c < iarr->GetNumberOfTuples(); ++c) { // Tet corners and edges are ordered as expected for (k = 0; k < 10; ++k, ++ptr) { *ptr = *ptr - 1; } // ... but the body-centered node is placed *before* the // tet face nodes and the faces are not in the canonical // side-set ordering. static int tetMapping[5] = { 1, 4, 2, 3, 0 }; int ftmp[5]; for (k = 0; k < 5; ++k) { ftmp[k] = ptr[tetMapping[k]]; } for (k = 0; k < 5; ++k, ++ptr) { *ptr = ftmp[k] - 1; } } ptr += binfop->BdsPerEntry[0] - binfop->PointsPerCell; } else { for (c = 0; c <= iarr->GetMaxId(); ++c, ++ptr) { *ptr = *ptr - 1; } } arr = iarr; } else if (key.ObjectType == vtkExodusIIReader::ELEM_BLOCK_FACE_CONN || key.ObjectType == vtkExodusIIReader::ELEM_BLOCK_EDGE_CONN) { arr = nullptr; // bdsEntry will determine whether we call ex_get_conn to read edge or face connectivity: int bdsEntry = key.ObjectType == vtkExodusIIReader::ELEM_BLOCK_EDGE_CONN ? 1 : 2; // Fetch the block information from the key // int ctypidx = this->GetConnTypeIndexFromConnType( key.ObjectType ); int otypidx = 2; // These always refer to the element block int otyp = obj_types[otypidx]; BlockInfoType* binfop = (BlockInfoType*)this->GetObjectInfo(otypidx, key.ObjectId); // Only create the array if there's anything to put in it. if (binfop->BdsPerEntry[bdsEntry] > 0) { auto* iarr = vtkIdTypeArray::New(); iarr->SetNumberOfValues(binfop->BdsPerEntry[2]); if (ex_get_conn(exoid, static_cast(otyp), binfop->Id, nullptr, bdsEntry == 1 ? iarr->GetPointer(0) : nullptr, bdsEntry == 2 ? iarr->GetPointer(0) : nullptr) < 0) { vtkErrorMacro("Unable to read " << objtype_names[otypidx] << " " << binfop->Id << " (index " << key.ObjectId << ") " << (bdsEntry == 1 ? "edge" : "face") << " connectivity."); iarr->Delete(); iarr = nullptr; } else { vtkIdType c; auto ptr = iarr->GetPointer(0); for (c = 0; c <= iarr->GetMaxId(); ++c, ++ptr) { *ptr = *ptr - 1; } } arr = iarr; } } else if (key.ObjectType == vtkExodusIIReader::NODE_SET_CONN || key.ObjectType == vtkExodusIIReader::ELEM_SET_CONN) { int otyp = this->GetSetTypeFromSetConnType(key.ObjectType); int otypidx = this->GetObjectTypeIndexFromObjectType(otyp); SetInfoType* sinfop = &this->SetInfo[otyp][key.ObjectId]; auto* iarr = vtkIdTypeArray::New(); iarr->SetNumberOfComponents(1); iarr->SetNumberOfTuples(sinfop->Size); auto iptr = iarr->GetPointer(0); if (ex_get_set(exoid, static_cast(otyp), sinfop->Id, iptr, nullptr) < 0) { vtkErrorMacro("Unable to read " << objtype_names[otypidx] << " " << sinfop->Id << " (index " << key.ObjectId << ") nodal connectivity."); iarr->Delete(); iarr = nullptr; } vtkIdType id; for (id = 0; id < sinfop->Size; ++id, ++iptr) { // VTK uses 0-based indexing, unlike Exodus: --(*iptr); } arr = iarr; } else if (key.ObjectType == vtkExodusIIReader::EDGE_SET_CONN || key.ObjectType == vtkExodusIIReader::FACE_SET_CONN) { int otyp = this->GetSetTypeFromSetConnType(key.ObjectType); int otypidx = this->GetObjectTypeIndexFromObjectType(otyp); SetInfoType* sinfop = &this->SetInfo[otyp][key.ObjectId]; auto* iarr = vtkIdTypeArray::New(); iarr->SetNumberOfComponents(2); iarr->SetNumberOfTuples(sinfop->Size); std::vector tmpOrient; // hold the edge/face orientation information until we can interleave it. tmpOrient.resize(sinfop->Size); if (ex_get_set(exoid, static_cast(otyp), sinfop->Id, iarr->GetPointer(0), &tmpOrient[0]) < 0) { vtkErrorMacro("Unable to read " << objtype_names[otypidx] << " " << sinfop->Id << " (index " << key.ObjectId << ") nodal connectivity."); iarr->Delete(); iarr = nullptr; return nullptr; } auto iap = iarr->GetPointer(0); vtkIdType c; for (c = sinfop->Size - 1; c >= 0; --c) { iap[2 * c] = iap[c] - 1; // VTK uses 0-based indexing iap[2 * c + 1] = tmpOrient[c]; } arr = iarr; } else if (key.ObjectType == vtkExodusIIReader::SIDE_SET_CONN) { if (key.ArrayId <= 0) { // Stick all of side_set_node_list and side_set_node_count and side_set_nodes_per_side in one // array let InsertSetSides() figure it all out. Except for 0-based indexing SetInfoType* sinfop = &this->SetInfo[vtkExodusIIReader::SIDE_SET][key.ObjectId]; vtkIdType ssnllen; // side set node list length if (ex_get_side_set_node_list_len(exoid, sinfop->Id, &ssnllen) < 0) { vtkErrorMacro("Unable to fetch side set \"" << sinfop->Name.c_str() << "\" (" << sinfop->Id << ") node list length"); arr = nullptr; return nullptr; } auto* iarr = vtkIdTypeArray::New(); vtkIdType ilen = ssnllen + sinfop->Size; iarr->SetNumberOfComponents(1); iarr->SetNumberOfTuples(ilen); auto* dat = iarr->GetPointer(0); if (ex_get_side_set_node_list(exoid, sinfop->Id, dat, dat + sinfop->Size) < 0) { vtkErrorMacro("Unable to fetch side set \"" << sinfop->Name.c_str() << "\" (" << sinfop->Id << ") node list"); iarr->Delete(); arr = nullptr; return nullptr; } while (ilen > sinfop->Size) { // move to 0-based indexing on nodes, don't touch nodes/side counts at head of array --dat[--ilen]; } arr = iarr; } // if(key.ArrayId <= 0) else { // return information about where the side set cells come from on the elements // the first tuple value is the element id and the second is the canonical side // sinfop->Size is the number of sides in this side set SetInfoType* sinfop = &this->SetInfo[vtkExodusIIReader::SIDE_SET][key.ObjectId]; std::vector side_set_elem_list(sinfop->Size); std::vector side_set_side_list(sinfop->Size); if (ex_get_side_set(exoid, sinfop->Id, &side_set_elem_list[0], &side_set_side_list[0]) < 0) { vtkErrorMacro("Unable to fetch side set \"" << sinfop->Name.c_str() << "\" (" << sinfop->Id << ") node list"); arr = nullptr; return nullptr; } vtkIdTypeArray* iarr = vtkIdTypeArray::New(); iarr->SetNumberOfComponents(2); iarr->SetNumberOfTuples(sinfop->Size); for (int i = 0; i < sinfop->Size; i++) { // we'll have to fix up the side indexing later // because Exodus and VTK have different canonical orderings for wedges and hexes. vtkIdType info[2] = { side_set_elem_list[i], side_set_side_list[i] }; iarr->SetTypedTuple(i, info); } arr = iarr; } } else if (key.ObjectType == vtkExodusIIReader::NODAL_COORDS) { // read node coords vtkDataArray* displ = nullptr; if (this->ApplyDisplacements && key.Time >= 0) { displ = this->FindDisplacementVectors(key.Time); } std::vector coordTmp; vtkDoubleArray* darr = vtkDoubleArray::New(); arr = darr; arr->SetNumberOfComponents(3); arr->SetNumberOfTuples(this->ModelParameters.num_nodes); int dim = this->ModelParameters.num_dim; int c; vtkIdType t; double* xc = nullptr; double* yc = nullptr; double* zc = nullptr; coordTmp.resize(this->ModelParameters.num_nodes); for (c = 0; c < dim; ++c) { switch (c) { case 0: xc = &coordTmp[0]; break; case 1: yc = xc; xc = nullptr; break; case 2: zc = yc; yc = nullptr; break; default: vtkErrorMacro("Bad coordinate index " << c << " when reading point coordinates."); xc = yc = zc = nullptr; } if (ex_get_coord(exoid, xc, yc, zc) < 0) { vtkErrorMacro("Unable to read node coordinates for index " << c << "."); arr->Delete(); arr = nullptr; break; } double* cptr = darr->GetPointer(c); // // num_nodes can get big. Lets unroll the loop // for (t = 0; t + 8 < this->ModelParameters.num_nodes; t += 8) { *(cptr + 3 * 0) = coordTmp[t + 0]; *(cptr + 3 * 1) = coordTmp[t + 1]; *(cptr + 3 * 2) = coordTmp[t + 2]; *(cptr + 3 * 3) = coordTmp[t + 3]; *(cptr + 3 * 4) = coordTmp[t + 4]; *(cptr + 3 * 5) = coordTmp[t + 5]; *(cptr + 3 * 6) = coordTmp[t + 6]; *(cptr + 3 * 7) = coordTmp[t + 7]; cptr += 3 * 8; } for (; t < this->ModelParameters.num_nodes; ++t) { *cptr = coordTmp[t]; cptr += 3; } } if (dim < 3) { double* cptr = darr->GetPointer(2); for (t = 0; t < this->ModelParameters.num_nodes; ++t, cptr += 3) { *cptr = 0.; } } // // Unrolling some of the inner loops for the most common case - dim 3. // Also moving the maxTuples from inside of the for(;;) loops // Also moving cos() calculations out of the bottom of loops. // if (displ) { double* coords = darr->GetPointer(0); if (this->HasModeShapes && this->AnimateModeShapes) { double tempDouble = this->DisplacementMagnitude * cos(2.0 * vtkMath::Pi() * this->ModeShapeTime); if (dim == 3) { vtkIdType maxTuples = arr->GetNumberOfTuples(); for (vtkIdType idx = 0; idx < maxTuples; ++idx) { double* dispVal = displ->GetTuple(idx); coords[0] += dispVal[0] * tempDouble; coords[1] += dispVal[1] * tempDouble; coords[2] += dispVal[2] * tempDouble; coords += 3; } } else { for (vtkIdType idx = 0; idx < displ->GetNumberOfTuples(); ++idx) { double* dispVal = displ->GetTuple(idx); for (c = 0; c < dim; ++c) coords[c] += dispVal[c] * tempDouble; coords += 3; } } } else { if (dim == 3) { vtkIdType maxTuples = arr->GetNumberOfTuples(); for (vtkIdType idx = 0; idx < maxTuples; ++idx) { double* dispVal = displ->GetTuple(idx); coords[0] += dispVal[0] * this->DisplacementMagnitude; coords[1] += dispVal[1] * this->DisplacementMagnitude; coords[2] += dispVal[2] * this->DisplacementMagnitude; coords += 3; } } else { for (vtkIdType idx = 0; idx < displ->GetNumberOfTuples(); ++idx) { double* dispVal = displ->GetTuple(idx); for (c = 0; c < dim; ++c) coords[c] += dispVal[c] * this->DisplacementMagnitude; coords += 3; } } } } } else if (key.ObjectType == vtkExodusIIReader::OBJECT_ID) { BlockSetInfoType* bsinfop; // Yes, the next 2 statements are an intentional misuse of key // fields reserved for the ObjectId and ArrayId (since ObjectType // is used to signal that we want IDs instead of a field value). int otypidx = this->GetObjectTypeIndexFromObjectType(key.ObjectId); int obj = key.ArrayId; bsinfop = (BlockSetInfoType*)this->GetObjectInfo(otypidx, obj); arr = vtkIntArray::New(); arr->SetName(vtkExodusIIReaderPrivate::GetObjectIdArrayName()); arr->SetNumberOfComponents(1); arr->SetNumberOfTuples(bsinfop->Size); arr->FillComponent(0, bsinfop->Id); } else if (key.ObjectType == vtkExodusIIReader::ELEM_BLOCK_ATTRIB || key.ObjectType == vtkExodusIIReader::FACE_BLOCK_ATTRIB || key.ObjectType == vtkExodusIIReader::EDGE_BLOCK_ATTRIB) { int blkType = (key.ObjectType == vtkExodusIIReader::ELEM_BLOCK_ATTRIB ? vtkExodusIIReader::ELEM_BLOCK : (key.ObjectType == vtkExodusIIReader::FACE_BLOCK_ATTRIB ? vtkExodusIIReader::FACE_BLOCK : vtkExodusIIReader::EDGE_BLOCK)); BlockInfoType* binfop = &this->BlockInfo[blkType][key.ObjectId]; vtkDoubleArray* darr = vtkDoubleArray::New(); arr = darr; darr->SetName(binfop->AttributeNames[key.ArrayId].c_str()); darr->SetNumberOfComponents(1); darr->SetNumberOfTuples(binfop->Size); if (ex_get_one_attr(exoid, static_cast(blkType), binfop->Id, key.ArrayId + 1, darr->GetVoidPointer(0)) < 0) { // NB: The error message references the file-order object id, not the numerically sorted index // presented to users. vtkErrorMacro("Unable to read attribute " << key.ArrayId << " for object " << key.ObjectId << " of type " << key.ObjectType << " block type " << blkType << "."); arr->Delete(); arr = nullptr; } } else if (key.ObjectType == vtkExodusIIReader::INFO_RECORDS) { // Get Exodus II INFO records. Each INFO record is a single character string. vtkIdType num_info = 0; float fdum; char* cdum = nullptr; int i; vtkCharArray* carr = vtkCharArray::New(); carr->SetName("Info_Records"); carr->SetNumberOfComponents(MAX_LINE_LENGTH + 1); if (ex_inquire(exoid, EX_INQ_INFO, &num_info, &fdum, cdum) < 0) { vtkErrorMacro("Unable to get number of INFO records from ex_inquire"); carr->Delete(); arr = nullptr; } else { if (num_info > 0) { carr->SetNumberOfTuples(num_info); char** info = (char**)calloc(num_info, sizeof(char*)); for (i = 0; i < num_info; ++i) info[i] = (char*)calloc((MAX_LINE_LENGTH + 1), sizeof(char)); if (ex_get_info(exoid, info) < 0) { vtkErrorMacro("Unable to read INFO records from ex_get_info"); carr->Delete(); arr = nullptr; } else { for (i = 0; i < num_info; ++i) { carr->InsertTypedTuple(i, info[i]); } arr = carr; } for (i = 0; i < num_info; ++i) { free(info[i]); } free(info); } else { carr->Delete(); arr = nullptr; } } } else if (key.ObjectType == vtkExodusIIReader::QA_RECORDS) { // Get Exodus II QA records. Each QA record is made up of 4 character strings. vtkIdType num_qa_rec = 0; float fdum; char* cdum = nullptr; int i, j; vtkCharArray* carr = vtkCharArray::New(); carr->SetName("QA_Records"); carr->SetNumberOfComponents(maxNameLength + 1); if (ex_inquire(exoid, EX_INQ_QA, &num_qa_rec, &fdum, cdum) < 0) { vtkErrorMacro("Unable to get number of QA records from ex_inquire"); carr->Delete(); arr = nullptr; } else { if (num_qa_rec > 0) { carr->SetNumberOfTuples(num_qa_rec * 4); char*(*qa_record)[4] = (char*(*)[4])calloc(num_qa_rec, sizeof(*qa_record)); for (i = 0; i < num_qa_rec; ++i) { for (j = 0; j < 4; ++j) { // QA record string length is different than MaxNameLength qa_record[i][j] = (char*)calloc((MAX_STR_LENGTH + 1), sizeof(char)); } } if (ex_get_qa(exoid, qa_record) < 0) { vtkErrorMacro("Unable to read QA records from ex_get_qa"); carr->Delete(); arr = nullptr; } else { for (i = 0; i < num_qa_rec; ++i) { for (j = 0; j < 4; ++j) { carr->InsertTypedTuple((i * 4) + j, qa_record[i][j]); } } arr = carr; } for (i = 0; i < num_qa_rec; ++i) { for (j = 0; j < 4; ++j) { free(qa_record[i][j]); } } free(qa_record); } else { carr->Delete(); arr = nullptr; } } } else { vtkWarningMacro("You requested an array for objects of type " << key.ObjectType << " which I know nothing about"); arr = nullptr; } // Even if the array is larger than the allowable cache size, it will keep the most recent // insertion. So, we delete our reference knowing that the Cache will keep the object "alive" // until whatever called GetCacheOrRead() references the array. But, once you get an array from // GetCacheOrRead(), you better start running! if (arr) { this->Cache->Insert(key, arr); arr->FastDelete(); } return arr; } //------------------------------------------------------------------------------ int vtkExodusIIReaderPrivate::GetConnTypeIndexFromConnType(int ctyp) { int i; for (i = 0; i < num_conn_types; ++i) { if (conn_types[i] == ctyp) { return i; } } return -1; } //------------------------------------------------------------------------------ int vtkExodusIIReaderPrivate::GetObjectTypeIndexFromObjectType(int otyp) { int i; for (i = 0; i < num_obj_types; ++i) { if (obj_types[i] == otyp) { return i; } } return -1; } //------------------------------------------------------------------------------ int vtkExodusIIReaderPrivate::GetNumberOfObjectsAtTypeIndex(int typeIndex) { if (typeIndex < 0) { return 0; } else if (typeIndex < 3) { return (int)this->BlockInfo[obj_types[typeIndex]].size(); } else if (typeIndex < 8) { return (int)this->SetInfo[obj_types[typeIndex]].size(); } else if (typeIndex < 12) { return (int)this->MapInfo[obj_types[typeIndex]].size(); } return 0; } //------------------------------------------------------------------------------ vtkExodusIIReaderPrivate::ObjectInfoType* vtkExodusIIReaderPrivate::GetObjectInfo( int typeIndex, int objectIndex) { if (typeIndex < 0) { return nullptr; } else if (typeIndex < 3) { return &this->BlockInfo[obj_types[typeIndex]][objectIndex]; } else if (typeIndex < 8) { return &this->SetInfo[obj_types[typeIndex]][objectIndex]; } else if (typeIndex < 12) { return &this->MapInfo[obj_types[typeIndex]][objectIndex]; } return nullptr; } //------------------------------------------------------------------------------ vtkExodusIIReaderPrivate::ObjectInfoType* vtkExodusIIReaderPrivate::GetSortedObjectInfo( int otyp, int k) { int i = this->GetObjectTypeIndexFromObjectType(otyp); if (i < 0) { vtkDebugMacro("Could not find collection of objects with type " << otyp << "."); return nullptr; } int N = this->GetNumberOfObjectsAtTypeIndex(i); if (k < 0 || k >= N) { const char* otname = i >= 0 ? objtype_names[i] : "object"; static_cast(otname); // not referenced warning vtkDebugMacro( "You requested " << otname << " " << k << " in a collection of only " << N << " objects."); return nullptr; } return this->GetObjectInfo(i, this->SortedObjectIndices[otyp][k]); } //------------------------------------------------------------------------------ vtkExodusIIReaderPrivate::ObjectInfoType* vtkExodusIIReaderPrivate::GetUnsortedObjectInfo( int otyp, int k) { int i = this->GetObjectTypeIndexFromObjectType(otyp); if (i < 0) { vtkDebugMacro("Could not find collection of objects with type " << otyp << "."); return nullptr; } int N = this->GetNumberOfObjectsAtTypeIndex(i); if (k < 0 || k >= N) { const char* otname = i >= 0 ? objtype_names[i] : "object"; static_cast(otname); // not referenced warning vtkDebugMacro( "You requested " << otname << " " << k << " in a collection of only " << N << " objects."); return nullptr; } return this->GetObjectInfo(i, k); } //------------------------------------------------------------------------------ int vtkExodusIIReaderPrivate::GetBlockIndexFromFileGlobalId(int otyp, int refId) { std::vector::iterator bi; int i = 0; for (bi = this->BlockInfo[otyp].begin(); bi != this->BlockInfo[otyp].end(); ++bi, ++i) { if (refId >= bi->FileOffset && refId <= bi->FileOffset + bi->Size) return i; } return -1; } //------------------------------------------------------------------------------ vtkExodusIIReaderPrivate::BlockInfoType* vtkExodusIIReaderPrivate::GetBlockFromFileGlobalId( int otyp, int refId) { int blk = this->GetBlockIndexFromFileGlobalId(otyp, refId); if (blk >= 0) { return &this->BlockInfo[otyp][blk]; } return nullptr; } //------------------------------------------------------------------------------ vtkIdType vtkExodusIIReaderPrivate::GetSqueezePointId(BlockSetInfoType* bsinfop, int i) { if (i < 0) { vtkGenericWarningMacro("Invalid point id: " << i << ". Data file may be incorrect."); throw std::runtime_error("invalid point id in `GetSqueezePointId`"); } vtkIdType x; std::map::iterator it = bsinfop->PointMap.find(i); if (it == bsinfop->PointMap.end()) { // Nothing found; add a new entry to the map. x = bsinfop->NextSqueezePoint++; bsinfop->PointMap[i] = x; bsinfop->ReversePointMap[x] = i; } else { x = it->second; } return x; } //------------------------------------------------------------------------------ void vtkExodusIIReaderPrivate::DetermineVtkCellType(BlockInfoType& binfo) { vtkStdString elemType(vtksys::SystemTools::UpperCase(binfo.TypeName)); // Check for quadratic elements if ((elemType.substr(0, 3) == "TRI") && (binfo.BdsPerEntry[0] == 6)) { binfo.CellType = VTK_QUADRATIC_TRIANGLE; binfo.PointsPerCell = 6; } else if ((elemType.substr(0, 3) == "SHE") && (binfo.BdsPerEntry[0] == 8)) { binfo.CellType = VTK_QUADRATIC_QUAD; binfo.PointsPerCell = 8; } else if ((elemType.substr(0, 3) == "SHE") && (binfo.BdsPerEntry[0] == 9)) { binfo.CellType = VTK_QUADRATIC_QUAD; binfo.PointsPerCell = 8; } else if ((elemType.substr(0, 3) == "TET") && (binfo.BdsPerEntry[0] == 10)) { binfo.CellType = VTK_QUADRATIC_TETRA; binfo.PointsPerCell = 10; } else if ((elemType.substr(0, 3) == "TET") && (binfo.BdsPerEntry[0] == 11)) { binfo.CellType = VTK_QUADRATIC_TETRA; binfo.PointsPerCell = 10; } else if ((elemType.substr(0, 3) == "TET") && (binfo.BdsPerEntry[0] == 15)) { binfo.CellType = VTK_LAGRANGE_TETRAHEDRON; binfo.PointsPerCell = 15; } else if ((elemType.substr(0, 3) == "WED") && (binfo.BdsPerEntry[0] == 15)) { binfo.CellType = VTK_QUADRATIC_WEDGE; binfo.PointsPerCell = 15; } else if ((elemType.substr(0, 3) == "WED") && (binfo.BdsPerEntry[0] == 18)) { binfo.CellType = VTK_BIQUADRATIC_QUADRATIC_WEDGE; binfo.PointsPerCell = 18; } else if ((elemType.substr(0, 3) == "WED") && (binfo.BdsPerEntry[0] == 21)) { binfo.CellType = VTK_LAGRANGE_WEDGE; binfo.PointsPerCell = 21; } else if ((elemType.substr(0, 3) == "HEX") && (binfo.BdsPerEntry[0] == 20)) { binfo.CellType = VTK_QUADRATIC_HEXAHEDRON; binfo.PointsPerCell = 20; } else if ((elemType.substr(0, 3) == "HEX") && (binfo.BdsPerEntry[0] == 21)) { binfo.CellType = VTK_QUADRATIC_HEXAHEDRON; binfo.PointsPerCell = 20; } else if ((elemType.substr(0, 3) == "HEX") && (binfo.BdsPerEntry[0] == 27)) { binfo.CellType = VTK_TRIQUADRATIC_HEXAHEDRON; binfo.PointsPerCell = 27; } else if ((elemType.substr(0, 3) == "QUA") && (binfo.BdsPerEntry[0] == 8)) { binfo.CellType = VTK_QUADRATIC_QUAD; binfo.PointsPerCell = 8; } else if ((elemType.substr(0, 3) == "QUA") && (binfo.BdsPerEntry[0] == 9)) { binfo.CellType = VTK_BIQUADRATIC_QUAD; binfo.PointsPerCell = 9; } else if ((elemType.substr(0, 3) == "TRU") && (binfo.BdsPerEntry[0] == 3)) { binfo.CellType = VTK_QUADRATIC_EDGE; binfo.PointsPerCell = 3; } else if ((elemType.substr(0, 3) == "BEA") && (binfo.BdsPerEntry[0] == 3)) { binfo.CellType = VTK_QUADRATIC_EDGE; binfo.PointsPerCell = 3; } else if ((elemType.substr(0, 3) == "BAR") && (binfo.BdsPerEntry[0] == 3)) { binfo.CellType = VTK_QUADRATIC_EDGE; binfo.PointsPerCell = 3; } else if ((elemType.substr(0, 3) == "EDG") && (binfo.BdsPerEntry[0] == 3)) { binfo.CellType = VTK_QUADRATIC_EDGE; binfo.PointsPerCell = 3; } else if ((elemType.substr(0, 3) == "PYR") && (binfo.BdsPerEntry[0] == 13)) { binfo.CellType = VTK_QUADRATIC_PYRAMID; binfo.PointsPerCell = 13; } // Check for regular elements else if (elemType.substr(0, 3) == "CIR") { binfo.CellType = VTK_VERTEX; binfo.PointsPerCell = 1; } else if (elemType.substr(0, 3) == "SPH") { binfo.CellType = VTK_VERTEX; binfo.PointsPerCell = 1; } else if (elemType.substr(0, 3) == "BAR") { binfo.CellType = VTK_LINE; binfo.PointsPerCell = 2; } else if (elemType.substr(0, 3) == "TRU") { binfo.CellType = VTK_LINE; binfo.PointsPerCell = 2; } else if (elemType.substr(0, 3) == "BEA") { binfo.CellType = VTK_LINE; binfo.PointsPerCell = 2; } else if (elemType.substr(0, 3) == "EDG") { binfo.CellType = VTK_LINE; binfo.PointsPerCell = 2; } else if (elemType.substr(0, 3) == "TRI") { binfo.CellType = VTK_TRIANGLE; binfo.PointsPerCell = 3; } else if (elemType.substr(0, 3) == "QUA") { binfo.CellType = VTK_QUAD; binfo.PointsPerCell = 4; } else if (elemType.substr(0, 3) == "TET") { binfo.CellType = VTK_TETRA; binfo.PointsPerCell = 4; } else if (elemType.substr(0, 3) == "PYR") { binfo.CellType = VTK_PYRAMID; binfo.PointsPerCell = 5; } else if (elemType.substr(0, 3) == "WED") { binfo.CellType = VTK_WEDGE; binfo.PointsPerCell = 6; } else if (elemType.substr(0, 3) == "HEX") { binfo.CellType = VTK_HEXAHEDRON; binfo.PointsPerCell = 8; } else if (elemType.substr(0, 3) == "NSI") { binfo.CellType = VTK_POLYGON; binfo.PointsPerCell = 0; } else if (elemType.substr(0, 3) == "NFA") { binfo.CellType = VTK_POLYHEDRON; binfo.PointsPerCell = 0; } else if ((elemType.substr(0, 3) == "SHE") && (binfo.BdsPerEntry[0] == 3)) { binfo.CellType = VTK_TRIANGLE; binfo.PointsPerCell = 3; } else if ((elemType.substr(0, 3) == "SHE") && (binfo.BdsPerEntry[0] == 4)) { binfo.CellType = VTK_QUAD; binfo.PointsPerCell = 4; } else if ((elemType.substr(0, 8) == "STRAIGHT") && (binfo.BdsPerEntry[0] == 2)) { binfo.CellType = VTK_LINE; binfo.PointsPerCell = 2; } else if (elemType.substr(0, 3) == "SUP") { binfo.CellType = VTK_POLY_VERTEX; binfo.PointsPerCell = binfo.BdsPerEntry[0]; } else if ((elemType.substr(0, 4) == "NULL") && (binfo.Size == 0)) { (void)binfo; // silently ignore empty element blocks } else { vtkErrorMacro("Unsupported element type: " << elemType.c_str()); } // cell types not currently handled // quadratic wedge - 15,16 nodes // quadratic pyramid - 13 nodes } //------------------------------------------------------------------------------ vtkExodusIIReaderPrivate::ArrayInfoType* vtkExodusIIReaderPrivate::FindArrayInfoByName( int otyp, const char* name) { std::vector::iterator ai; for (ai = this->ArrayInfo[otyp].begin(); ai != this->ArrayInfo[otyp].end(); ++ai) { if (ai->Name == name) return &(*ai); } return nullptr; } //------------------------------------------------------------------------------ int vtkExodusIIReaderPrivate::IsObjectTypeBlock(int otyp) { return (otyp == vtkExodusIIReader::ELEM_BLOCK || otyp == vtkExodusIIReader::EDGE_BLOCK || otyp == vtkExodusIIReader::FACE_BLOCK); } //------------------------------------------------------------------------------ int vtkExodusIIReaderPrivate::IsObjectTypeSet(int otyp) { return (otyp == vtkExodusIIReader::ELEM_SET || otyp == vtkExodusIIReader::EDGE_SET || otyp == vtkExodusIIReader::FACE_SET || otyp == vtkExodusIIReader::NODE_SET || otyp == vtkExodusIIReader::SIDE_SET); } //------------------------------------------------------------------------------ int vtkExodusIIReaderPrivate::IsObjectTypeMap(int otyp) { return (otyp == vtkExodusIIReader::ELEM_MAP || otyp == vtkExodusIIReader::EDGE_MAP || otyp == vtkExodusIIReader::FACE_MAP || otyp == vtkExodusIIReader::NODE_MAP); } //------------------------------------------------------------------------------ int vtkExodusIIReaderPrivate::GetObjectTypeFromMapType(int mtyp) { switch (mtyp) { case vtkExodusIIReader::ELEM_MAP: return vtkExodusIIReader::ELEM_BLOCK; case vtkExodusIIReader::FACE_MAP: return vtkExodusIIReader::FACE_BLOCK; case vtkExodusIIReader::EDGE_MAP: return vtkExodusIIReader::EDGE_BLOCK; case vtkExodusIIReader::NODE_MAP: return vtkExodusIIReader::NODAL; } return -1; } //------------------------------------------------------------------------------ int vtkExodusIIReaderPrivate::GetMapTypeFromObjectType(int otyp) { switch (otyp) { case vtkExodusIIReader::ELEM_BLOCK: return vtkExodusIIReader::ELEM_MAP; case vtkExodusIIReader::FACE_BLOCK: return vtkExodusIIReader::FACE_MAP; case vtkExodusIIReader::EDGE_BLOCK: return vtkExodusIIReader::EDGE_MAP; case vtkExodusIIReader::NODAL: return vtkExodusIIReader::NODE_MAP; } return -1; } //------------------------------------------------------------------------------ int vtkExodusIIReaderPrivate::GetTemporalTypeFromObjectType(int otyp) { switch (otyp) { case vtkExodusIIReader::ELEM_BLOCK: return vtkExodusIIReader::ELEM_BLOCK_TEMPORAL; // case vtkExodusIIReader::FACE_BLOCK: // return vtkExodusIIReader::FACE_MAP; // case vtkExodusIIReader::EDGE_BLOCK: // return vtkExodusIIReader::EDGE_MAP; case vtkExodusIIReader::NODAL: return vtkExodusIIReader::NODAL_TEMPORAL; case vtkExodusIIReader::GLOBAL: return vtkExodusIIReader::GLOBAL_TEMPORAL; } return -1; } //------------------------------------------------------------------------------ int vtkExodusIIReaderPrivate::GetSetTypeFromSetConnType(int sctyp) { switch (sctyp) { case vtkExodusIIReader::NODE_SET_CONN: return vtkExodusIIReader::NODE_SET; case vtkExodusIIReader::EDGE_SET_CONN: return vtkExodusIIReader::EDGE_SET; case vtkExodusIIReader::FACE_SET_CONN: return vtkExodusIIReader::FACE_SET; case vtkExodusIIReader::SIDE_SET_CONN: return vtkExodusIIReader::SIDE_SET; case vtkExodusIIReader::ELEM_SET_CONN: return vtkExodusIIReader::ELEM_SET; } return -1; } //------------------------------------------------------------------------------ int vtkExodusIIReaderPrivate::GetBlockConnTypeFromBlockType(int btyp) { switch (btyp) { case vtkExodusIIReader::EDGE_BLOCK: return vtkExodusIIReader::EDGE_BLOCK_CONN; case vtkExodusIIReader::FACE_BLOCK: return vtkExodusIIReader::FACE_BLOCK_CONN; case vtkExodusIIReader::ELEM_BLOCK: return vtkExodusIIReader::ELEM_BLOCK_ELEM_CONN; } return -1; } //------------------------------------------------------------------------------ void vtkExodusIIReaderPrivate::RemoveBeginningAndTrailingSpaces( int len, char** names, int maxNameLength) { for (int i = 0; i < len; i++) { char* c = names[i]; int nmlen = (int)strlen(c); char* cbegin = c; char* cend = c + nmlen - 1; // remove spaces or non-printing character from start and end for (int j = 0; j < nmlen; j++) { if (!isgraph(*cbegin)) cbegin++; else break; } for (int j = 0; j < nmlen; j++) { if (!isgraph(*cend)) cend--; else break; } if (cend < cbegin) { snprintf(names[i], maxNameLength + 1, "null_%d", i); continue; } int newlen = cend - cbegin + 1; if (newlen < nmlen) { for (int j = 0; j < newlen; j++) { *c++ = *cbegin++; } *c = '\0'; } } } //------------------------------------------------------------------------------ void vtkExodusIIReaderPrivate::ClearConnectivityCaches() { std::map>::iterator blksit; for (blksit = this->BlockInfo.begin(); blksit != this->BlockInfo.end(); ++blksit) { std::vector::iterator blkit; for (blkit = blksit->second.begin(); blkit != blksit->second.end(); ++blkit) { if (blkit->CachedConnectivity) { blkit->CachedConnectivity->Delete(); blkit->CachedConnectivity = nullptr; } } } std::map>::iterator setsit; for (setsit = this->SetInfo.begin(); setsit != this->SetInfo.end(); ++setsit) { std::vector::iterator setit; for (setit = setsit->second.begin(); setit != setsit->second.end(); ++setit) { if (setit->CachedConnectivity) { setit->CachedConnectivity->Delete(); setit->CachedConnectivity = nullptr; } } } } //------------------------------------------------------------------------------ void vtkExodusIIReaderPrivate::SetParser(vtkExodusIIReaderParser* parser) { // Properly sets the parser object but does not call Modified. The parser // represents the state of the data in files, not the state of this object. if (this->Parser != parser) { vtkExodusIIReaderParser* oldParser = this->Parser; this->Parser = parser; if (this->Parser) this->Parser->Register(this); if (oldParser) oldParser->UnRegister(this); } } //------------------------------------------------------------------------------ int vtkExodusIIReaderPrivate::GetNumberOfParts() { return static_cast(this->PartInfo.size()); } //------------------------------------------------------------------------------ const char* vtkExodusIIReaderPrivate::GetPartName(int idx) { return this->PartInfo[idx].Name.c_str(); } //------------------------------------------------------------------------------ const char* vtkExodusIIReaderPrivate::GetPartBlockInfo(int idx) { char buffer[80]; vtkStdString blocks; std::vector blkIndices = this->PartInfo[idx].BlockIndices; for (unsigned int i = 0; i < blkIndices.size(); i++) { snprintf(buffer, sizeof(buffer), "%d, ", blkIndices[i]); blocks += buffer; } blocks.erase(blocks.size() - 2, blocks.size() - 1); return blocks.c_str(); } //------------------------------------------------------------------------------ int vtkExodusIIReaderPrivate::GetPartStatus(int idx) { // a part is only active if all its blocks are active std::vector blkIndices = this->PartInfo[idx].BlockIndices; for (unsigned int i = 0; i < blkIndices.size(); i++) { if (!this->GetUnsortedObjectStatus(vtkExodusIIReader::ELEM_BLOCK, blkIndices[i])) { return 0; } } return 1; } //------------------------------------------------------------------------------ int vtkExodusIIReaderPrivate::GetPartStatus(const vtkStdString& name) { for (unsigned int i = 0; i < this->PartInfo.size(); i++) { if (this->PartInfo[i].Name == name) { return this->GetPartStatus(i); } } return -1; } //------------------------------------------------------------------------------ void vtkExodusIIReaderPrivate::SetPartStatus(int idx, int on) { // update the block status for all the blocks in this part std::vector blkIndices = this->PartInfo[idx].BlockIndices; for (unsigned int i = 0; i < blkIndices.size(); i++) { this->SetUnsortedObjectStatus(vtkExodusIIReader::ELEM_BLOCK, blkIndices[i], on); } } //------------------------------------------------------------------------------ void vtkExodusIIReaderPrivate::SetPartStatus(const vtkStdString& name, int flag) { for (unsigned int idx = 0; idx < this->PartInfo.size(); ++idx) { if (name == this->PartInfo[idx].Name) { this->SetPartStatus(idx, flag); return; } } } //------------------------------------------------------------------------------ int vtkExodusIIReaderPrivate::GetNumberOfMaterials() { return static_cast(this->MaterialInfo.size()); } //------------------------------------------------------------------------------ const char* vtkExodusIIReaderPrivate::GetMaterialName(int idx) { return this->MaterialInfo[idx].Name.c_str(); } //------------------------------------------------------------------------------ int vtkExodusIIReaderPrivate::GetMaterialStatus(int idx) { std::vector blkIndices = this->MaterialInfo[idx].BlockIndices; for (unsigned int i = 0; i < blkIndices.size(); i++) { if (!this->GetUnsortedObjectStatus(vtkExodusIIReader::ELEM_BLOCK, blkIndices[i])) { return 0; } } return 1; } //------------------------------------------------------------------------------ int vtkExodusIIReaderPrivate::GetMaterialStatus(const vtkStdString& name) { for (unsigned int i = 0; i < this->MaterialInfo.size(); i++) { if (this->MaterialInfo[i].Name == name) { return this->GetMaterialStatus(i); } } return -1; } //------------------------------------------------------------------------------ void vtkExodusIIReaderPrivate::SetMaterialStatus(int idx, int on) { // update the block status for all the blocks in this material std::vector blkIndices = this->MaterialInfo[idx].BlockIndices; for (unsigned int i = 0; i < blkIndices.size(); i++) { this->SetUnsortedObjectStatus(vtkExodusIIReader::ELEM_BLOCK, blkIndices[i], on); } } //------------------------------------------------------------------------------ void vtkExodusIIReaderPrivate::SetMaterialStatus(const vtkStdString& name, int flag) { for (unsigned int idx = 0; idx < this->MaterialInfo.size(); ++idx) { if (name == this->MaterialInfo[idx].Name) { this->SetMaterialStatus(idx, flag); return; } } } //------------------------------------------------------------------------------ int vtkExodusIIReaderPrivate::GetNumberOfAssemblies() { return static_cast(this->AssemblyInfo.size()); } //------------------------------------------------------------------------------ const char* vtkExodusIIReaderPrivate::GetAssemblyName(int idx) { return this->AssemblyInfo[idx].Name.c_str(); } //------------------------------------------------------------------------------ int vtkExodusIIReaderPrivate::GetAssemblyStatus(int idx) { std::vector blkIndices = this->AssemblyInfo[idx].BlockIndices; for (unsigned int i = 0; i < blkIndices.size(); i++) { if (!this->GetUnsortedObjectStatus(vtkExodusIIReader::ELEM_BLOCK, blkIndices[i])) { return 0; } } return 1; } //------------------------------------------------------------------------------ int vtkExodusIIReaderPrivate::GetAssemblyStatus(const vtkStdString& name) { for (unsigned int i = 0; i < this->AssemblyInfo.size(); i++) { if (this->AssemblyInfo[i].Name == name) { return this->GetAssemblyStatus(i); } } return -1; } //------------------------------------------------------------------------------ void vtkExodusIIReaderPrivate::SetAssemblyStatus(int idx, int on) { std::vector blkIndices = this->AssemblyInfo[idx].BlockIndices; // update the block status for all the blocks in this material for (unsigned int i = 0; i < blkIndices.size(); i++) { this->SetUnsortedObjectStatus(vtkExodusIIReader::ELEM_BLOCK, blkIndices[i], on); } } //------------------------------------------------------------------------------ void vtkExodusIIReaderPrivate::SetAssemblyStatus(const vtkStdString& name, int flag) { for (unsigned int idx = 0; idx < this->AssemblyInfo.size(); ++idx) { if (name == this->AssemblyInfo[idx].Name) { this->SetAssemblyStatus(idx, flag); return; } } } //------------------------------------------------------------------------------ // Normally, this would be below with all the other vtkExodusIIReader member definitions, // but the PrintSelf test script is really lame. void vtkExodusIIReader::PrintSelf(ostream& os, vtkIndent indent) { this->Superclass::PrintSelf(os, indent); os << indent << "FileName: " << (this->FileName ? this->FileName : "(null)") << "\n"; os << indent << "XMLFileName: " << (this->XMLFileName ? this->XMLFileName : "(null)") << "\n"; os << indent << "DisplayType: " << this->DisplayType << "\n"; os << indent << "TimeStep: " << this->TimeStep << "\n"; os << indent << "TimeStepRange: [" << this->TimeStepRange[0] << ", " << this->TimeStepRange[1] << "]\n"; os << indent << "ModeShapesRange: [ " << this->GetModeShapesRange()[0] << ", " << this->GetModeShapesRange()[1] << "]\n"; os << indent << "IgnoreFileTime: " << this->GetIgnoreFileTime() << "\n"; os << indent << "SILUpdateStamp: " << this->SILUpdateStamp << "\n"; os << indent << "UseLegacyBlockNames: " << this->UseLegacyBlockNames << "\n"; if (this->Metadata) { os << indent << "Metadata:\n"; this->Metadata->PrintSelf(os, indent.GetNextIndent()); } else { os << indent << "Metadata: (null)\n"; } } void vtkExodusIIReaderPrivate::PrintSelf(ostream& os, vtkIndent indent) { // this->Superclass::Print Self( os, indent ); os << indent << "Exoid: " << this->Exoid << "\n"; os << indent << "AppWordSize: " << this->AppWordSize << "\n"; os << indent << "DiskWordSize: " << this->DiskWordSize << "\n"; os << indent << "ExodusVersion: " << this->ExodusVersion << "\n"; os << indent << "ModelParameters:\n"; vtkIndent inden2 = indent.GetNextIndent(); os << inden2 << "Title: " << this->ModelParameters.title << "\n"; os << inden2 << "Dimension: " << this->ModelParameters.num_dim << "\n"; os << inden2 << "Nodes: " << this->ModelParameters.num_nodes << "\n"; os << inden2 << "Edges: " << this->ModelParameters.num_edge << "\n"; os << inden2 << "Faces: " << this->ModelParameters.num_face << "\n"; os << inden2 << "Elements: " << this->ModelParameters.num_elem << "\n"; os << inden2 << "Edge Blocks: " << this->ModelParameters.num_edge_blk << "\n"; os << inden2 << "Face Blocks: " << this->ModelParameters.num_face_blk << "\n"; os << inden2 << "Element Blocks: " << this->ModelParameters.num_elem_blk << "\n"; os << inden2 << "Node Sets: " << this->ModelParameters.num_node_sets << "\n"; os << inden2 << "Edge Sets: " << this->ModelParameters.num_edge_sets << "\n"; os << inden2 << "Face Sets: " << this->ModelParameters.num_face_sets << "\n"; os << inden2 << "Side Sets: " << this->ModelParameters.num_side_sets << "\n"; os << inden2 << "Element Sets: " << this->ModelParameters.num_elem_sets << "\n"; os << inden2 << "Node Maps: " << this->ModelParameters.num_node_maps << "\n"; os << inden2 << "Edge Maps: " << this->ModelParameters.num_edge_maps << "\n"; os << inden2 << "Face Maps: " << this->ModelParameters.num_face_maps << "\n"; os << inden2 << "Element Maps: " << this->ModelParameters.num_elem_maps << "\n"; os << indent << "Time steps (" << this->Times.size() << "):"; int i; for (i = 0; i < (int)this->Times.size(); ++i) { os << " " << this->Times[i]; } os << "\n"; os << indent << "HasModeShapes: " << this->HasModeShapes << "\n"; os << indent << "ModeShapeTime: " << this->ModeShapeTime << "\n"; os << indent << "AnimateModeShapes: " << this->AnimateModeShapes << "\n"; // Print nodal variables if (!this->ArrayInfo[vtkExodusIIReader::NODAL].empty()) { os << indent << "Nodal Arrays:\n"; std::vector::iterator ai; for (ai = this->ArrayInfo[vtkExodusIIReader::NODAL].begin(); ai != this->ArrayInfo[vtkExodusIIReader::NODAL].end(); ++ai) { printArray(os, indent, vtkExodusIIReader::NODAL, *ai); } } // Print blocks os << indent << "Blocks:\n"; std::map>::iterator bti; for (bti = this->BlockInfo.begin(); bti != this->BlockInfo.end(); ++bti) { std::vector::iterator bi; for (bi = bti->second.begin(); bi != bti->second.end(); ++bi) { printBlock(os, indent.GetNextIndent(), bti->first, *bi); } if (!this->ArrayInfo[bti->first].empty()) { os << indent << " Results variables:\n"; std::vector::iterator ai; for (ai = this->ArrayInfo[bti->first].begin(); ai != this->ArrayInfo[bti->first].end(); ++ai) { printArray(os, indent.GetNextIndent(), bti->first, *ai); } } } // Print sets os << indent << "Sets:\n"; std::map>::iterator sti; for (sti = this->SetInfo.begin(); sti != this->SetInfo.end(); ++sti) { std::vector::iterator si; for (si = sti->second.begin(); si != sti->second.end(); ++si) { printSet(os, indent.GetNextIndent(), sti->first, *si); } if (!this->ArrayInfo[sti->first].empty()) { os << indent << " Results variables:\n"; std::vector::iterator ai; for (ai = this->ArrayInfo[sti->first].begin(); ai != this->ArrayInfo[sti->first].end(); ++ai) { printArray(os, indent.GetNextIndent(), sti->first, *ai); } } } // Print maps os << indent << "Maps:\n"; std::map>::iterator mti; for (mti = this->MapInfo.begin(); mti != this->MapInfo.end(); ++mti) { std::vector::iterator mi; for (mi = mti->second.begin(); mi != mti->second.end(); ++mi) { printMap(os, indent.GetNextIndent(), mti->first, *mi); } } os << indent << "Array Cache:\n"; this->Cache->PrintSelf(os, inden2); os << indent << "SqueezePoints: " << this->SqueezePoints << "\n"; os << indent << "ApplyDisplacements: " << this->ApplyDisplacements << "\n"; os << indent << "DisplacementMagnitude: " << this->DisplacementMagnitude << "\n"; os << indent << "GenerateObjectIdArray: " << this->GenerateObjectIdArray << "\n"; os << indent << "GenerateFileIdArray: " << this->GenerateFileIdArray << "\n"; os << indent << "FileId: " << this->FileId << "\n"; } int vtkExodusIIReaderPrivate::OpenFile(const char* filename) { if (!filename || !strlen(filename)) { vtkErrorMacro("Exodus filename pointer was nullptr or pointed to an empty string."); return 0; } if (this->Exoid >= 0) { this->CloseFile(); } this->Exoid = ex_open(filename, EX_READ, &this->AppWordSize, &this->DiskWordSize, &this->ExodusVersion); if (this->Exoid <= 0) { vtkErrorMacro("Unable to open \"" << filename << "\" for reading"); return 0; } #ifdef VTK_USE_64BIT_IDS // Set the exodus API to always return integer types as 64-bit // without this call, large exodus files are not supported (which // is ok in 32 bit ids mode since VTK's ids can't fit the data). ex_set_int64_status(this->Exoid, EX_ALL_INT64_API); #endif // figure out the longest string name we have and then set that to be the // maximum length for the variable names. This is called every time that the reader // is updated so we don't have to worry about setting the global max_name_length variable. // this is because in our current version of the ExodusII libraries the exo Id isn't used // in the ex_set_max_name_length() function. ex_set_max_name_length(this->Exoid, this->Parent->GetMaxNameLength()); vtkIdType numNodesInFile; char dummyChar; float dummyFloat; ex_inquire(this->Exoid, EX_INQ_NODES, &numNodesInFile, &dummyFloat, &dummyChar); return 1; } int vtkExodusIIReaderPrivate::CloseFile() { if (this->Exoid >= 0) { VTK_EXO_FUNC(ex_close(this->Exoid), "Could not close an open file (" << this->Exoid << ")"); this->Exoid = -1; } return 0; } int vtkExodusIIReaderPrivate::UpdateTimeInformation() { // BUG #15632: For files with spatial partitions, vtkPExodusIIReader uses vtkExodusIIReader // to read each of the files. Since time information between those files doesn't change and // it can be quite time consuming to collect the time information, vtkPExodusIIReader forcibly // passes time information from the first reader to all others. SkipUpdateTimeInformation helps us // get that going without significant changes to the reader. if (this->SkipUpdateTimeInformation) { return 0; } int exoid = this->Exoid; vtkIdType itmp[5]; int num_timesteps; int i; VTK_EXO_FUNC( ex_inquire(exoid, EX_INQ_TIME, itmp, nullptr, nullptr), "Inquire for EX_INQ_TIME failed"); num_timesteps = itmp[0]; this->Times.clear(); if (num_timesteps > 0) { this->Times.resize(num_timesteps); int exo_err = ex_get_all_times(this->Exoid, &this->Times[0]); if (exo_err < 0 || this->IgnoreFileTime) { for (i = 0; i < num_timesteps; ++i) { this->Times[i] = i; } // vtkWarningMacro("Could not retrieve time values, assuming times equal to timesteps"); } } return 0; } //------------------------------------------------------------------------------ void vtkExodusIIReaderPrivate::BuildSIL() { // Initialize the SIL, dump all previous information. this->SIL->Initialize(); if (this->Parser) { // The parser has built the SIL for us, // use that. this->SIL->ShallowCopy(this->Parser->GetSIL()); return; } // Else build a minimal SIL with only the blocks. vtkSmartPointer childEdge = vtkSmartPointer::New(); childEdge->InsertNextValue(0); vtkSmartPointer crossEdge = vtkSmartPointer::New(); crossEdge->InsertNextValue(0); // CrossEdge is an edge linking hierarchies. vtkUnsignedCharArray* crossEdgesArray = vtkUnsignedCharArray::New(); crossEdgesArray->SetName("CrossEdges"); this->SIL->GetEdgeData()->AddArray(crossEdgesArray); crossEdgesArray->Delete(); std::deque names; int cc; // Now build the hierarchy. vtkIdType rootId = this->SIL->AddVertex(); names.emplace_back("SIL"); // Add the ELEM_BLOCK subtree. vtkIdType blocksRoot = this->SIL->AddChild(rootId, childEdge); names.emplace_back("Blocks"); // Add the assembly subtree this->SIL->AddChild(rootId, childEdge); names.emplace_back("Assemblies"); // Add the materials subtree this->SIL->AddChild(rootId, childEdge); names.emplace_back("Materials"); // This is the map of block names to node ids. std::map blockids; int numBlocks = this->GetNumberOfObjectsOfType(vtkExodusIIReader::ELEM_BLOCK); for (cc = 0; cc < numBlocks; cc++) { vtkIdType child = this->SIL->AddChild(blocksRoot, childEdge); std::string block_name = this->GetObjectName(vtkExodusIIReader::ELEM_BLOCK, cc); names.push_back(block_name); blockids[block_name] = child; } // This array is used to assign names to nodes. vtkStringArray* namesArray = vtkStringArray::New(); namesArray->SetName("Names"); namesArray->SetNumberOfTuples(this->SIL->GetNumberOfVertices()); this->SIL->GetVertexData()->AddArray(namesArray); namesArray->Delete(); std::deque::iterator iter; for (cc = 0, iter = names.begin(); iter != names.end(); ++iter, ++cc) { namesArray->SetValue(cc, (*iter).c_str()); } } //------------------------------------------------------------------------------ int vtkExodusIIReaderPrivate::RequestInformation() { int exoid = this->Exoid; // int itmp[5]; vtkIdType* ids; vtkIdType nids; int obj; int i, j; int num_timesteps; char** obj_names; char** obj_typenames = nullptr; char** var_names = nullptr; int have_var_names; int num_vars = 0; /* number of variables per object */ char tmpName[256]; tmpName[255] = '\0'; int maxNameLength = this->Parent->GetMaxNameLength(); this->InformationTimeStamp .Modified(); // Update MTime so that it will be newer than parent's FileNameMTime VTK_EXO_FUNC( ex_get_init_ext(exoid, &this->ModelParameters), "Unable to read database parameters."); VTK_EXO_FUNC(this->UpdateTimeInformation(), ""); // VTK_EXO_FUNC( ex_inquire( exoid, EX_INQ_TIME, itmp, 0, 0 ), "Inquire for EX_INQ_TIME // failed" ); num_timesteps = itmp[0]; num_timesteps = static_cast(this->Times.size()); /* this->Times.clear(); if ( num_timesteps > 0 ) { this->Times.resize( num_timesteps ); VTK_EXO_FUNC( ex_get_all_times( this->Exoid, &this->Times[0] ), "Could not retrieve time values." ); } */ for (i = 0; i < num_obj_types; ++i) { if (OBJTYPE_IS_NODAL(i)) { continue; } vtkIdType blockEntryFileOffset = 1; vtkIdType setEntryFileOffset = 1; std::map sortedObjects; int* truth_tab = nullptr; have_var_names = 0; VTK_EXO_FUNC(ex_inquire(exoid, obj_sizes[i], &nids, nullptr, nullptr), "Object ID list size could not be determined."); if (nids) { ids = (vtkIdType*)malloc(nids * sizeof(vtkIdType)); obj_names = (char**)malloc(nids * sizeof(char*)); for (obj = 0; obj < nids; ++obj) { obj_names[obj] = (char*)malloc((maxNameLength + 1) * sizeof(char)); } if (OBJTYPE_IS_BLOCK(i)) { obj_typenames = (char**)malloc(nids * sizeof(char*)); for (obj = 0; obj < nids; ++obj) { obj_typenames[obj] = (char*)malloc((maxNameLength + 1) * sizeof(char)); obj_typenames[obj][0] = '\0'; } } } else { ids = nullptr; obj_names = nullptr; obj_typenames = nullptr; } if (nids == 0 && !OBJTYPE_IS_MAP(i)) continue; if (nids) { VTK_EXO_FUNC(ex_get_ids(exoid, static_cast(obj_types[i]), ids), "Could not read object ids for i=" << i << " and otyp=" << obj_types[i] << "."); VTK_EXO_FUNC(ex_get_names(exoid, static_cast(obj_types[i]), obj_names), "Could not read object names."); } BlockInfoType binfo; SetInfoType sinfo; MapInfoType minfo; if (OBJTYPE_IS_BLOCK(i)) { this->BlockInfo[obj_types[i]].clear(); this->BlockInfo[obj_types[i]].reserve(nids); } else if (OBJTYPE_IS_SET(i)) { this->SetInfo[obj_types[i]].clear(); this->SetInfo[obj_types[i]].reserve(nids); } else { this->MapInfo[obj_types[i]].clear(); this->MapInfo[obj_types[i]].reserve(nids); } if ((OBJTYPE_IS_BLOCK(i)) || (OBJTYPE_IS_SET(i))) { VTK_EXO_FUNC( ex_get_var_param(exoid, obj_typestr[i], &num_vars), "Could not read number of variables."); if (num_vars && num_timesteps > 0) { truth_tab = (int*)malloc(num_vars * nids * sizeof(int)); VTK_EXO_FUNC(ex_get_var_tab(exoid, obj_typestr[i], nids, num_vars, truth_tab), "Could not read truth table."); var_names = (char**)malloc(num_vars * sizeof(char*)); for (j = 0; j < num_vars; ++j) var_names[j] = (char*)malloc((maxNameLength + 1) * sizeof(char)); VTK_EXO_FUNC(ex_get_var_names(exoid, obj_typestr[i], num_vars, var_names), "Could not read variable names."); this->RemoveBeginningAndTrailingSpaces(num_vars, var_names, maxNameLength); have_var_names = 1; } } if (!have_var_names) var_names = nullptr; for (obj = 0; obj < nids; ++obj) { if (OBJTYPE_IS_BLOCK(i)) { binfo.Name = obj_names[obj]; binfo.Id = ids[obj]; binfo.CachedConnectivity = nullptr; binfo.NextSqueezePoint = 0; if (obj_types[i] == vtkExodusIIReader::ELEM_BLOCK) { VTK_EXO_FUNC(ex_get_block(exoid, static_cast(obj_types[i]), ids[obj], obj_typenames[obj], &binfo.Size, &binfo.BdsPerEntry[0], &binfo.BdsPerEntry[1], &binfo.BdsPerEntry[2], &binfo.AttributesPerEntry), "Could not read block params."); binfo.Status = 1; // load element blocks by default binfo.TypeName = obj_typenames[obj]; } else { VTK_EXO_FUNC(ex_get_block(exoid, static_cast(obj_types[i]), ids[obj], obj_typenames[obj], &binfo.Size, &binfo.BdsPerEntry[0], &binfo.BdsPerEntry[1], &binfo.BdsPerEntry[2], &binfo.AttributesPerEntry), "Could not read block params."); binfo.Status = 0; // don't load edge/face blocks by default binfo.TypeName = obj_typenames[obj]; binfo.BdsPerEntry[1] = binfo.BdsPerEntry[2] = 0; } this->GetInitialObjectStatus(obj_types[i], &binfo); // num_entries = binfo.Size; binfo.FileOffset = blockEntryFileOffset; blockEntryFileOffset += binfo.Size; if (binfo.Name.length() == 0) { if (this->Parent->GetUseLegacyBlockNames()) { snprintf(tmpName, sizeof(tmpName), #ifdef VTK_USE_64BIT_IDS "Unnamed block ID: %lld Type: %s", #else "Unnamed block ID: %d Type: %s", #endif ids[obj], binfo.TypeName.length() ? binfo.TypeName.c_str() : "nullptr"); } else { #ifdef VTK_USE_64BIT_IDS snprintf(tmpName, sizeof(tmpName), "Unnamed block ID: %lld", ids[obj]); #else snprintf(tmpName, sizeof(tmpName), "Unnamed block ID: %d", ids[obj]); #endif } binfo.Name = tmpName; } binfo.OriginalName = binfo.Name; this->DetermineVtkCellType(binfo); if (binfo.AttributesPerEntry) { char** attr_names; attr_names = (char**)malloc(binfo.AttributesPerEntry * sizeof(char*)); for (j = 0; j < binfo.AttributesPerEntry; ++j) attr_names[j] = (char*)malloc((maxNameLength + 1) * sizeof(char)); VTK_EXO_FUNC(ex_get_attr_names( exoid, static_cast(obj_types[i]), ids[obj], attr_names), "Could not read attributes names."); for (j = 0; j < binfo.AttributesPerEntry; ++j) { binfo.AttributeNames.emplace_back(attr_names[j]); binfo.AttributeStatus.push_back(0); // don't load attributes by default } for (j = 0; j < binfo.AttributesPerEntry; ++j) free(attr_names[j]); free(attr_names); } // Check to see if there is metadata that defines what part, material, // and assembly(ies) this block belongs to. if (this->Parser && this->Parser->HasInformationAboutBlock(binfo.Id)) { // Update the block name using the XML. binfo.Name = this->Parser->GetBlockName(binfo.Id); // int blockIdx = static_cast( this->BlockInfo[obj_types[i]].size() ); //// Add this block to our parts, materials, and assemblies collections // unsigned int k; // int found = 0; //// Look to see if this part has already been created // for (k=0;kPartInfo.size();k++) // { // if (this->PartInfo[k].Name==partName) // { // //binfo.PartId = k; // this->PartInfo[k].BlockIndices.push_back(blockIdx); // found=1; // } // } // if (!found) // { // PartInfoType pinfo; // pinfo.Name = partName; // pinfo.Id = static_cast( this->PartInfo.size() ); // //binfo.PartId = k; // pinfo.BlockIndices.push_back(blockIdx); // this->PartInfo.push_back(pinfo); // } // // found=0; // for (k=0;kMaterialInfo.size();k++) // { // if (this->MaterialInfo[k].Name==materialName) // { // //binfo.MaterialId = k; // this->MaterialInfo[k].BlockIndices.push_back(blockIdx); // found=1; // } // } // if (!found) // { // MaterialInfoType matinfo; // matinfo.Name = materialName; // matinfo.Id = static_cast( this->MaterialInfo.size() ); // //binfo.MaterialId = k; // matinfo.BlockIndices.push_back(blockIdx); // this->MaterialInfo.push_back(matinfo); // } // // for (k=0;kAssemblyInfo.size();n++) // { // if (this->AssemblyInfo[n].Name==assemblyName) { // //binfo.AssemblyIds.push_back(j); // this->AssemblyInfo[n].BlockIndices.push_back(blockIdx); // found=1; // } // } // if (!found) // { // AssemblyInfoType ainfo; // ainfo.Name = assemblyName; // ainfo.Id = static_cast( this->AssemblyInfo.size() ); // //binfo.AssemblyIds.push_back(k); // ainfo.BlockIndices.push_back(blockIdx); // this->AssemblyInfo.push_back(ainfo); // } // } } sortedObjects[binfo.Id] = static_cast(this->BlockInfo[obj_types[i]].size()); this->BlockInfo[obj_types[i]].push_back(binfo); } else if (OBJTYPE_IS_SET(i)) { sinfo.Name = obj_names[obj]; sinfo.Status = 0; sinfo.Id = ids[obj]; sinfo.CachedConnectivity = nullptr; sinfo.NextSqueezePoint = 0; VTK_EXO_FUNC(ex_get_set_param(exoid, static_cast(obj_types[i]), ids[obj], &sinfo.Size, &sinfo.DistFact), "Could not read set parameters."); // num_entries = sinfo.Size; sinfo.FileOffset = setEntryFileOffset; setEntryFileOffset += sinfo.Size; this->GetInitialObjectStatus(obj_types[i], &sinfo); if (sinfo.Name.length() == 0) { snprintf(tmpName, sizeof(tmpName), #ifdef VTK_USE_64BIT_IDS "Unnamed set ID: %lld", #else "Unnamed set ID: %d", #endif ids[obj]); sinfo.Name = tmpName; } sortedObjects[sinfo.Id] = (int)this->SetInfo[obj_types[i]].size(); this->SetInfo[obj_types[i]].push_back(sinfo); } else { /* object is map */ minfo.Id = ids[obj]; minfo.Status = obj == 0 ? 1 : 0; // only load the first map by default switch (obj_types[i]) { case vtkExodusIIReader::NODE_MAP: minfo.Size = this->ModelParameters.num_nodes; break; case vtkExodusIIReader::EDGE_MAP: minfo.Size = this->ModelParameters.num_edge; break; case vtkExodusIIReader::FACE_MAP: minfo.Size = this->ModelParameters.num_face; break; case vtkExodusIIReader::ELEM_MAP: minfo.Size = this->ModelParameters.num_elem; break; default: minfo.Size = 0; } minfo.Name = obj_names[obj]; if (minfo.Name.length() == 0) { snprintf(tmpName, sizeof(tmpName), #ifdef VTK_USE_64BIT_IDS "Unnamed map ID: %lld", #else "Unnamed map ID: %d", #endif ids[obj]); minfo.Name = tmpName; } sortedObjects[minfo.Id] = (int)this->MapInfo[obj_types[i]].size(); this->MapInfo[obj_types[i]].push_back(minfo); } } // end of loop over all object ids // Now that we have all objects of that type in the sortedObjects, we can // iterate over it to fill in the SortedObjectIndices (the map is a *sorted* // associative container) std::map::iterator soit; for (soit = sortedObjects.begin(); soit != sortedObjects.end(); ++soit) { this->SortedObjectIndices[obj_types[i]].push_back(soit->second); } if (((OBJTYPE_IS_BLOCK(i)) || (OBJTYPE_IS_SET(i))) && num_vars && num_timesteps > 0) { this->ArrayInfo[obj_types[i]].clear(); // Fill in ArrayInfo entries, combining array names into vectors/tensors where appropriate: this->GlomArrayNames(obj_types[i], nids, num_vars, var_names, truth_tab); } if (var_names) { for (j = 0; j < num_vars; ++j) free(var_names[j]); free(var_names); } if (truth_tab) free(truth_tab); if (nids) { free(ids); for (obj = 0; obj < nids; ++obj) free(obj_names[obj]); free(obj_names); if (OBJTYPE_IS_BLOCK(i)) { for (obj = 0; obj < nids; ++obj) free(obj_typenames[obj]); free(obj_typenames); } } } // end of loop over all object types // this->ComputeGridOffsets(); // Now read information for nodal arrays VTK_EXO_FUNC( ex_get_var_param(exoid, "n", &num_vars), "Unable to read number of nodal variables."); if (num_vars > 0) { var_names = (char**)malloc(num_vars * sizeof(char*)); for (j = 0; j < num_vars; ++j) { var_names[j] = (char*)malloc((maxNameLength + 1) * sizeof(char)); } VTK_EXO_FUNC( ex_get_var_names(exoid, "n", num_vars, var_names), "Could not read nodal variable names."); this->RemoveBeginningAndTrailingSpaces(num_vars, var_names, maxNameLength); nids = 1; std::vector dummy_truth; dummy_truth.reserve(num_vars); for (j = 0; j < num_vars; ++j) { dummy_truth.push_back(1); } this->GlomArrayNames(vtkExodusIIReader::NODAL, nids, num_vars, var_names, &dummy_truth[0]); for (j = 0; j < num_vars; ++j) { free(var_names[j]); } free(var_names); var_names = nullptr; } // Now read information for global variables VTK_EXO_FUNC( ex_get_var_param(exoid, "g", &num_vars), "Unable to read number of global variables."); if (num_vars > 0) { var_names = (char**)malloc(num_vars * sizeof(char*)); for (j = 0; j < num_vars; ++j) { var_names[j] = (char*)malloc((maxNameLength + 1) * sizeof(char)); } VTK_EXO_FUNC( ex_get_var_names(exoid, "g", num_vars, var_names), "Could not read global variable names."); this->RemoveBeginningAndTrailingSpaces(num_vars, var_names, maxNameLength); nids = 1; std::vector dummy_truth; dummy_truth.reserve(num_vars); for (j = 0; j < num_vars; ++j) { dummy_truth.push_back(1); } this->GlomArrayNames(vtkExodusIIReader::GLOBAL, nids, num_vars, var_names, &dummy_truth[0]); for (j = 0; j < num_vars; ++j) { free(var_names[j]); } free(var_names); var_names = nullptr; } return 0; } int vtkExodusIIReaderPrivate::RequestData(vtkIdType timeStep, vtkMultiBlockDataSet* output) { // The work done here depends on several conditions: // - Has connectivity changed (i.e., has block/set status changed)? // - If so, AND if point "squeeze" turned on, must reload points and re-squeeze. // - If so, must re-assemble all arrays // - Must recreate block/set id array. // - Has requested time changed? // - If so, AND if "deflect mesh" turned on, must load new deflections and compute new points. // - If so, must assemble all time-varying arrays for new time. // - Has array status changed? // - If so, must delete old and/or load new arrays. // Obviously, many of these tasks overlap. For instance, it would be // foolish to re-assemble all the arrays when the connectivity has // changed and then toss them out in order to load arrays for a // different time step. // Caching strategy: use GLOBAL "object type" for assembled arrays. // If connectivity hasn't changed, then these arrays can be used; // otherwise, "raw" arrays must be used. // Pro: // - single cache == easier bookkeeping (two caches would require us to decide how to equitably // split avail mem between them) // - many different operations are accelerated: // - just changing which variables are loaded // - changing which blocks are in output (doesn't require disk access if cache hit) // - possible extension to single-node/cell over time // Con: // - higher memory consumption for caching the same set of arrays (or, holding cache size fixed: // fewer arrays fit) if (!output) { vtkErrorMacro("You must specify an output mesh"); } // Iterate over all block and set types, creating a // multiblock dataset to hold objects of each type. int conntypidx; output->SetNumberOfBlocks(num_conn_types); for (conntypidx = 0; conntypidx < num_conn_types; ++conntypidx) { int otypidx = conn_obj_idx_cvt[conntypidx]; int otyp = obj_types[otypidx]; // Loop over all blocks/sets of this type int numObj = this->GetNumberOfObjectsOfType(otyp); vtkMultiBlockDataSet* mbds; mbds = vtkMultiBlockDataSet::New(); mbds->SetNumberOfBlocks(numObj); output->SetBlock(conntypidx, mbds); output->GetMetaData(conntypidx)->Set(vtkCompositeDataSet::NAME(), conn_types_names[conntypidx]); mbds->FastDelete(); // cout << "++ Block: " << mbds << " ObjectType: " << otyp << "\n"; int obj; int sortIdx; for (sortIdx = 0; sortIdx < numObj; ++sortIdx) { const char* object_name = this->GetObjectName(otyp, sortIdx); // Preserve the "sorted" order when concatenating obj = this->SortedObjectIndices[otyp][sortIdx]; BlockSetInfoType* bsinfop = static_cast(this->GetObjectInfo(otypidx, obj)); // cout << ( bsinfop->Status ? "++" : "--" ) << " ObjectId: " << bsinfop->Id; // vtkLogF(TRACE, "%s: name=%s, idx=%d, type=%d status=%d", // vtkLogIdentifier(this), object_name, sortIdx, otypidx, bsinfop->Status); if (!bsinfop->Status) { mbds->SetBlock(sortIdx, nullptr); if (object_name) { mbds->GetMetaData(sortIdx)->Set(vtkCompositeDataSet::NAME(), object_name); } continue; } vtkUnstructuredGrid* ug = vtkUnstructuredGrid::New(); mbds->SetBlock(sortIdx, ug); if (object_name) { mbds->GetMetaData(sortIdx)->Set(vtkCompositeDataSet::NAME(), object_name); } ug->FastDelete(); // cout << " Grid: " << ug << "\n"; try { // Connectivity first. Either from the cache in bsinfop or read from disk. // Connectivity isn't allowed to change with time. this->AssembleOutputConnectivity(timeStep, otyp, obj, conntypidx, bsinfop, ug); // Now prepare points. // These shouldn't change unless the connectivity has changed. this->AssembleOutputPoints(timeStep, bsinfop, ug); // Then, add the desired arrays from cache (or disk) // Point and cell arrays are handled differently because they // have different problems to solve. // Point arrays must use the PointMap index to subset values. // Cell arrays may be used as-is. this->AssembleOutputPointArrays(timeStep, bsinfop, ug); this->AssembleOutputCellArrays(timeStep, otyp, obj, bsinfop, ug); // Some arrays may be procedurally generated (e.g., the ObjectId // array, global element and node number arrays). This constructs // them as required. this->AssembleOutputProceduralArrays(timeStep, otyp, obj, ug); // QA and informational records in the ExodusII file are appended // to each and every output unstructured grid. this->AssembleOutputGlobalArrays(timeStep, otyp, obj, bsinfop, ug); // Maps (as distinct from the global element and node arrays above) // are per-cell or per-node integers. As with point arrays, the // PointMap is used to subset node maps. Cell arrays are stored in // ExodusII files for all elements (across all blocks of a given type) // and thus must be subset for the unstructured grid of interest. this->AssembleOutputPointMaps(timeStep, bsinfop, ug); this->AssembleOutputCellMaps(timeStep, otyp, obj, bsinfop, ug); } catch (const std::runtime_error&) { vtkErrorMacro("Error reading block '" << (object_name ? object_name : "(no-name)") << "', id=" << bsinfop->Id << ". Skipping."); ug->Initialize(); } } } this->CloseFile(); return 0; } int vtkExodusIIReaderPrivate::SetUpEmptyGrid(vtkMultiBlockDataSet* output) { if (!output) { vtkErrorMacro("You must specify an output mesh"); } // Iterate over all block and set types, creating a // multiblock dataset to hold objects of each type. int conntypidx; int nbl = 0; output->SetNumberOfBlocks(num_conn_types); for (conntypidx = 0; conntypidx < num_conn_types; ++conntypidx) { int otypidx = conn_obj_idx_cvt[conntypidx]; int otyp = obj_types[otypidx]; // Loop over all blocks/sets of this type int numObj = this->GetNumberOfObjectsOfType(otyp); vtkMultiBlockDataSet* mbds; mbds = vtkMultiBlockDataSet::New(); mbds->SetNumberOfBlocks(numObj); output->SetBlock(conntypidx, mbds); output->GetMetaData(conntypidx)->Set(vtkCompositeDataSet::NAME(), conn_types_names[conntypidx]); mbds->FastDelete(); int obj; int sortIdx; for (sortIdx = 0; sortIdx < numObj; ++sortIdx) { // Preserve the "sorted" order when concatenating obj = this->SortedObjectIndices[otyp][sortIdx]; BlockSetInfoType* bsinfop = static_cast(this->GetObjectInfo(otypidx, obj)); // cout << ( bsinfop->Status ? "++" : "--" ) << " ObjectId: " << bsinfop->Id; if (!bsinfop->Status) { // cout << "\n"; mbds->SetBlock(sortIdx, nullptr); continue; } vtkUnstructuredGrid* ug = vtkUnstructuredGrid::New(); mbds->SetBlock(sortIdx, ug); ug->FastDelete(); ++nbl; } } #if 0 int idx; vtkUnstructuredGrid* leaf; // Set up an empty unstructured grid leaf->Allocate(0); // Create new points vtkPoints* newPoints = vtkPoints::New(); newPoints->SetNumberOfPoints( 0 ); leaf->SetPoints( newPoints ); newPoints->Delete(); newPoints = nullptr; // Create point and cell arrays int typ; for ( typ = 0; typ < numObjResultTypes; ++typ ) { int otyp = objResultTypes[typ]; int nObjArr = this->GetNumberOfObjectArrays( otyp ); for ( idx = 0; idx < nObjArr; ++idx ) { vtkDoubleArray* da = vtkDoubleArray::New(); da->SetName( this->GetObjectArrayName( otyp, idx ) ); da->SetNumberOfComponents( this->GetNumberOfObjectArrayComponents( otyp, idx ) ); if ( otyp == vtkExodusIIReader::NODAL ) { leaf->GetPointData()->AddArray( da ); } else { leaf->GetCellData()->AddArray( da ); } da->FastDelete(); } } for ( typ = 0; typ < numObjAttribTypes; ++typ ) { int otyp = objAttribTypes[typ]; int nObj = this->GetNumberOfObjects( otyp ); for ( idx = 0; idx < nObj; ++ idx ) { // Attributes are defined per block, not per block type. int nObjAtt = this->GetNumberOfObjectAttributes( otyp, idx ); for ( int aidx = 0; aidx < nObjAtt; ++ aidx ) { vtkDoubleArray* da = vtkDoubleArray::New(); da->SetName( this->GetObjectAttributeName( otyp, idx, aidx ) ); da->SetNumberOfComponents( 1 ); // All attributes are cell data leaf->GetCellData()->AddArray( da ); da->FastDelete(); } } } if ( this->GetGenerateObjectIdCellArray() ) { vtkIntArray* ia = vtkIntArray::New(); ia->SetName( this->GetObjectIdArrayName() ); ia->SetNumberOfComponents( 1 ); leaf->GetCellData()->AddArray( ia ); ia->FastDelete(); } if ( this->GetGenerateGlobalNodeIdArray() ) { vtkIntArray* ia = vtkIntArray::New(); ia->SetName( this->GetGlobalNodeIdArrayName() ); ia->SetNumberOfComponents( 1 ); leaf->GetPointData()->AddArray( ia ); ia->FastDelete(); } if ( this->GetGenerateGlobalElementIdArray() ) { vtkIntArray* ia = vtkIntArray::New(); ia->SetName( this->GetGlobalElementIdArrayName() ); ia->SetNumberOfComponents( 1 ); leaf->GetCellData()->AddArray( ia ); ia->FastDelete(); } #endif // 0 return 1; } void vtkExodusIIReaderPrivate::Reset() { vtkLogF(TRACE, "vtkExodusIIReaderPrivate(%p)::Reset", this); this->CloseFile(); this->ResetCache(); // must come before BlockInfo and SetInfo are cleared. this->BlockInfo.clear(); this->SetInfo.clear(); this->MapInfo.clear(); this->PartInfo.clear(); this->MaterialInfo.clear(); this->AssemblyInfo.clear(); this->SortedObjectIndices.clear(); this->ArrayInfo.clear(); this->ExodusVersion = -1.; this->Times.clear(); memset((void*)&this->ModelParameters, 0, sizeof(this->ModelParameters)); // Don't clear file id since it's not part of meta-data that's read from the // file, it's set externally (by vtkPExodusIIReader). // Refer to BUG #7633. // this->FileId = 0; this->Modified(); } void vtkExodusIIReaderPrivate::ResetSettings() { this->GenerateGlobalElementIdArray = 0; this->GenerateGlobalNodeIdArray = 0; this->GenerateImplicitElementIdArray = 0; this->GenerateImplicitNodeIdArray = 0; this->GenerateGlobalIdArray = 0; this->GenerateObjectIdArray = 1; this->GenerateFileIdArray = 0; this->ApplyDisplacements = 1; this->DisplacementMagnitude = 1.; this->HasModeShapes = 0; this->ModeShapeTime = -1.; this->AnimateModeShapes = 1; this->SqueezePoints = 1; this->InitialArrayInfo.clear(); this->InitialObjectInfo.clear(); } void vtkExodusIIReaderPrivate::ResetCache() { this->Cache->Clear(); this->Cache->SetCacheCapacity( this->CacheSize); // FIXME: Perhaps Cache should have a Reset and a Clear method? this->ClearConnectivityCaches(); } void vtkExodusIIReaderPrivate::SetCacheSize(double size) { if (this->CacheSize != size) { this->CacheSize = size; this->Cache->SetCacheCapacity(this->CacheSize); this->Modified(); } } bool vtkExodusIIReaderPrivate::IsXMLMetadataValid() { // Make sure that each block id referred to in the metadata arrays exist // in the data std::set blockIdsFromXml; this->Parser->GetBlockIds(blockIdsFromXml); std::vector blocksFromData = this->BlockInfo[vtkExodusIIReader::ELEM_BLOCK]; std::vector::iterator iter2; std::set::iterator iter; bool isBlockValid = false; for (iter = blockIdsFromXml.begin(); iter != blockIdsFromXml.end(); ++iter) { isBlockValid = false; for (iter2 = blocksFromData.begin(); iter2 != blocksFromData.end(); ++iter2) { if (*iter == (*iter2).Id) { isBlockValid = true; break; } } if (!isBlockValid) { break; } } return isBlockValid; } void vtkExodusIIReaderPrivate::SetSqueezePoints(int sp) { if (this->SqueezePoints == sp) return; this->SqueezePoints = sp; this->Modified(); // Invalidate global "topology" cache // The point maps should be invalidated // FIXME: bsinfop->NextSqueezePoint = 0 for all bsinfop // FIXME: bsinfop->CachedConnectivity = 0 for all bsinfop // FIXME: bsinfop->PointMap.clear() for all bsinfop // FIXME: bsinfop->ReversePointMap.clear() for all bsinfop } int vtkExodusIIReaderPrivate::GetNumberOfNodes() { return this->ModelParameters.num_nodes; } int vtkExodusIIReaderPrivate::GetNumberOfObjectsOfType(int otyp) { int i = this->GetObjectTypeIndexFromObjectType(otyp); if (i < 0) { // Could signal warning here, but might not want it if file simply doesn't have objects of some // obscure type (e.g., edge sets) return 0; } return this->GetNumberOfObjectsAtTypeIndex(i); } int vtkExodusIIReaderPrivate::GetNumberOfObjectArraysOfType(int otyp) { std::map>::iterator it = this->ArrayInfo.find(otyp); if (it != this->ArrayInfo.end()) { return (int)it->second.size(); } // Could signal warning here, but might not want it if file simply doesn't have objects of some // obscure type (e.g., edge sets) return 0; } const char* vtkExodusIIReaderPrivate::GetObjectName(int otyp, int k) { ObjectInfoType* oinfop = this->GetSortedObjectInfo(otyp, k); return oinfop ? oinfop->Name.c_str() : nullptr; } int vtkExodusIIReaderPrivate::GetObjectId(int otyp, int k) { ObjectInfoType* oinfop = this->GetSortedObjectInfo(otyp, k); return oinfop ? oinfop->Id : -1; } int vtkExodusIIReaderPrivate::GetObjectSize(int otyp, int k) { ObjectInfoType* oinfop = this->GetSortedObjectInfo(otyp, k); return oinfop ? oinfop->Size : 0; } int vtkExodusIIReaderPrivate::GetObjectStatus(int otyp, int k) { ObjectInfoType* oinfop = this->GetSortedObjectInfo(otyp, k); return oinfop ? oinfop->Status : 0; } int vtkExodusIIReaderPrivate::GetUnsortedObjectStatus(int otyp, int k) { ObjectInfoType* oinfop = this->GetUnsortedObjectInfo(otyp, k); return oinfop ? oinfop->Status : 0; } void vtkExodusIIReaderPrivate::GetInitialObjectStatus(int otyp, ObjectInfoType* objType) { for (unsigned int oidx = 0; oidx < this->InitialObjectInfo[otyp].size(); oidx++) { if ((!this->InitialObjectInfo[otyp][oidx].Name.empty() && objType->Name == this->InitialObjectInfo[otyp][oidx].Name) || (this->InitialObjectInfo[otyp][oidx].Id != -1 && objType->Id == this->InitialObjectInfo[otyp][oidx].Id)) { objType->Status = this->InitialObjectInfo[otyp][oidx].Status; break; } } } void vtkExodusIIReaderPrivate::SetObjectStatus(int otyp, int k, int stat) { stat = (stat != 0); // Force stat to be either 0 or 1 // OK, found the object ObjectInfoType* oinfop = this->GetSortedObjectInfo(otyp, k); if (!oinfop) { // error message will have been generated by GetSortedObjectInfo() return; } vtkLogF(TRACE, "vtkExodusIIReaderPrivate(%p): SetObjectStatus(%d, %d (%s), %d)", this, otyp, k, oinfop->Name.c_str(), stat); if (oinfop->Status == stat) { // no change => do nothing return; } oinfop->Status = stat; this->Modified(); } void vtkExodusIIReaderPrivate::SetUnsortedObjectStatus(int otyp, int k, int stat) { stat = (stat != 0); // Force stat to be either 0 or 1 // OK, found the object ObjectInfoType* oinfop = this->GetUnsortedObjectInfo(otyp, k); if (!oinfop) { // error message will have been generated by GetSortedObjectInfo() return; } vtkLogF(TRACE, "vtkExodusIIReaderPrivate(%p): SetUnsortedObjectStatus(%d, %d (%s), %d)", this, otyp, k, oinfop->Name.c_str(), stat); if (oinfop->Status == stat) { // no change => do nothing return; } oinfop->Status = stat; this->Modified(); } void vtkExodusIIReaderPrivate::SetInitialObjectStatus( int objectType, const char* objName, int status) { ObjectInfoType info; vtkStdString nm = objName; size_t idx = 0; int idlen = 0; int id = -1; // When no name is found for an object, it is given one of a certain format. // Parse the id out of that string and use it to identify the object later. if ((idx = nm.find("ID: ")) != vtkStdString::npos) { idx += 4; idlen = 0; while (idx + idlen < nm.length() && nm.at(idx + idlen) != ' ') { idlen++; } id = atoi(nm.substr(idx, idlen).c_str()); } else { info.Name = objName; } info.Id = id; info.Status = status; this->InitialObjectInfo[objectType].push_back(info); } const char* vtkExodusIIReaderPrivate::GetObjectArrayName(int otyp, int i) { std::map>::iterator it = this->ArrayInfo.find(otyp); if (it != this->ArrayInfo.end()) { int N = (int)it->second.size(); if (i < 0 || i >= N) { vtkDebugMacro("You requested array " << i << " in a collection of only " << N << " arrays."); return nullptr; } return it->second[i].Name.c_str(); } vtkDebugMacro("Could not find collection of arrays for objects of type " << otyp << " (" << objtype_names[this->GetObjectTypeIndexFromObjectType(otyp)] << ")."); return nullptr; } int vtkExodusIIReaderPrivate::GetNumberOfObjectArrayComponents(int otyp, int i) { std::map>::iterator it = this->ArrayInfo.find(otyp); if (it != this->ArrayInfo.end()) { int N = (int)it->second.size(); if (i < 0 || i >= N) { vtkDebugMacro("You requested array " << i << " in a collection of only " << N << " arrays."); return 0; } return it->second[i].Components; } vtkDebugMacro("Could not find collection of arrays for objects of type " << otyp << " (" << objtype_names[this->GetObjectTypeIndexFromObjectType(otyp)] << ")."); return 0; } int vtkExodusIIReaderPrivate::GetObjectArrayStatus(int otyp, int i) { std::map>::iterator it = this->ArrayInfo.find(otyp); if (it != this->ArrayInfo.end()) { int N = (int)it->second.size(); if (i < 0 || i >= N) { vtkDebugMacro("You requested array " << i << " in a collection of only " << N << " arrays."); return 0; } return it->second[i].Status; } vtkDebugMacro("Could not find collection of arrays for objects of type " << otyp << " (" << objtype_names[this->GetObjectTypeIndexFromObjectType(otyp)] << ")."); return 0; } void vtkExodusIIReaderPrivate::GetInitialObjectArrayStatus(int otyp, ArrayInfoType* objType) { for (unsigned int oidx = 0; oidx < this->InitialArrayInfo[otyp].size(); oidx++) { if (objType->Name == this->InitialArrayInfo[otyp][oidx].Name) { objType->Status = this->InitialArrayInfo[otyp][oidx].Status; break; } } } void vtkExodusIIReaderPrivate::SetObjectArrayStatus(int otyp, int i, int stat) { stat = (stat != 0); // Force stat to be either 0 or 1 std::map>::iterator it = this->ArrayInfo.find(otyp); if (it != this->ArrayInfo.end()) { int N = (int)it->second.size(); if (i < 0 || i >= N) { vtkDebugMacro("You requested array " << i << " in a collection of only " << N << " arrays."); return; } if (it->second[i].Status == stat) { // no change => do nothing return; } it->second[i].Status = stat; this->Modified(); // FIXME: Mark something so we know what's changed since the last RequestData?! // For the "global" (assembled) array, this is tricky because we really only want // to invalidate a range of the total array... For now, we'll just force the "global" // array to be reassembled even if it does mean a lot more copying -- it's not like // it was any faster before. // vtkExodusIICacheKey key( 0, GLOBAL, 0, i ); // vtkExodusIICacheKey pattern( 0, 1, 0, 1 ); this->Cache->Invalidate( vtkExodusIICacheKey(0, vtkExodusIIReader::GLOBAL, otyp, i), vtkExodusIICacheKey(0, 1, 1, 1)); } else { vtkDebugMacro("Could not find collection of arrays for objects of type " << otyp << " (" << objtype_names[this->GetObjectTypeIndexFromObjectType(otyp)] << ")."); } } void vtkExodusIIReaderPrivate::SetInitialObjectArrayStatus( int objectType, const char* arrayName, int status) { ArrayInfoType ainfo; ainfo.Name = arrayName; ainfo.Status = status; this->InitialArrayInfo[objectType].push_back(ainfo); } int vtkExodusIIReaderPrivate::GetNumberOfObjectAttributes(int otyp, int oi) { std::map>::iterator it = this->BlockInfo.find(otyp); if (it != this->BlockInfo.end()) { int N = (int)it->second.size(); if (oi < 0 || oi >= N) { int otypIdx = this->GetObjectTypeIndexFromObjectType(otyp); const char* btname = otypIdx >= 0 ? objtype_names[otypIdx] : "block"; static_cast(btname); // not referenced warning vtkDebugMacro( "You requested " << btname << " " << oi << " in a collection of only " << N << " blocks."); return 0; } oi = this->SortedObjectIndices[otyp][oi]; // index into sorted list of objects (block order, not // file order) return (int)it->second[oi].AttributeNames.size(); } return 0; } const char* vtkExodusIIReaderPrivate::GetObjectAttributeName(int otyp, int oi, int ai) { std::map>::iterator it = this->BlockInfo.find(otyp); if (it != this->BlockInfo.end()) { int N = (int)it->second.size(); if (oi < 0 || oi >= N) { vtkDebugMacro("You requested block " << oi << " in a collection of only " << N << " blocks."); return nullptr; } oi = this->SortedObjectIndices[otyp][oi]; // index into sorted list of objects (block order, not // file order) N = (int)it->second[oi].AttributeNames.size(); if (ai < 0 || ai >= N) { vtkDebugMacro( "You requested attribute " << ai << " in a collection of only " << N << " attributes."); return nullptr; } else { return it->second[oi].AttributeNames[ai].c_str(); } } vtkDebugMacro("Could not find collection of blocks of type " << otyp << " (" << objtype_names[this->GetObjectTypeIndexFromObjectType(otyp)] << ")."); return nullptr; } int vtkExodusIIReaderPrivate::GetObjectAttributeIndex(int otyp, int oi, const char* attribName) { std::map>::iterator it = this->BlockInfo.find(otyp); if (it != this->BlockInfo.end()) { int N = (int)it->second.size(); if (oi < 0 || oi >= N) { vtkDebugMacro("You requested block " << oi << " in a collection of only " << N << " blocks."); return -1; } oi = this->SortedObjectIndices[otyp][oi]; // index into sorted list of objects (block order, not // file order) N = (int)it->second[oi].AttributeNames.size(); int ai; for (ai = 0; ai < N; ++ai) { if (it->second[oi].AttributeNames[ai] == attribName) { return ai; } } return -1; } vtkDebugMacro("Could not find collection of blocks of type " << otyp << " (" << objtype_names[this->GetObjectTypeIndexFromObjectType(otyp)] << ")."); return -1; } int vtkExodusIIReaderPrivate::GetObjectAttributeStatus(int otyp, int oi, int ai) { std::map>::iterator it = this->BlockInfo.find(otyp); if (it != this->BlockInfo.end()) { int N = (int)it->second.size(); if (oi < 0 || oi >= N) { vtkDebugMacro("You requested block " << oi << " in a collection of only " << N << " blocks."); return 0; } oi = this->SortedObjectIndices[otyp][oi]; // index into sorted list of objects (block order, not // file order) N = (int)it->second[oi].AttributeStatus.size(); if (ai < 0 || ai >= N) { vtkDebugMacro( "You requested attribute " << ai << " in a collection of only " << N << " attributes."); return 0; } else { return it->second[oi].AttributeStatus[ai]; } } vtkDebugMacro("Could not find collection of blocks of type " << otyp << " (" << objtype_names[this->GetObjectTypeIndexFromObjectType(otyp)] << ")."); return 0; } void vtkExodusIIReaderPrivate::SetObjectAttributeStatus(int otyp, int oi, int ai, int status) { status = status ? 1 : 0; std::map>::iterator it = this->BlockInfo.find(otyp); if (it != this->BlockInfo.end()) { int N = (int)it->second.size(); if (oi < 0 || oi >= N) { vtkDebugMacro("You requested block " << oi << " in a collection of only " << N << " blocks."); return; } oi = this->SortedObjectIndices[otyp][oi]; // index into sorted list of objects (block order, not // file order) N = (int)it->second[oi].AttributeStatus.size(); if (ai < 0 || ai >= N) { vtkDebugMacro( "You requested attribute " << ai << " in a collection of only " << N << " attribute."); return; } else { if (it->second[oi].AttributeStatus[ai] == status) { return; } it->second[oi].AttributeStatus[ai] = status; this->Modified(); } } vtkDebugMacro("Could not find collection of blocks of type " << otyp << " (" << objtype_names[this->GetObjectTypeIndexFromObjectType(otyp)] << ")."); } void vtkExodusIIReaderPrivate::SetApplyDisplacements(vtkTypeBool d) { if (this->ApplyDisplacements == d) return; this->ApplyDisplacements = d; this->Modified(); // Require the coordinates to be recomputed: this->Cache->Invalidate( vtkExodusIICacheKey(0, vtkExodusIIReader::NODAL_COORDS, 0, 0), vtkExodusIICacheKey(0, 1, 0, 0)); } void vtkExodusIIReaderPrivate::SetDisplacementMagnitude(double s) { if (this->DisplacementMagnitude == s) return; this->DisplacementMagnitude = s; this->Modified(); // Require the coordinates to be recomputed: this->Cache->Invalidate( vtkExodusIICacheKey(0, vtkExodusIIReader::NODAL_COORDS, 0, 0), vtkExodusIICacheKey(0, 1, 0, 0)); } vtkDataArray* vtkExodusIIReaderPrivate::FindDisplacementVectors(int timeStep) { std::map>::iterator it = this->ArrayInfo.find(vtkExodusIIReader::NODAL); if (it != this->ArrayInfo.end()) { int N = (int)it->second.size(); for (int i = 0; i < N; ++i) { std::string upperName = vtksys::SystemTools::UpperCase(it->second[i].Name.substr(0, 3)); if (upperName == "DIS" && it->second[i].Components == this->ModelParameters.num_dim) { return this->GetCacheOrRead(vtkExodusIICacheKey(timeStep, vtkExodusIIReader::NODAL, 0, i)); } } } return nullptr; } // -------------------------------------------------------- PUBLIC CLASS MEMBERS vtkStandardNewMacro(vtkExodusIIReader); vtkCxxSetObjectMacro(vtkExodusIIReader, Metadata, vtkExodusIIReaderPrivate); vtkInformationKeyMacro(vtkExodusIIReader, GLOBAL_VARIABLE, Integer); vtkInformationKeyMacro(vtkExodusIIReader, GLOBAL_TEMPORAL_VARIABLE, Integer); vtkExodusIIReader::vtkExodusIIReader() { this->FileName = nullptr; this->XMLFileName = nullptr; this->Metadata = vtkExodusIIReaderPrivate::New(); this->Metadata->Parent = this; this->Metadata->SetCacheSize(0.0); this->TimeStep = 0; this->TimeStepRange[0] = 0; this->TimeStepRange[1] = 0; this->ModeShapesRange[0] = 0; this->ModeShapesRange[1] = 0; this->DisplayType = 0; this->DisplayType = 0; this->SILUpdateStamp = -1; this->UseLegacyBlockNames = false; this->SetNumberOfInputPorts(0); } vtkExodusIIReader::~vtkExodusIIReader() { this->SetXMLFileName(nullptr); this->SetFileName(nullptr); this->SetMetadata(nullptr); // this->SetExodusModel( 0 ); } // Normally, vtkExodusIIReader::PrintSelf would be here. // But it's above to prevent PrintSelf-Hybrid from failing because it assumes // the first PrintSelf method is the one for the class declared in the header file. int vtkExodusIIReader::CanReadFile(const char* fname) { int exoid; int appWordSize = 8; int diskWordSize = 8; float version; if ((exoid = ex_open(fname, EX_READ, &appWordSize, &diskWordSize, &version)) < 0) { return 0; } if (ex_close(exoid) != 0) { vtkWarningMacro("Unable to close \"" << fname << "\" opened for testing."); return 0; } return 1; } #if 0 void vtkExodusIIReaderPrivate::Modified() { cout << "E2RP modified\n"; this->Superclass::Modified(); } void vtkExodusIIReader::Modified() { cout << "E2R modified\n"; this->Superclass::Modified(); } #endif // 0 vtkMTimeType vtkExodusIIReader::GetMTime() { // return this->MTime.GetMTime(); /* vtkMTimeType mtime1, mtime2; vtkMTimeType readerMTime = this->MTime.GetMTime(); vtkMTimeType privateMTime = this->Metadata->GetMTime(); vtkMTimeType fileNameMTime = this->FileNameMTime.GetMTime(); vtkMTimeType xmlFileNameMTime = this->XMLFileNameMTime.GetMTime(); mtime1 = privateMTime > readerMTime ? privateMTime : readerMTime; mtime2 = fileNameMTime > xmlFileNameMTime ? fileNameMTime : xmlFileNameMTime; return mtime1 > mtime2 ? mtime1 : mtime2; */ vtkMTimeType readerMTime = this->MTime.GetMTime(); vtkMTimeType privateMTime = this->Metadata->GetMTime(); return privateMTime > readerMTime ? privateMTime : readerMTime; } vtkMTimeType vtkExodusIIReader::GetMetadataMTime() { return this->Metadata->InformationTimeStamp < this->Metadata->GetMTime() ? this->Metadata->InformationTimeStamp : this->Metadata->GetMTime(); } #define vtkSetStringMacroBody(propName, fname) \ int modified = 0; \ if (fname == this->propName) \ return; \ if (fname && this->propName && !strcmp(fname, this->propName)) \ return; \ modified = 1; \ delete[] this->propName; \ if (fname) \ { \ this->propName = vtksys::SystemTools::DuplicateString(fname); \ } \ else \ { \ this->propName = nullptr; \ } void vtkExodusIIReader::SetFileName(const char* fname) { vtkLogF(TRACE, "%s: SetFileName old=%s, new=%s", vtkLogIdentifier(this), this->FileName, fname); vtkSetStringMacroBody(FileName, fname); if (modified) { this->Metadata->Reset(); this->FileNameMTime.Modified(); } } void vtkExodusIIReader::SetXMLFileName(const char* fname) { vtkSetStringMacroBody(XMLFileName, fname); if (modified) { this->XMLFileNameMTime.Modified(); this->Modified(); } } //------------------------------------------------------------------------------ vtkTypeBool vtkExodusIIReader::ProcessRequest( vtkInformation* request, vtkInformationVector** inputVector, vtkInformationVector* outputVector) { if (request->Has(vtkDemandDrivenPipeline::REQUEST_DATA())) { return this->RequestData(request, inputVector, outputVector); } // execute information if (request->Has(vtkDemandDrivenPipeline::REQUEST_INFORMATION())) { return this->RequestInformation(request, inputVector, outputVector); } return this->Superclass::ProcessRequest(request, inputVector, outputVector); } //------------------------------------------------------------------------------ int vtkExodusIIReader::RequestInformation(vtkInformation* vtkNotUsed(request), vtkInformationVector** vtkNotUsed(inputVector), vtkInformationVector* outputVector) { int newMetadata = 0; vtkInformation* outInfo = outputVector->GetInformationObject(0); // If the metadata is older than the filename if (this->GetMetadataMTime() < this->FileNameMTime) { if (this->Metadata->OpenFile(this->FileName)) { // We need to initialize the XML parser before calling RequestInformation // on the metadata if (this->FindXMLFile()) { vtkExodusIIReaderParser* parser = vtkExodusIIReaderParser::New(); this->Metadata->SetParser(parser); // Now overwrite any names in the exodus file with names from XML file. parser->Go(this->XMLFileName); parser->Delete(); } this->Metadata->RequestInformation(); // Now check to see if the DART metadata is valid if (this->Metadata->Parser && !this->Metadata->IsXMLMetadataValid()) { this->Metadata->Parser->Delete(); this->Metadata->Parser = nullptr; // Reset block names. int numBlocks = this->Metadata->GetNumberOfObjectsOfType(vtkExodusIIReader::ELEM_BLOCK); for (int cc = 0; cc < numBlocks; cc++) { vtkExodusIIReaderPrivate::BlockInfoType* binfop = static_cast( this->Metadata->GetSortedObjectInfo(vtkExodusIIReader::ELEM_BLOCK, cc)); binfop->Name = binfop->OriginalName; } } // Once meta-data has been refreshed we update the SIL. this->Metadata->BuildSIL(); this->SILUpdateStamp++; // update the timestamp. this->Metadata->CloseFile(); newMetadata = 1; } else { vtkErrorMacro("Unable to open file \"" << (this->FileName ? this->FileName : "(null)") << "\" to read metadata"); return 0; } } this->AdvertiseTimeSteps(outInfo); // Advertize the SIL. outInfo->Set(vtkDataObject::SIL(), this->Metadata->GetSIL()); if (newMetadata) { // update ExodusModelMetadata } return 1; } int vtkExodusIIReader::RequestData(vtkInformation* vtkNotUsed(request), vtkInformationVector** vtkNotUsed(inputVector), vtkInformationVector* outputVector) { if (!this->FileName || !this->Metadata->OpenFile(this->FileName)) { vtkErrorMacro("Unable to open file \"" << (this->FileName ? this->FileName : "(null)") << "\" to read data"); return 0; } vtkInformation* outInfo = outputVector->GetInformationObject(0); vtkMultiBlockDataSet* output = vtkMultiBlockDataSet::SafeDownCast(outInfo->Get(vtkDataObject::DATA_OBJECT())); // Check if a particular time was requested. if (outInfo->Has(vtkStreamingDemandDrivenPipeline::UPDATE_TIME_STEP())) { // Get the requested time step. We only support requests of a single time step in this reader // right now double requestedTimeStep = outInfo->Get(vtkStreamingDemandDrivenPipeline::UPDATE_TIME_STEP()); // Save the time value in the output data information. int length = outInfo->Length(vtkStreamingDemandDrivenPipeline::TIME_STEPS()); double* steps = outInfo->Get(vtkStreamingDemandDrivenPipeline::TIME_STEPS()); if (!this->GetHasModeShapes()) { // find the highest time step with a time value that is smaller than the requested time. // timeStep = 0; // while (timeStep < length - 1 && steps[timeStep] < requestedTimeStep) // { // timeStep++; // } // this->TimeStep = timeStep; // find the timestep with the closest value int cnt = 0; int closestStep = 0; double minDist = -1; for (cnt = 0; cnt < length; cnt++) { double tdist = (steps[cnt] - requestedTimeStep > requestedTimeStep - steps[cnt]) ? steps[cnt] - requestedTimeStep : requestedTimeStep - steps[cnt]; if (minDist < 0 || tdist < minDist) { minDist = tdist; closestStep = cnt; } } this->TimeStep = closestStep; // cout << "Requested value: " << requestedTimeStep << " Step: " << this->TimeStep << endl; output->GetInformation()->Set(vtkDataObject::DATA_TIME_STEP(), steps[this->TimeStep]); } else if (this->GetAnimateModeShapes()) { // Let the metadata know the time value so that the Metadata->RequestData call below will // generate the animated mode shape properly. this->Metadata->ModeShapeTime = requestedTimeStep; output->GetInformation()->Set(vtkDataObject::DATA_TIME_STEP(), this->Metadata->ModeShapeTime); // output->GetInformation()->Remove( vtkDataObject::DATA_TIME_STEP() ); } } this->Metadata->RequestData(this->TimeStep, output); return 1; } int vtkExodusIIReader::GetMaxNameLength() { return ex_inquire_int(this->Metadata->Exoid, EX_INQ_DB_MAX_USED_NAME_LENGTH); } void vtkExodusIIReader::SetGenerateObjectIdCellArray(vtkTypeBool x) { this->Metadata->SetGenerateObjectIdArray(x); } vtkTypeBool vtkExodusIIReader::GetGenerateObjectIdCellArray() { return this->Metadata->GetGenerateObjectIdArray(); } void vtkExodusIIReader::SetGenerateGlobalElementIdArray(vtkTypeBool x) { this->Metadata->SetGenerateGlobalElementIdArray(x); } vtkTypeBool vtkExodusIIReader::GetGenerateGlobalElementIdArray() { return this->Metadata->GetGenerateGlobalElementIdArray(); } void vtkExodusIIReader::SetGenerateGlobalNodeIdArray(vtkTypeBool x) { this->Metadata->SetGenerateGlobalNodeIdArray(x); } vtkTypeBool vtkExodusIIReader::GetGenerateGlobalNodeIdArray() { return this->Metadata->GetGenerateGlobalNodeIdArray(); } void vtkExodusIIReader::SetGenerateImplicitElementIdArray(vtkTypeBool x) { this->Metadata->SetGenerateImplicitElementIdArray(x); } vtkTypeBool vtkExodusIIReader::GetGenerateImplicitElementIdArray() { return this->Metadata->GetGenerateImplicitElementIdArray(); } void vtkExodusIIReader::SetGenerateImplicitNodeIdArray(vtkTypeBool x) { this->Metadata->SetGenerateImplicitNodeIdArray(x); } vtkTypeBool vtkExodusIIReader::GetGenerateImplicitNodeIdArray() { return this->Metadata->GetGenerateImplicitNodeIdArray(); } void vtkExodusIIReader::SetGenerateFileIdArray(vtkTypeBool x) { this->Metadata->SetGenerateFileIdArray(x); } vtkTypeBool vtkExodusIIReader::GetGenerateFileIdArray() { return this->Metadata->GetGenerateFileIdArray(); } void vtkExodusIIReader::SetFileId(int x) { this->Metadata->SetFileId(x); } int vtkExodusIIReader::GetFileId() { return this->Metadata->GetFileId(); } // FIXME: Implement the four functions that return ID_NOT_FOUND below. int vtkExodusIIReader::GetGlobalElementID(vtkDataSet* data, int localID) { return GetGlobalElementID(data, localID, SEARCH_TYPE_ELEMENT_THEN_NODE); } int vtkExodusIIReader::GetGlobalElementID(vtkDataSet* data, int localID, int searchType) { (void)data; (void)localID; (void)searchType; return ID_NOT_FOUND; } int vtkExodusIIReader::GetGlobalFaceID(vtkDataSet* data, int localID) { return GetGlobalFaceID(data, localID, SEARCH_TYPE_ELEMENT_THEN_NODE); } int vtkExodusIIReader::GetGlobalFaceID(vtkDataSet* data, int localID, int searchType) { (void)data; (void)localID; (void)searchType; return ID_NOT_FOUND; } int vtkExodusIIReader::GetGlobalEdgeID(vtkDataSet* data, int localID) { return GetGlobalEdgeID(data, localID, SEARCH_TYPE_ELEMENT_THEN_NODE); } int vtkExodusIIReader::GetGlobalEdgeID(vtkDataSet* data, int localID, int searchType) { (void)data; (void)localID; (void)searchType; return ID_NOT_FOUND; } int vtkExodusIIReader::GetGlobalNodeID(vtkDataSet* data, int localID) { return GetGlobalNodeID(data, localID, SEARCH_TYPE_NODE_THEN_ELEMENT); } int vtkExodusIIReader::GetGlobalNodeID(vtkDataSet* data, int localID, int searchType) { (void)data; (void)localID; (void)searchType; return ID_NOT_FOUND; } void vtkExodusIIReader::SetApplyDisplacements(vtkTypeBool d) { this->Metadata->SetApplyDisplacements(d); } vtkTypeBool vtkExodusIIReader::GetApplyDisplacements() { return this->Metadata->GetApplyDisplacements(); } void vtkExodusIIReader::SetDisplacementMagnitude(float s) { this->Metadata->SetDisplacementMagnitude(s); } float vtkExodusIIReader::GetDisplacementMagnitude() { return this->Metadata->GetDisplacementMagnitude(); } void vtkExodusIIReader::SetHasModeShapes(vtkTypeBool ms) { this->Metadata->SetHasModeShapes(ms); } vtkTypeBool vtkExodusIIReader::GetHasModeShapes() { return this->Metadata->GetHasModeShapes(); } void vtkExodusIIReader::SetModeShapeTime(double phase) { // Phase should repeat outside the bounds [0,1]. For example, 0.25 is // equivalent to 1.25, 2.25, -0.75, and -1.75. double x = phase - floor(phase); this->Metadata->SetModeShapeTime(x); } double vtkExodusIIReader::GetModeShapeTime() { return this->Metadata->GetModeShapeTime(); } void vtkExodusIIReader::SetAnimateModeShapes(vtkTypeBool flag) { this->Metadata->SetAnimateModeShapes(flag); } vtkTypeBool vtkExodusIIReader::GetAnimateModeShapes() { return this->Metadata->GetAnimateModeShapes(); } void vtkExodusIIReader::SetIgnoreFileTime(bool value) { if (this->Metadata->GetIgnoreFileTime() == value) { return; } this->Metadata->SetIgnoreFileTime(value); this->Modified(); } bool vtkExodusIIReader::GetIgnoreFileTime() { return this->Metadata->GetIgnoreFileTime(); } const char* vtkExodusIIReader::GetTitle() { return this->Metadata->ModelParameters.title; } int vtkExodusIIReader::GetDimensionality() { return this->Metadata->ModelParameters.num_dim; } int vtkExodusIIReader::GetNumberOfTimeSteps() { return (int)this->Metadata->Times.size(); } int vtkExodusIIReader::GetNumberOfNodesInFile() { return this->Metadata->ModelParameters.num_nodes; } int vtkExodusIIReader::GetNumberOfEdgesInFile() { return this->Metadata->ModelParameters.num_edge; } int vtkExodusIIReader::GetNumberOfFacesInFile() { return this->Metadata->ModelParameters.num_face; } int vtkExodusIIReader::GetNumberOfElementsInFile() { return this->Metadata->ModelParameters.num_elem; } int vtkExodusIIReader::GetNumberOfObjects(int objectType) { return this->Metadata->GetNumberOfObjectsOfType(objectType); } int vtkExodusIIReader::GetObjectTypeFromName(const char* name) { vtkStdString tname(name); if (tname == "edge") return EDGE_BLOCK; else if (tname == "face") return FACE_BLOCK; else if (tname == "element") return ELEM_BLOCK; else if (tname == "node set") return NODE_SET; else if (tname == "edge set") return EDGE_SET; else if (tname == "face set") return FACE_SET; else if (tname == "side set") return SIDE_SET; else if (tname == "element set") return ELEM_SET; else if (tname == "node map") return NODE_MAP; else if (tname == "edge map") return EDGE_MAP; else if (tname == "face map") return FACE_MAP; else if (tname == "element map") return ELEM_MAP; else if (tname == "grid") return GLOBAL; else if (tname == "node") return NODAL; else if (tname == "assembly") return ASSEMBLY; else if (tname == "part") return PART; else if (tname == "material") return MATERIAL; else if (tname == "hierarchy") return HIERARCHY; else if (tname == "cell") return GLOBAL_CONN; else if (tname == "element block cell") return ELEM_BLOCK_ELEM_CONN; else if (tname == "element block face") return ELEM_BLOCK_FACE_CONN; else if (tname == "element block edge") return ELEM_BLOCK_EDGE_CONN; else if (tname == "face block cell") return FACE_BLOCK_CONN; else if (tname == "edge block cell") return EDGE_BLOCK_CONN; else if (tname == "element set cell") return ELEM_SET_CONN; else if (tname == "side set cell") return SIDE_SET_CONN; else if (tname == "face set cell") return FACE_SET_CONN; else if (tname == "edge set cell") return EDGE_SET_CONN; else if (tname == "node set cell") return NODE_SET_CONN; else if (tname == "nodal coordinates") return NODAL_COORDS; else if (tname == "object id") return OBJECT_ID; else if (tname == "implicit element id") return IMPLICIT_ELEMENT_ID; else if (tname == "implicit node id") return IMPLICIT_NODE_ID; else if (tname == "global element id") return GLOBAL_ELEMENT_ID; else if (tname == "global node id") return GLOBAL_NODE_ID; else if (tname == "element id") return ELEMENT_ID; else if (tname == "node id") return NODE_ID; else if (tname == "pointmap") return NODAL_SQUEEZEMAP; return -1; } const char* vtkExodusIIReader::GetObjectTypeName(int otyp) { switch (otyp) { case EDGE_BLOCK: return "edge"; case FACE_BLOCK: return "face"; case ELEM_BLOCK: return "element"; case NODE_SET: return "node set"; case EDGE_SET: return "edge set"; case FACE_SET: return "face set"; case SIDE_SET: return "side set"; case ELEM_SET: return "element set"; case NODE_MAP: return "node map"; case EDGE_MAP: return "edge map"; case FACE_MAP: return "face map"; case ELEM_MAP: return "element map"; case GLOBAL: return "grid"; case NODAL: return "node"; case ASSEMBLY: return "assembly"; case PART: return "part"; case MATERIAL: return "material"; case HIERARCHY: return "hierarchy"; case GLOBAL_CONN: return "cell"; case ELEM_BLOCK_ELEM_CONN: return "element block cell"; case ELEM_BLOCK_FACE_CONN: return "element block face"; case ELEM_BLOCK_EDGE_CONN: return "element block edge"; case FACE_BLOCK_CONN: return "face block cell"; case EDGE_BLOCK_CONN: return "edge block cell"; case ELEM_SET_CONN: return "element set cell"; case SIDE_SET_CONN: return "side set cell"; case FACE_SET_CONN: return "face set cell"; case EDGE_SET_CONN: return "edge set cell"; case NODE_SET_CONN: return "node set cell"; case NODAL_COORDS: return "nodal coordinates"; case OBJECT_ID: return "object id"; case IMPLICIT_ELEMENT_ID: return "implicit element id"; case IMPLICIT_NODE_ID: return "implicit node id"; case GLOBAL_ELEMENT_ID: return "global element id"; case GLOBAL_NODE_ID: return "global node id"; case ELEMENT_ID: return "element id"; case NODE_ID: return "node id"; case NODAL_SQUEEZEMAP: return "pointmap"; } return nullptr; } int vtkExodusIIReader::GetNumberOfNodes() { return this->Metadata->GetNumberOfNodes(); } int vtkExodusIIReader::GetNumberOfEntriesInObject(int objectType, int objectIndex) { return this->Metadata->GetObjectSize(objectType, objectIndex); } int vtkExodusIIReader::GetObjectId(int objectType, int objectIndex) { return this->Metadata->GetObjectId(objectType, objectIndex); } int vtkExodusIIReader::GetObjectStatus(int objectType, int objectIndex) { return this->Metadata->GetObjectStatus(objectType, objectIndex); } void vtkExodusIIReader::SetObjectStatus(int objectType, int objectIndex, int status) { vtkLogF(TRACE, "%s: SetObjectStatus(type=%d, idx=%d, status=%d)", vtkLogIdentifier(this), objectType, objectIndex, status); this->Metadata->SetObjectStatus(objectType, objectIndex, status); } void vtkExodusIIReader::SetObjectStatus(int objectType, const char* objectName, int status) { vtkLogScopeF(TRACE, "%s: SetObjectStatus(%s, %s, %d)", vtkLogIdentifier(this), this->GetObjectTypeName(objectType), objectName, status); if (objectName && strlen(objectName) > 0) { if (this->GetNumberOfObjects(objectType) == 0) { // The object status is being set before the meta data has been finalized // so cache this value for later and use as the initial value // If the number of objects really is zero then this doesn't do any harm. this->Metadata->SetInitialObjectStatus(objectType, objectName, status); return; } this->SetObjectStatus(objectType, this->GetObjectIndex(objectType, objectName), status); assert(this->GetObjectStatus(objectType, objectName) == status); } } const char* vtkExodusIIReader::GetObjectName(int objectType, int objectIndex) { return this->Metadata->GetObjectName(objectType, objectIndex); } int vtkExodusIIReader::GetObjectIndex(int objectType, const char* objectName) { if (!objectName) { vtkErrorMacro("You must specify a non-nullptr name"); return -1; } int nObj = this->GetNumberOfObjects(objectType); if (nObj == 0) { vtkDebugMacro("No objects of that type (" << objectType << ") to find index for given name " << objectName << "."); return -1; } vtkStdString objectRealName(objectName); // handle legacy block names. vtksys::RegularExpression regex( "^(Unnamed block ID: [0-9]+)( Type: [0-9a-zA-Z]+)?( Size: [0-9]+)?$"); if (regex.find(objectRealName)) { objectRealName = regex.match(1); } for (int obj = 0; obj < nObj; ++obj) { const char* storedObjName = this->GetObjectName(objectType, obj); if (objectRealName == vtkStdString(storedObjName)) { return obj; } } vtkDebugMacro( "No objects named \"" << objectName << "\" of the specified type (" << objectType << ")."); return -1; } int vtkExodusIIReader::GetObjectIndex(int objectType, int id) { int nObj = this->GetNumberOfObjects(objectType); if (nObj == 0) { vtkDebugMacro( "No objects of that type (" << objectType << ") to find index for given id " << id << "."); return -1; } for (int obj = 0; obj < nObj; ++obj) { if (this->GetObjectId(objectType, obj) == id) { return obj; } } vtkDebugMacro( "No objects with id \"" << id << "\" of the specified type (" << objectType << ")."); return -1; } int vtkExodusIIReader::GetNumberOfObjectArrays(int objectType) { return this->Metadata->GetNumberOfObjectArraysOfType(objectType); } const char* vtkExodusIIReader::GetObjectArrayName(int objectType, int arrayIndex) { return this->Metadata->GetObjectArrayName(objectType, arrayIndex); } int vtkExodusIIReader::GetNumberOfObjectArrayComponents(int objectType, int arrayIndex) { return this->Metadata->GetNumberOfObjectArrayComponents(objectType, arrayIndex); } int vtkExodusIIReader::GetObjectArrayStatus(int objectType, int arrayIndex) { return this->Metadata->GetObjectArrayStatus(objectType, arrayIndex); } void vtkExodusIIReader::SetObjectArrayStatus(int objectType, int arrayIndex, int status) { this->Metadata->SetObjectArrayStatus(objectType, arrayIndex, status); } void vtkExodusIIReader::SetObjectArrayStatus(int objectType, const char* arrayName, int status) { if (arrayName && strlen(arrayName) > 0) { if (this->GetNumberOfObjectArrays(objectType) == 0) { // The array status is being set before the meta data has been finalized // so cache this value for later and use as the initial value // If the number of arrays really is zero then this doesn't do any harm. this->Metadata->SetInitialObjectArrayStatus(objectType, arrayName, status); return; } this->SetObjectArrayStatus( objectType, this->GetObjectArrayIndex(objectType, arrayName), status); } } int vtkExodusIIReader::GetNumberOfObjectAttributes(int objectType, int objectIndex) { return this->Metadata->GetNumberOfObjectAttributes(objectType, objectIndex); } const char* vtkExodusIIReader::GetObjectAttributeName( int objectType, int objectIndex, int attribIndex) { return this->Metadata->GetObjectAttributeName(objectType, objectIndex, attribIndex); } int vtkExodusIIReader::GetObjectAttributeIndex( int objectType, int objectIndex, const char* attribName) { return this->Metadata->GetObjectAttributeIndex(objectType, objectIndex, attribName); } int vtkExodusIIReader::GetObjectAttributeStatus(int objectType, int objectIndex, int attribIndex) { return this->Metadata->GetObjectAttributeStatus(objectType, objectIndex, attribIndex); } void vtkExodusIIReader::SetObjectAttributeStatus( int objectType, int objectIndex, int attribIndex, int status) { this->Metadata->SetObjectAttributeStatus(objectType, objectIndex, attribIndex, status); } int vtkExodusIIReader::GetObjectArrayIndex(int objectType, const char* arrayName) { if (!arrayName) { vtkErrorMacro("You must specify a non-nullptr name"); return -1; } int nObj = this->GetNumberOfObjectArrays(objectType); if (nObj == 0) { vtkDebugMacro("No objects of that type (" << objectType << ") to find index for given array " << arrayName << "."); return -1; } for (int obj = 0; obj < nObj; ++obj) { if (!strcmp(arrayName, this->GetObjectArrayName(objectType, obj))) { return obj; } } vtkDebugMacro( "No arrays named \"" << arrayName << "\" of the specified type (" << objectType << ")."); return -1; } vtkIdType vtkExodusIIReader::GetTotalNumberOfNodes() { return this->Metadata->GetModelParams()->num_nodes; } vtkIdType vtkExodusIIReader::GetTotalNumberOfEdges() { return this->Metadata->GetModelParams()->num_edge; } vtkIdType vtkExodusIIReader::GetTotalNumberOfFaces() { return this->Metadata->GetModelParams()->num_face; } vtkIdType vtkExodusIIReader::GetTotalNumberOfElements() { return this->Metadata->GetModelParams()->num_elem; } // %--------------------------------------------------------------------------- int vtkExodusIIReader::GetNumberOfPartArrays() { return this->Metadata->GetNumberOfParts(); } const char* vtkExodusIIReader::GetPartArrayName(int arrayIdx) { return this->Metadata->GetPartName(arrayIdx); } int vtkExodusIIReader::GetPartArrayID(const char* name) { int numArrays = this->GetNumberOfPartArrays(); for (int i = 0; i < numArrays; i++) { if (strcmp(name, this->GetPartArrayName(i)) == 0) { return i; } } return -1; } const char* vtkExodusIIReader::GetPartBlockInfo(int arrayIdx) { return this->Metadata->GetPartBlockInfo(arrayIdx); } void vtkExodusIIReader::SetPartArrayStatus(int index, int flag) { // Only modify if we are 'out of sync' if (this->Metadata->GetPartStatus(index) != flag) { this->Metadata->SetPartStatus(index, flag); // Because which parts are on/off affects the // geometry we need to remake the mesh cache // this->RemakeDataCacheFlag = 1; this->Modified(); } } void vtkExodusIIReader::SetPartArrayStatus(const char* name, int flag) { // Only modify if we are 'out of sync' if (this->Metadata->GetPartStatus(name) != flag) { this->Metadata->SetPartStatus(name, flag); // Because which parts are on/off affects the // geometry we need to remake the mesh cache // this->RemakeDataCacheFlag = 1; this->Modified(); } } int vtkExodusIIReader::GetPartArrayStatus(int index) { return this->Metadata->GetPartStatus(index); } int vtkExodusIIReader::GetPartArrayStatus(const char* part) { return this->Metadata->GetPartStatus(part); } int vtkExodusIIReader::GetNumberOfMaterialArrays() { return this->Metadata->GetNumberOfMaterials(); } const char* vtkExodusIIReader::GetMaterialArrayName(int arrayIdx) { return this->Metadata->GetMaterialName(arrayIdx); } int vtkExodusIIReader::GetMaterialArrayID(const char* matl) { (void)matl; return 0; } void vtkExodusIIReader::SetMaterialArrayStatus(int index, int flag) { // Only modify if we are 'out of sync' if (this->Metadata->GetMaterialStatus(index) != flag) { this->Metadata->SetMaterialStatus(index, flag); // Because which materials are on/off affects the // geometry we need to remake the mesh cache // this->RemakeDataCacheFlag = 1; this->Modified(); } } void vtkExodusIIReader::SetMaterialArrayStatus(const char* matl, int flag) { // Only modify if we are 'out of sync' if (this->Metadata->GetMaterialStatus(matl) != flag) { this->Metadata->SetMaterialStatus(matl, flag); // Because which materials are on/off affects the // geometry we need to remake the mesh cache // this->RemakeDataCacheFlag = 1; this->Modified(); } } int vtkExodusIIReader::GetMaterialArrayStatus(int index) { return this->Metadata->GetMaterialStatus(index); } int vtkExodusIIReader::GetMaterialArrayStatus(const char* matl) { return this->Metadata->GetMaterialStatus(matl); } int vtkExodusIIReader::GetNumberOfAssemblyArrays() { return this->Metadata->GetNumberOfAssemblies(); } const char* vtkExodusIIReader::GetAssemblyArrayName(int arrayIdx) { return this->Metadata->GetAssemblyName(arrayIdx); } int vtkExodusIIReader::GetAssemblyArrayID(const char* name) { int numArrays = this->GetNumberOfAssemblyArrays(); for (int i = 0; i < numArrays; i++) { if (strcmp(name, this->GetAssemblyArrayName(i)) == 0) { return i; } } return -1; } void vtkExodusIIReader::SetAssemblyArrayStatus(int index, int flag) { // Only modify if we are 'out of sync' if (this->Metadata->GetAssemblyStatus(index) != flag) { this->Metadata->SetAssemblyStatus(index, flag); // Because which materials are on/off affects the // geometry we need to remake the mesh cache // this->RemakeDataCacheFlag = 1; this->Modified(); } } void vtkExodusIIReader::SetAssemblyArrayStatus(const char* name, int flag) { // Only modify if we are 'out of sync' if (this->Metadata->GetAssemblyStatus(name) != flag) { this->Metadata->SetAssemblyStatus(name, flag); // Because which materials are on/off affects the // geometry we need to remake the mesh cache // this->RemakeDataCacheFlag = 1; this->Modified(); } } int vtkExodusIIReader::GetAssemblyArrayStatus(int index) { return this->Metadata->GetAssemblyStatus(index); } int vtkExodusIIReader::GetAssemblyArrayStatus(const char* name) { return this->Metadata->GetAssemblyStatus(name); } int vtkExodusIIReader::GetNumberOfHierarchyArrays() { // if (this->Metadata->Parser) // { // return this->Metadata->Parser->GetNumberOfHierarchyEntries(); // } return 0; } const char* vtkExodusIIReader::GetHierarchyArrayName(int vtkNotUsed(arrayIdx)) { // if (this->Metadata->Parser) // { // this->Metadata->Parser->SetCurrentHierarchyEntry(arrayIdx); // return this->Metadata->Parser->GetCurrentHierarchyEntry(); // } return "Should not see this"; } void vtkExodusIIReader::SetHierarchyArrayStatus(int vtkNotUsed(index), int vtkNotUsed(flag)) { //// Only modify if we are 'out of sync' ////if (this->GetHierarchyArrayStatus(index) != flag) //// { // if (this->Metadata->Parser) // { // std::vector blocksIds = this->Metadata->Parser->GetBlocksForEntry(index); // for (std::vector::size_type i=0;iMetadata->SetObjectStatus(vtkExodusIIReader::ELEM_BLOCK, // this->GetObjectIndex(ELEM_BLOCK,blocksIds[i]),flag); // } // // // Because which materials are on/off affects the // // geometry we need to remake the mesh cache // //this->RemakeDataCacheFlag = 1; // this->Modified(); // } } void vtkExodusIIReader::SetHierarchyArrayStatus(const char* vtkNotUsed(name), int vtkNotUsed(flag)) { //// Only modify if we are 'out of sync' ////if (this->GetHierarchyArrayStatus(name) != flag) ////{ // if (this->Metadata->Parser) // { // std::vector blocksIds=this->Metadata->Parser->GetBlocksForEntry // (vtkStdString(name)); // for (std::vector::size_type i=0;iMetadata->SetObjectStatus(vtkExodusIIReader::ELEM_BLOCK, // this->GetObjectIndex(ELEM_BLOCK,blocksIds[i]),flag); // } // // // Because which materials are on/off affects the // // geometry we need to remake the mesh cache // //this->RemakeDataCacheFlag = 1; // this->Modified(); // } } //------------------------------------------------------------------------------ int vtkExodusIIReader::GetHierarchyArrayStatus(int vtkNotUsed(index)) { // if (this->Metadata->Parser) // { // std::vector blocksIds=this->Metadata->Parser->GetBlocksForEntry(index); // for (std::vector::size_type i=0;iMetadata->GetObjectStatus(vtkExodusIIReader::ELEM_BLOCK, // this->GetObjectIndex(ELEM_BLOCK,blocksIds[i]))==0) // return 0; // } // } return 1; } //------------------------------------------------------------------------------ int vtkExodusIIReader::GetHierarchyArrayStatus(const char* vtkNotUsed(name)) { // if (this->Metadata->Parser) // { // std::vector blocksIds=this->Metadata->Parser->GetBlocksForEntry(name); // for (std::vector::size_type i=0;iMetadata->GetObjectStatus(vtkExodusIIReader::ELEM_BLOCK, // this->GetObjectIndex(ELEM_BLOCK,blocksIds[i]))==0) // return 0; // } // } return 1; } //------------------------------------------------------------------------------ vtkGraph* vtkExodusIIReader::GetSIL() { return this->Metadata->GetSIL(); } //------------------------------------------------------------------------------ void vtkExodusIIReader::SetDisplayType(int typ) { if (typ == this->DisplayType || typ < 0 || typ > 2) return; this->DisplayType = typ; this->Modified(); } //------------------------------------------------------------------------------ int vtkExodusIIReader::IsValidVariable(const char* type, const char* name) { return (this->GetVariableID(type, name) >= 0); } //------------------------------------------------------------------------------ int vtkExodusIIReader::GetVariableID(const char* type, const char* name) { int otyp = this->GetObjectTypeFromName(type); if (otyp < 0) { return 0; } switch (otyp) { case NODAL: case EDGE_BLOCK: case FACE_BLOCK: case ELEM_BLOCK: case NODE_SET: case EDGE_SET: case FACE_SET: case SIDE_SET: case ELEM_SET: return this->GetObjectArrayIndex(otyp, name); case ASSEMBLY: return this->GetAssemblyArrayID(name); case HIERARCHY: return -1; // FIXME: There is no this->GetHierarchyArrayID( name ) and it's not clear there // should be. case MATERIAL: return this->GetMaterialArrayID(name); case PART: return this->GetPartArrayID(name); default: return -1; } } int vtkExodusIIReader::GetTimeSeriesData( int ID, const char* vName, const char* vType, vtkFloatArray* result) { (void)ID; (void)vName; (void)vType; (void)result; return -1; } void vtkExodusIIReader::SetAllArrayStatus(int otyp, int status) { int numObj; int i; switch (otyp) { case EDGE_BLOCK_CONN: case FACE_BLOCK_CONN: case ELEM_BLOCK_ELEM_CONN: case NODE_SET_CONN: case EDGE_SET_CONN: case FACE_SET_CONN: case SIDE_SET_CONN: case ELEM_SET_CONN: { // Convert the "connectivity" type into an "object" type: int ctypidx = this->Metadata->GetConnTypeIndexFromConnType(otyp); int otypidx = conn_obj_idx_cvt[ctypidx]; otyp = obj_types[otypidx]; // Now set the status numObj = this->GetNumberOfObjects(otyp); for (i = 0; i < numObj; ++i) { this->SetObjectStatus(otyp, i, status); } } break; case NODAL: case GLOBAL: case EDGE_BLOCK: case FACE_BLOCK: case ELEM_BLOCK: case NODE_SET: case EDGE_SET: case FACE_SET: case SIDE_SET: case ELEM_SET: numObj = this->GetNumberOfObjectArrays(otyp); for (i = 0; i < numObj; ++i) { this->SetObjectArrayStatus(otyp, i, status); } break; // --------------------- case ASSEMBLY: numObj = this->GetNumberOfAssemblyArrays(); for (i = 0; i < numObj; ++i) { this->SetAssemblyArrayStatus(i, status); } VTK_FALLTHROUGH; case PART: numObj = this->GetNumberOfPartArrays(); for (i = 0; i < numObj; ++i) { this->SetPartArrayStatus(i, status); } VTK_FALLTHROUGH; case MATERIAL: numObj = this->GetNumberOfMaterialArrays(); for (i = 0; i < numObj; ++i) { this->SetMaterialArrayStatus(i, status); } VTK_FALLTHROUGH; case HIERARCHY: numObj = this->GetNumberOfHierarchyArrays(); for (i = 0; i < numObj; ++i) { this->SetHierarchyArrayStatus(i, status); } break; default: break; } } void vtkExodusIIReader::Dump() { vtkIndent indent; this->PrintSelf(cout, indent); } bool vtkExodusIIReader::FindXMLFile() { // If the XML filename exists and is newer than any existing parser (or there is no parser), // reread XML file. if ((this->Metadata->Parser && this->Metadata->Parser->GetMTime() < this->XMLFileNameMTime && this->XMLFileName) || (!Metadata->Parser)) { if (Metadata->Parser) { Metadata->Parser->Delete(); Metadata->Parser = nullptr; } if (!this->XMLFileName || !vtksys::SystemTools::FileExists(this->XMLFileName)) { if (this->FileName) { // Catch the case where filename was non-nullptr but didn't exist. this->SetXMLFileName(nullptr); } } else { return true; } } return false; } void vtkExodusIIReader::AdvertiseTimeSteps(vtkInformation* outInfo) { // This method is called in vtkExodusIIReader::RequestInformation() to update // information about timesteps. Since this gets called after this->Metadata // has processed the file meta-data it's a good place to update iVars that // reflect the meta-data read from the file about timesteps/mode shapes. int nTimes = static_cast(this->Metadata->Times.size()); this->TimeStepRange[0] = 0; this->TimeStepRange[1] = (nTimes > 0) ? (nTimes - 1) : 0; // Since modeshape range is 1 indexed. this->ModeShapesRange[0] = this->TimeStepRange[0] + 1; this->ModeShapesRange[1] = this->TimeStepRange[1] + 1; if (!this->GetHasModeShapes()) { if (this->GetIgnoreFileTime()) { std::vector times(nTimes); for (size_t i = 0; i < times.size(); ++i) { times[i] = i; } double timeRange[2]; timeRange[0] = 0; timeRange[1] = nTimes - 1; outInfo->Set(vtkStreamingDemandDrivenPipeline::TIME_STEPS(), ×[0], nTimes); outInfo->Set(vtkStreamingDemandDrivenPipeline::TIME_RANGE(), timeRange, 2); } else { if (nTimes) { double timeRange[2]; timeRange[0] = this->Metadata->Times[0]; timeRange[1] = this->Metadata->Times[nTimes - 1]; outInfo->Set( vtkStreamingDemandDrivenPipeline::TIME_STEPS(), &this->Metadata->Times[0], nTimes); outInfo->Set(vtkStreamingDemandDrivenPipeline::TIME_RANGE(), timeRange, 2); } } } else if (this->GetAnimateModeShapes()) { outInfo->Remove(vtkStreamingDemandDrivenPipeline::TIME_STEPS()); static double timeRange[] = { 0, 1 }; outInfo->Set(vtkStreamingDemandDrivenPipeline::TIME_RANGE(), timeRange, 2); } else { outInfo->Remove(vtkStreamingDemandDrivenPipeline::TIME_STEPS()); outInfo->Remove(vtkStreamingDemandDrivenPipeline::TIME_RANGE()); } } void vtkExodusIIReader::Reset() { this->Metadata->Reset(); this->Metadata->ResetSettings(); } void vtkExodusIIReader::ResetSettings() { this->Metadata->ResetSettings(); } void vtkExodusIIReader::SetCacheSize(double CacheSize) { this->Metadata->SetCacheSize(CacheSize); } double vtkExodusIIReader::GetCacheSize() { return this->Metadata->GetCacheSize(); } void vtkExodusIIReader::SetSqueezePoints(bool sp) { this->Metadata->SetSqueezePoints(sp ? 1 : 0); } bool vtkExodusIIReader::GetSqueezePoints() { return this->Metadata->GetSqueezePoints() != 0; } void vtkExodusIIReader::ResetCache() { this->Metadata->ResetCache(); }