/*========================================================================= 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 "vtkFloatArray.h" #include "vtkIdTypeArray.h" #include "vtkInformation.h" #include "vtkInformationVector.h" #include "vtkIntArray.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 "vtkSortDataArray.h" #include "vtkStdString.h" #include "vtkStreamingDemandDrivenPipeline.h" #include "vtkUnstructuredGrid.h" #include "vtkXMLParser.h" #include "vtkStringArray.h" #include "vtkUnsignedCharArray.h" #include "vtkVariantArray.h" #include "vtkSmartPointer.h" #include "vtkExodusIIReaderParser.h" #include #include #include #include #include #include #include "vtksys/SystemTools.hxx" #include "vtksys/RegularExpression.hxx" #include "vtk_exodusII.h" #include #include /* for free() */ #include /* for memset() */ #include /* for toupper(), isgraph() */ #include /* for cos() */ #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 int 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->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;iGetNumberOfTuples();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( this->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, vtkIntArray* 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; } vtkIntArray* ent = nullptr; 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; } ent->Register(this); } // 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) { vtkIntArray* efconn; efconn = vtkArrayDownCast( this->GetCacheOrRead( vtkExodusIICacheKey( -1, vtkExodusIIReader::ELEM_BLOCK_FACE_CONN, obj, 0 ))); if (efconn) efconn->Register(this); if (!efconn || !ent) { vtkWarningMacro( << "Element block (" << efconn << ") and " << "number of faces per poly (" << ent << ") arrays are both required. " << "Skipping block id " << binfo->Id << "; expect trouble." ); binfo->Status = 0; if (ent) ent->UnRegister(this); if (efconn) efconn->UnRegister(this); return; } this->InsertBlockPolyhedra(binfo, ent, efconn); efconn->UnRegister(this); ent->UnRegister(this); return; } vtkIntArray* arr; 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; if (ent) { ent->UnRegister(this); } return; } if (this->SqueezePoints) { std::vector cellIds; cellIds.resize( binfo->PointsPerCell ); int* 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 { #ifdef VTK_USE_64BIT_IDS std::vector cellIds; cellIds.resize( binfo->PointsPerCell ); int* srcIds = arr->GetPointer( 0 ); for ( int i = 0; i < binfo->Size; ++i ) { int entitiesPerCell = binfo->PointsPerCell; if ( ent != nullptr) { entitiesPerCell = ent->GetValue (i); cellIds.resize( entitiesPerCell ); } for ( int p = 0; p < entitiesPerCell; ++p ) { cellIds[p] = srcIds[p]; //cout << " " << srcIds[p]; } //cout << "\n"; binfo->CachedConnectivity->InsertNextCell( binfo->CellType, entitiesPerCell, &cellIds[0] ); srcIds += entitiesPerCell; } #else // VTK_USE_64BIT_IDS vtkIdType* srcIds = (vtkIdType*) arr->GetPointer( 0 ); for ( int i = 0; i < binfo->Size; ++i ) { int entitiesPerCell = binfo->PointsPerCell; if ( ent != 0) { 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"; } #endif // VTK_USE_64BIT_IDS } if (ent) { ent->UnRegister (this); } } //----------------------------------------------------------------------------- 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; } vtkIntArray* 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( vtkIntArray* 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; int* 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( vtkIntArray* 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; int* 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( vtkIntArray* 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; int* nodesPerSide = refs->GetPointer( 0 ); int* 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( this->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; } } 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; } } 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; } #ifdef VTK_USE_64BIT_IDS { std::vector tmpMap( arr->GetNumberOfTuples() ); if ( ex_get_num_map( exoid, static_cast( key.ObjectType ), minfop->Id, &tmpMap[0] ) < 0 ) { vtkErrorMacro( "Could not read map \"" << minfop->Name.c_str() << "\" (" << minfop->Id << ") from disk." ); arr->Delete(); arr = nullptr; return nullptr; } // // Move the check of maxTuples out of the for(;;) loop. // vtkIdType maxTuples = arr->GetNumberOfTuples(); for ( vtkIdType i = 0; i < maxTuples; ++i ) { iarr->SetValue( i, tmpMap[i] ); } } #else if ( ex_get_num_map( exoid, static_cast( key.ObjectType ), minfop->Id, (int*)arr->GetVoidPointer( 0 ) ) < 0 ) { vtkErrorMacro( "Could not read nodal map variable " << minfop->Name.c_str() << "." ); arr->Delete(); arr = 0; } #endif // VTK_USE_64BIT_IDS } 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 { #ifdef VTK_USE_64BIT_IDS std::vector tmpMap( src->GetNumberOfTuples() ); if ( ex_get_id_map( exoid, static_cast( ckey.ObjectType ), &tmpMap[0] ) < 0 ) { vtkErrorMacro( "Could not read elem num map for global implicit id" ); src->Delete(); return nullptr; } else { for ( vtkIdType i = 0; i < src->GetNumberOfTuples(); ++i ) { src->SetValue( i, tmpMap[i] ); } } #else if ( ex_get_id_map( exoid, static_cast( ckey.ObjectType ), (int*)src->GetPointer( 0 ) ) < 0 ) { vtkErrorMacro( "Could not read elem num map for global implicit id" ); src->Delete(); return 0; } #endif // VTK_USE_64BIT_IDS } 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 { #ifdef VTK_USE_64BIT_IDS std::vector tmpMap( src->GetNumberOfTuples() ); if ( ex_get_id_map( exoid, (ex_entity_type)( vtkExodusIIReader::NODE_MAP ), &tmpMap[0] ) < 0 ) { vtkErrorMacro( "Could not read node num map for global implicit id" ); src->Delete(); return nullptr; } else { for ( vtkIdType i = 0; i < src->GetNumberOfTuples(); ++i ) { src->SetValue( i, tmpMap[i] ); } } #else if ( ex_get_id_map( exoid, (ex_entity_type)( vtkExodusIIReader::NODE_MAP ), (int*)src->GetPointer( 0 ) ) < 0 ) { vtkErrorMacro( "Could not node node num map for global implicit id" ); src->Delete(); return 0; } #endif // VTK_USE_64BIT_IDS } 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 ) { #ifdef VTK_USE_64BIT_IDS std::vector tmpMap( iarr->GetNumberOfTuples() ); if ( ex_get_id_map( exoid, static_cast( ktmp.ObjectType ), &tmpMap[0] ) < 0 ) { vtkErrorMacro( "Could not read old-style node or element map." ); iarr->Delete(); iarr = nullptr; } else { // // Move getting the maxTuples from the for(;;) loop. // vtkIdType maxTuples = iarr->GetNumberOfTuples(); for ( vtkIdType i = 0; i < maxTuples ; ++i ) { iarr->SetValue( i, tmpMap[i] ); } } #else if ( ex_get_id_map( exoid, static_cast( ktmp.ObjectType ), (int*)iarr->GetPointer( 0 ) ) < 0 ) { vtkErrorMacro( "Could not read old-style node or element map." ); iarr->Delete(); iarr = 0; } #endif // VTK_USE_64BIT_IDS } } 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 ); vtkIntArray* iarr = vtkIntArray::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; int* 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 { 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) { vtkIntArray* iarr = vtkIntArray::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; int* 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]; vtkIntArray* iarr = vtkIntArray::New(); iarr->SetNumberOfComponents( 1 ); iarr->SetNumberOfTuples( sinfop->Size ); int* 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]; vtkIntArray* iarr = vtkIntArray::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; } int* 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]; int 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; } vtkIntArray* iarr = vtkIntArray::New(); vtkIdType ilen = ssnllen + sinfop->Size; iarr->SetNumberOfComponents( 1 ); iarr->SetNumberOfTuples( ilen ); int* 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;iSize;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( this->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. int 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. int 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[i][j] = (char *) calloc( ( maxNameLength + 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."); i = 0; } 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) == "WED") && (binfo.BdsPerEntry[0] == 15)) { binfo.CellType=VTK_QUADRATIC_WEDGE; binfo.PointsPerCell = 15; } 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 >::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 = this->PartInfo[idx].BlockIndices; for (unsigned int i=0;iGetUnsortedObjectStatus(vtkExodusIIReader::ELEM_BLOCK,blkIndices[i])) { return 0; } } return 1; } //----------------------------------------------------------------------------- int vtkExodusIIReaderPrivate::GetPartStatus(const vtkStdString& name) { for (unsigned int i=0;iPartInfo.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;iSetUnsortedObjectStatus(vtkExodusIIReader::ELEM_BLOCK, blkIndices[i], on); } } //----------------------------------------------------------------------------- void vtkExodusIIReaderPrivate::SetPartStatus(const vtkStdString& name, int flag) { for(unsigned int idx=0; idxPartInfo.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;iGetUnsortedObjectStatus(vtkExodusIIReader::ELEM_BLOCK,blkIndices[i])) { return 0; } } return 1; } //----------------------------------------------------------------------------- int vtkExodusIIReaderPrivate::GetMaterialStatus(const vtkStdString& name) { for (unsigned int i=0;iMaterialInfo.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;iSetUnsortedObjectStatus(vtkExodusIIReader::ELEM_BLOCK,blkIndices[i],on); } } //----------------------------------------------------------------------------- void vtkExodusIIReaderPrivate::SetMaterialStatus(const vtkStdString& name, int flag) { for(unsigned int idx=0; idxMaterialInfo.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;iGetUnsortedObjectStatus(vtkExodusIIReader::ELEM_BLOCK,blkIndices[i])) { return 0; } } return 1; } //----------------------------------------------------------------------------- int vtkExodusIIReaderPrivate::GetAssemblyStatus(const vtkStdString& name) { for (unsigned int i=0;iAssemblyInfo.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;iSetUnsortedObjectStatus(vtkExodusIIReader::ELEM_BLOCK,blkIndices[i],on); } } //----------------------------------------------------------------------------- void vtkExodusIIReaderPrivate::SetAssemblyStatus(const vtkStdString& name, int flag) { for(unsigned int idx=0; idxAssemblyInfo.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 Tcl 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 << "SILUpdateStamp: " << this->SILUpdateStamp << "\n"; if ( this->Metadata ) { os << indent << "Metadata:\n"; this->Metadata->PrintData( os, indent.GetNextIndent() ); } else { os << indent << "Metadata: (null)\n"; } } void vtkExodusIIReaderPrivate::PrintData( 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 ); // 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()); if ( this->Exoid <= 0 ) { vtkErrorMacro( "Unable to open \"" << filename << "\" for reading" ); return 0; } int 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; int 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) { 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.push_back("SIL"); // Add the ELEM_BLOCK subtree. vtkIdType blocksRoot = this->SIL->AddChild(rootId, childEdge); names.push_back("Blocks"); // Add the assembly subtree this->SIL->AddChild(rootId, childEdge); names.push_back("Assemblies"); // Add the materials subtree this->SIL->AddChild(rootId, childEdge); names.push_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]; int* ids; int 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 = (int*) malloc( nids * sizeof(int) ); 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) { snprintf( tmpName, sizeof(tmpName), "Unnamed block ID: %d Type: %s", ids[obj], binfo.TypeName.length() ? binfo.TypeName.c_str() : "nullptr"); 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.push_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), "Unnamed set ID: %d", 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), "Unnamed map ID: %d", 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; 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(); //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; 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"; // 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 ); ++nbl; } } 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() { 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; oidxInitialObjectInfo[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; } 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; } 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; int 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 = static_cast( nm.find( "ID: " ) ) ) != (int) vtkStdString::npos ) { idx += 4; idlen = 0; while(idx+idlen < static_cast(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; oidxInitialArrayInfo[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( int 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); 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->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 ) \ { \ size_t fnl = strlen( fname ) + 1; \ char* dst = new char[fnl]; \ const char* src = fname; \ this->propName = dst; \ do { *dst++ = *src++; } while ( --fnl ); \ } \ else \ { \ this->propName = 0; \ } void vtkExodusIIReader::SetFileName( const char* 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(); } } //---------------------------------------------------------------------------- int 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;cntrequestedTimeStep-steps[cnt])? steps[cnt]-requestedTimeStep: requestedTimeStep-steps[cnt]; if (minDist<0 || tdistTimeStep=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( int x ) { this->Metadata->SetGenerateObjectIdArray( x ); } int vtkExodusIIReader::GetGenerateObjectIdCellArray() { return this->Metadata->GetGenerateObjectIdArray(); } void vtkExodusIIReader::SetGenerateGlobalElementIdArray( int x ) { this->Metadata->SetGenerateGlobalElementIdArray( x ); } int vtkExodusIIReader::GetGenerateGlobalElementIdArray() { return this->Metadata->GetGenerateGlobalElementIdArray(); } void vtkExodusIIReader::SetGenerateGlobalNodeIdArray( int x ) { this->Metadata->SetGenerateGlobalNodeIdArray( x ); } int vtkExodusIIReader::GetGenerateGlobalNodeIdArray() { return this->Metadata->GetGenerateGlobalNodeIdArray(); } void vtkExodusIIReader::SetGenerateImplicitElementIdArray( int x ) { this->Metadata->SetGenerateImplicitElementIdArray( x ); } int vtkExodusIIReader::GetGenerateImplicitElementIdArray() { return this->Metadata->GetGenerateImplicitElementIdArray(); } void vtkExodusIIReader::SetGenerateImplicitNodeIdArray( int x ) { this->Metadata->SetGenerateImplicitNodeIdArray( x ); } int vtkExodusIIReader::GetGenerateImplicitNodeIdArray() { return this->Metadata->GetGenerateImplicitNodeIdArray(); } void vtkExodusIIReader::SetGenerateFileIdArray( int x ) { this->Metadata->SetGenerateFileIdArray( x ); } int 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( int d ) { this->Metadata->SetApplyDisplacements( d ); } int 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( int ms ) { this->Metadata->SetHasModeShapes(ms); } int 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(int flag) { this->Metadata->SetAnimateModeShapes(flag); } int vtkExodusIIReader::GetAnimateModeShapes() { return this->Metadata->GetAnimateModeShapes(); } 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 ) { this->Metadata->SetObjectStatus( objectType, objectIndex, status ); } void vtkExodusIIReader::SetObjectStatus( int objectType, const char* objectName, int 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 ); } } 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); size_t i = objectRealName.find(" Size: "); if(i!= vtkStdString::npos) { objectRealName.erase(i); } 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;iGetPartArrayName( 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;iGetAssemblyArrayName( 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 ) { vtkStdString baseName( vtksys::SystemTools::GetFilenameWithoutExtension( this->FileName ) ); vtkStdString xmlExt( baseName + ".xml" ); if ( vtksys::SystemTools::FileExists( xmlExt ) ) { this->SetXMLFileName( xmlExt.c_str() ); return true; } vtkStdString dartExt( baseName + ".dart" ); if ( vtksys::SystemTools::FileExists( dartExt ) ) { this->SetXMLFileName( dartExt.c_str() ); return true; } vtkStdString baseDir( vtksys::SystemTools::GetFilenamePath( this->FileName ) ); vtkStdString artifact( baseDir + "/artifact.dta" ); if ( vtksys::SystemTools::FileExists( artifact ) ) { this->SetXMLFileName( artifact.c_str() ); return true; } // 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() ) { double timeRange[2]; if ( nTimes ) { 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(); }