Permalink
Find file
Fetching contributors…
Cannot retrieve contributors at this time
6690 lines (6076 sloc) 215 KB
/*=========================================================================
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 "vtkCellData.h"
#include "vtkCellType.h"
#include "vtkCharArray.h"
#include "vtkDoubleArray.h"
#include "vtkExodusModel.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 "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"
#ifdef VTK_USE_PARALLEL
# include "vtkMultiProcessController.h"
#endif // VTK_USE_PARALLEL
#include <vtkstd/algorithm>
#include <vtkstd/vector>
#include <vtkstd/map>
#include <vtkstd/set>
#include <vtkstd/deque>
#include <vtkstd/string>
#include "vtksys/SystemTools.hxx"
#include "vtksys/RegularExpression.hxx"
#include "vtkExodusII.h"
#include <stdio.h>
#include <stdlib.h> /* for free() */
#include <string.h> /* for memset() */
#include <ctype.h> /* for toupper(), isgraph() */
#include <math.h> /* for cos() */
#ifdef EXODUSII_HAVE_MALLOC_H
# include <malloc.h>
#endif /* EXODUSII_HAVE_MALLOC_H */
#if defined(_WIN32) && !defined(__CYGWIN__)
# define SNPRINTF _snprintf
#else
# define SNPRINTF snprintf
#endif
/// Define this to get printouts summarizing array glomming process
#undef VTK_DBG_GLOM
#define VTK_EXO_BLKSETID_NAME "BlockId"
#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",
0, /* maps have no result variables */
0,
0,
0,
"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"
// ----------------------------------------------------------- UTILITY ROUTINES
// This function exists because FORTRAN ordering sucks.
static void extractTruthForVar( int num_obj, int num_vars, const int* truth_tab, int var, vtkstd::vector<int>& 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->TimeStep = 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->EdgeFieldDecorations = 0;
this->FaceFieldDecorations = 0;
this->EdgeDecorationMesh = 0;
this->FaceDecorationMesh = 0;
this->Parser = 0;
this->FastPathObjectType = vtkExodusIIReader::NODAL;
this->FastPathIdType = NULL;
this->FastPathObjectId = -1;
this->SIL = vtkMutableDirectedGraph::New();
this->ProducedFastPathOutput = false;
memset( (void*)&this->ModelParameters, 0, sizeof(this->ModelParameters) );
}
//-----------------------------------------------------------------------------
vtkExodusIIReaderPrivate::~vtkExodusIIReaderPrivate()
{
this->CloseFile();
this->Cache->Delete();
this->ClearConnectivityCaches();
this->SetFastPathIdType( 0 );
if(this->Parser)
{
this->Parser->Delete();
this->Parser = 0;
}
this->SIL->Delete();
this->SIL = 0;
}
//-----------------------------------------------------------------------------
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 vtkstd::vector<vtkExodusIIReaderVariableCheck*> 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;
typedef vtkstd::vector<vtkExodusIIReaderPrivate::ArrayInfoType> varVec;
varVec arrays;
vtkstd::vector<int> 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<unsigned int>( (*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.
/*
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<BlockInfoType*>( bsinfop ) );
}
else if ( CONNTYPE_IS_SET(conntypidx) )
{
this->InsertSetCells( otyp, oidx, conn_types[conntypidx],
timeStep, static_cast<SetInfoType*>( 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 );
vtkstd::map<vtkIdType,vtkIdType>::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;
vtkstd::vector<ArrayInfoType>::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 )
{
vtkWarningMacro( "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;
}
// Panic if we're given a bad otyp.
vtkstd::map<int,vtkstd::vector<ArrayInfoType> >::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
}
vtkCellData* cd = output->GetCellData();
// 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.
vtkstd::vector<ArrayInfoType>::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 && ! 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 vtkNotUsed(timeStep), int otyp, int obj, BlockSetInfoType* bsinfop,
vtkUnstructuredGrid* output )
{
(void)obj;
vtkFieldData *ofieldData = output->GetFieldData();
int status = 1;
vtkstd::vector<ArrayInfoType>::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 )
{
vtkWarningMacro( "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 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);
}
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;
vtkstd::vector<MapInfoType>::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 = vtkIdTypeArray::SafeDownCast( this->GetCacheOrRead(
vtkExodusIICacheKey( -1, vtkExodusIIReader::NODE_MAP, 0, midx ) ) );
if ( !src )
{
vtkWarningMacro(
"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 );
vtkstd::map<int,vtkstd::vector<MapInfoType> >::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).
vtkstd::vector<MapInfoType>::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;
}
//-----------------------------------------------------------------------------
int vtkExodusIIReaderPrivate::AssembleArraysOverTime(vtkMultiBlockDataSet* output )
{
if ( this->FastPathObjectId < 0 )
{
// No downstream filter has requested temporal data from this reader.
return 0;
}
vtkstd::vector<ArrayInfoType>::iterator ai;
vtkFieldData* ofd = output->GetFieldData();
vtkIdType internalExodusId = -1;
int status = 1;
int aidx = 0;
int objId = -1;
// We need to get the internal id used by the exodus file from either the
// VTK index, or from the global id
if (strcmp( this->FastPathIdType, "GLOBAL" ) == 0)
{
vtkExodusIICacheKey globalIdMapKey;
switch ( this->FastPathObjectType )
{
case vtkExodusIIReader::NODAL:
globalIdMapKey =
vtkExodusIICacheKey( -1, vtkExodusIIReader::NODE_ID, 0, 0 );
break;
case vtkExodusIIReader::ELEM_BLOCK:
globalIdMapKey =
vtkExodusIICacheKey( -1, vtkExodusIIReader::ELEMENT_ID, 0, 0 );
break;
default:
vtkWarningMacro( "Unsupported object type for fast path." );
return 0;
}
vtkIdTypeArray* globalIdMap = vtkIdTypeArray::SafeDownCast(
this->GetCacheOrRead( globalIdMapKey ) );
if (!globalIdMap)
{
return 0;
}
vtkIdType index = globalIdMap->LookupValue(this->FastPathObjectId);
if (index >= 0)
{
internalExodusId = index + 1;
}
}
// This will happen if the data does not reside in this file
if (internalExodusId < 0)
{
//vtkWarningMacro( "Unable to map id to internal exodus id." );
return 0;
}
for (ai = this->ArrayInfo[this->FastPathObjectType].begin();
ai != this->ArrayInfo[this->FastPathObjectType].end(); ++ai, ++aidx)
{
if (! ai->Status)
{
continue; // Skip arrays we don't want.
}
// If this array isn't defined over the block that the element resides in,
// skip. Right now this is only done when the fast-path id type is "INDEX".
if ( objId >= 0 &&
this->FastPathObjectType == vtkExodusIIReader::ELEM_BLOCK &&
! strcmp( this->FastPathIdType, "INDEX" ) )
{
if ( ! ai->ObjectTruth[objId] )
{
continue;
}
}
vtkExodusIICacheKey temporalDataKey(
-1, this->GetTemporalTypeFromObjectType( this->FastPathObjectType ),
internalExodusId, aidx );
vtkDataArray* temporalData = this->GetCacheOrRead( temporalDataKey );
if ( !temporalData )
{
vtkWarningMacro( "Unable to read array " << ai->Name.c_str() );
status = 0;
continue;
}
ofd->AddArray(temporalData);
}
return status;
}
//-----------------------------------------------------------------------------
void vtkExodusIIReaderPrivate::AssembleOutputEdgeDecorations()
{
if ( this->EdgeFieldDecorations == vtkExodusIIReader::NONE )
{
// Do nothing if no decorations are requested.
return;
}
}
//-----------------------------------------------------------------------------
void vtkExodusIIReaderPrivate::AssembleOutputFaceDecorations()
{
if ( this->FaceFieldDecorations == vtkExodusIIReader::NONE )
{
// Do nothing if no decorations are requested.
return;
}
}
//-----------------------------------------------------------------------------
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 = 0;
if ( binfo->PointsPerCell == 0 )
{
int arrId;
if (conn_type == vtkExodusIIReader::ELEM_BLOCK_ELEM_CONN)
{
arrId = 0;
}
else
{
arrId = 1;
}
ent = vtkIntArray::SafeDownCast(
this->GetCacheOrRead( vtkExodusIICacheKey( -1, vtkExodusIIReader::ENTITY_COUNTS, obj, arrId ) ) );
if ( ! ent )
{
vtkErrorMacro( "Entity used 0 points per cell, but didn't return poly_hedra correctly" );
binfo->Status = 0;
return;
}
}
vtkIntArray* arr;
arr = vtkIntArray::SafeDownCast( this->GetCacheOrRead( vtkExodusIICacheKey( -1, conn_type, obj, 0 ) ) );
if ( ! arr )
{
vtkWarningMacro( "Block wasn't present in file? Working around it. Expect trouble." );
binfo->Status = 0;
return;
}
if ( this->SqueezePoints )
{
vtkstd::vector<vtkIdType> cellIds;
cellIds.resize( binfo->PointsPerCell );
int* srcIds = arr->GetPointer( 0 );
for ( int i = 0; i < binfo->Size; ++i )
{
int entitiesPerCell = binfo->PointsPerCell;
if ( ent != 0)
{
entitiesPerCell = ent->GetValue (i);
cellIds.resize( entitiesPerCell );
}
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
vtkstd::vector<vtkIdType> cellIds;
cellIds.resize( binfo->PointsPerCell );
int* srcIds = arr->GetPointer( 0 );
for ( int i = 0; i < binfo->Size; ++i )
{
int entitiesPerCell = binfo->PointsPerCell;
if ( ent != 0)
{
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
}
}
//-----------------------------------------------------------------------------
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 = vtkIntArray::SafeDownCast(
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 );
vtkstd::map<vtkIdType,vtkIdType>::iterator it;
for ( it = bsinfop->PointMap.begin(); it != bsinfop->PointMap.end(); ++ 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 = 0; //&this->BlockInfo[otyp][bnum];
int* nodeconn = 0;
vtkIdType* cellConn;
int nnpe = 0;
vtkIntArray* nconn;
vtkstd::vector<vtkIdType> 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 = vtkIntArray::SafeDownCast(
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;
vtkstd::vector<vtkIdType> 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 = 0;
}
else
{
arr = this->Cache->Find( key );
}
if ( arr )
{
//
return arr;
}
int exoid = this->Exoid;
// If array is NULL, 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( 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 = 0;
}
}
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<ex_entity_type>( 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 = 0;
}
}
else
{
// Exodus doesn't support reading with a stride, so we have to manually interleave the arrays. Bleh.
vtkstd::vector<vtkstd::vector<double> > 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<ex_entity_type>( 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 = 0;
return 0;
}
}
int t;
vtkstd::vector<double> tmpTuple;
tmpTuple.resize( ncomps );
tmpTuple[ncomps - 1] = 0.; // In case we're embedding a 2-D vector in 3-D
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.
vtkstd::vector<vtkstd::vector<double> > 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 = 0;
return 0;
}
}
int t;
vtkstd::vector<double> 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 = 0;
}
}
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 = 0;
}
}
else
{
// Exodus doesn't support reading with a stride, so we have to manually interleave the arrays. Bleh.
vtkstd::vector<vtkstd::vector<double> > 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 = 0;
return 0;
}
}
int t;
vtkstd::vector<double> 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 = 0;
}
}
else
{
// Exodus doesn't support reading with a stride, so we have to manually interleave the arrays. Bleh.
vtkstd::vector<vtkstd::vector<double> > 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 = 0;
return 0;
}
}
int t;
vtkstd::vector<double> 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<ex_entity_type>( 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 = 0;
}
}
else
{
// Exodus doesn't support reading with a stride, so we have to manually interleave the arrays. Bleh.
vtkstd::vector<vtkstd::vector<double> > 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<ex_entity_type>( 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 = 0;
}
}
// Carefully use arr->GetNumberOfComponents() when sizing
// output as we may have promoted 2-D arrays to 3-D.
int t = arr->GetNumberOfComponents();
vtkstd::vector<double> 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
{
vtkstd::vector<int> tmpMap( arr->GetNumberOfTuples() );
if ( ex_get_num_map( exoid, static_cast<ex_entity_type>( key.ObjectType ), minfop->Id, &tmpMap[0] ) < 0 )
{
vtkErrorMacro( "Could not read map \"" << minfop->Name.c_str() << "\" (" << minfop->Id << ") from disk." );
arr->Delete();
arr = 0;
return 0;
}
for ( vtkIdType i = 0; i < arr->GetNumberOfTuples(); ++i )
{
iarr->SetValue( i, tmpMap[i] );
}
}
#else
if ( ex_get_num_map( exoid, static_cast<ex_entity_type>( 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 = vtkIdTypeArray::SafeDownCast( this->GetCacheOrRead( ckey ) );
if ( ! src )
{
arr = 0;
return 0;
}
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
vtkstd::vector<int> tmpMap( src->GetNumberOfTuples() );
if ( ex_get_id_map( exoid, static_cast<ex_entity_type>( ckey.ObjectType ), &tmpMap[0] ) < 0 )
{
vtkErrorMacro( "Could not read elem num map for global implicit id" );
src->Delete();
return 0;
}
else
{
for ( vtkIdType i = 0; i < src->GetNumberOfTuples(); ++i )
{
src->SetValue( i, tmpMap[i] );
}
}
#else
if ( ex_get_id_map( exoid, static_cast<ex_entity_type>( 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 = vtkIdTypeArray::SafeDownCast(
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 );
vtkstd::map<vtkIdType,vtkIdType>::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
vtkstd::vector<int> 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 0;
}
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 );
vtkstd::map<vtkIdType,vtkIdType>::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 = vtkIdTypeArray::SafeDownCast(this->GetCacheOrRead( ktmp ))) )
{
iarr = vtkIdTypeArray::New();
iarr->SetNumberOfComponents( 1 );
iarr->SetNumberOfTuples( mapSize );
if ( mapSize )
{
#ifdef VTK_USE_64BIT_IDS
vtkstd::vector<int> tmpMap( iarr->GetNumberOfTuples() );
if ( ex_get_id_map( exoid, static_cast<ex_entity_type>( ktmp.ObjectType ), &tmpMap[0] ) < 0 )
{
vtkErrorMacro( "Could not read old-style node or element map." );
iarr->Delete();
iarr = 0;
}
else
{
for ( vtkIdType i = 0; i < iarr->GetNumberOfTuples(); ++i )
{
iarr->SetValue( i, tmpMap[i] );
}
}
#else
if ( ex_get_id_map( exoid, static_cast<ex_entity_type>( 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;
if (key.ArrayId == 0)
{
ctypidx = 0;
}
else
{
ctypidx = 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<ex_entity_type>( otyp ), binfop->Id,
iarr->GetPointer(0)) < 0 )
{
vtkErrorMacro( "Unable to read " << binfop->Id << " (index " << key.ObjectId <<
") entity count per polyhedra" );
iarr->Delete();
iarr = 0;
}
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
{
iarr->SetNumberOfComponents( binfop->BdsPerEntry[0] );
iarr->SetNumberOfTuples( binfop->Size );
}
if ( ex_get_conn( exoid, static_cast<ex_entity_type>( otyp ), binfop->Id, iarr->GetPointer(0), 0, 0 ) < 0 )
{
vtkErrorMacro( "Unable to read " << objtype_names[otypidx] << " " << binfop->Id << " (index " << key.ObjectId <<
") nodal connectivity." );
iarr->Delete();
iarr = 0;
}
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 if (binfop->CellType == VTK_POLYGON)
{
int arrId;
if (key.ObjectType == vtkExodusIIReader::ELEM_BLOCK_ELEM_CONN)
{
arrId = 0;
}
else
{
arrId = 1;
}
vtkIntArray* ent;
ent = vtkIntArray::SafeDownCast(
this->GetCacheOrRead(
vtkExodusIICacheKey( -1, vtkExodusIIReader::ENTITY_COUNTS,
key.ObjectId, arrId ) ) );
if ( ! ent )
{
vtkErrorMacro("Entity used 0 points per cell, but didn't return poly_hedra correctly");
iarr = 0;
}
else
{
// reverse each polygon's winding order.
for ( c = 0; c < binfop->Size; c ++ )
{
int *nptr = ptr + ent->GetValue (c);
int *eptr = nptr - 1;
while ( eptr >= ptr )
{
*eptr = *eptr - 1;
*ptr = *ptr - 1;
int tmp = *eptr;
*eptr = *ptr;
*ptr = tmp;
ptr ++;
eptr --;
}
ptr = nptr;
}
}
}
*/
else
{
for ( c = 0; c <= iarr->GetMaxId(); ++c, ++ptr )
{
*ptr = *ptr - 1;
}
}
arr = iarr;
}
else if ( key.ObjectType == vtkExodusIIReader::ELEM_BLOCK_FACE_CONN )
{
// FIXME: Call ex_get_conn with non-NULL face conn pointer
// This won't be needed until the Exodus reader outputs multiblock data with vtkGenericDataSet blocks for higher order meshes.
arr = 0;
}
else if ( key.ObjectType == vtkExodusIIReader::ELEM_BLOCK_EDGE_CONN )
{
// FIXME: Call ex_get_conn with non-NULL edge conn pointer
// This won't be needed until the Exodus reader outputs multiblock data with vtkGenericDataSet blocks for higher order meshes.
arr = 0;
}
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<ex_entity_type>( otyp ), sinfop->Id, iptr, 0 ) < 0 )
{
vtkErrorMacro( "Unable to read " << objtype_names[otypidx] << " " << sinfop->Id << " (index " << key.ObjectId <<
") nodal connectivity." );
iarr->Delete();
iarr = 0;
}
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 );
vtkstd::vector<int> tmpOrient; // hold the edge/face orientation information until we can interleave it.
tmpOrient.resize( sinfop->Size );
if ( ex_get_set( exoid, static_cast<ex_entity_type>( 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 = 0;
return 0;
}
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 )
{
// 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 = 0;
return 0;
}
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 = 0;
return 0;
}
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;
}
else if ( key.ObjectType == vtkExodusIIReader::NODAL_COORDS )
{
// read node coords
vtkDataArray* displ = 0;
if ( this->ApplyDisplacements && key.Time >= 0 )
{
displ = this->FindDisplacementVectors( key.Time );
}
vtkstd::vector<double> 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 = 0;
double* yc = 0;
double* zc = 0;
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 = 0;
break;
case 2:
zc = yc;
yc = 0;
break;
default:
vtkErrorMacro( "Bad coordinate index " << c << " when reading point coordinates." );
xc = yc = zc = 0;
}
if ( ex_get_coord( exoid, xc, yc, zc ) < 0 )
{
vtkErrorMacro( "Unable to read node coordinates for index " << c << "." );
arr->Delete();
arr = 0;
break;
}
double* cptr = darr->GetPointer( c );
for ( t = 0; 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.;
}
}
if ( displ )
{
double* coords = darr->GetPointer( 0 );
if ( this->HasModeShapes && this->AnimateModeShapes )
{
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 * cos( 2. * vtkMath::DoublePi() * this->ModeShapeTime );
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
)
{
BlockInfoType* binfop = &this->BlockInfo[key.ObjectType][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<ex_entity_type>( key.ObjectType ), key.ObjectId, key.ArrayId, 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 << "." );
arr->Delete();
arr = 0;
}
}
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 = 0;
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 = 0;
}
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 = 0;
}
else
{
for ( i = 0; i < num_info; ++i )
{
carr->InsertTupleValue( i, info[i] );
}
arr = carr;
}
for ( i = 0; i < num_info; ++i )
{
free(info[i]);
}
free(info);
}
else
{
carr->Delete();
arr = 0;
}
}
}
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 = 0;
int i,j;
vtkCharArray* carr = vtkCharArray::New();
carr->SetName( "QA_Records" );
carr->SetNumberOfComponents( MAX_STR_LENGTH + 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 = 0;
}
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( ( MAX_STR_LENGTH + 1 ), sizeof(char) );
}
}
if ( ex_get_qa( exoid, qa_record ) < 0 )
{
vtkErrorMacro( "Unable to read QA records from ex_get_qa");
carr->Delete();
arr = 0;
}
else
{
for ( i = 0; i < num_qa_rec; ++i )
{
for ( j = 0; j < 4 ; ++j )
{
carr->InsertTupleValue( ( 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 = 0;
}
}
}
else
{
vtkWarningMacro( "You requested an array for objects of type " << key.ObjectType <<
" which I know nothing about" );
arr = 0;
}
// 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 0;
}
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 0;
}
//-----------------------------------------------------------------------------
vtkExodusIIReaderPrivate::ObjectInfoType* vtkExodusIIReaderPrivate::GetSortedObjectInfo( int otyp, int k )
{
int i = this->GetObjectTypeIndexFromObjectType( otyp );
if ( i < 0 )
{
vtkWarningMacro( "Could not find collection of objects with type " << otyp << "." );
return 0;
}
int N = this->GetNumberOfObjectsAtTypeIndex( i );
if ( k < 0 || k >= N )
{
const char* otname = i >= 0 ? objtype_names[i] : "object";
vtkWarningMacro( "You requested " << otname << " " << k << " in a collection of only " << N << " objects." );
return 0;
}
return this->GetObjectInfo( i, this->SortedObjectIndices[otyp][k] );
}
//-----------------------------------------------------------------------------
vtkExodusIIReaderPrivate::ObjectInfoType* vtkExodusIIReaderPrivate::GetUnsortedObjectInfo( int otyp, int k )
{
int i = this->GetObjectTypeIndexFromObjectType( otyp );
if ( i < 0 )
{
vtkWarningMacro( "Could not find collection of objects with type " << otyp << "." );
return 0;
}
int N = this->GetNumberOfObjectsAtTypeIndex( i );
if ( k < 0 || k >= N )
{
const char* otname = i >= 0 ? objtype_names[i] : "object";
vtkWarningMacro( "You requested " << otname << " " << k << " in a collection of only " << N << " objects." );
return 0;
}
return this->GetObjectInfo( i, k );
}
//-----------------------------------------------------------------------------
int vtkExodusIIReaderPrivate::GetBlockIndexFromFileGlobalId( int otyp, int refId )
{
vtkstd::vector<BlockInfoType>::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 0;
}
//-----------------------------------------------------------------------------
vtkIdType vtkExodusIIReaderPrivate::GetSqueezePointId( BlockSetInfoType* bsinfop, int i )
{
if (i<0)
{
vtkGenericWarningMacro("Invalid point id: " << i
<< ". Data file may be incorrect.");
i = 0;
}
vtkIdType x;
vtkstd::map<vtkIdType,vtkIdType>::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; }
// 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" || elemType.substr(0,3) == "NFA")
{
binfo.CellType = VTK_POLYGON;
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,8) == "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 )
{
vtkstd::vector<ArrayInfoType>::iterator ai;
for ( ai = this->ArrayInfo[otyp].begin(); ai != this->ArrayInfo[otyp].end(); ++ai )
{
if ( ai->Name == name )
return &(*ai);
}
return 0;
}
//-----------------------------------------------------------------------------
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 i, j;
for (i=0; i<len; i++)
{
char *c = names[i];
int nmlen = (int)strlen(c);
char *cbegin = c;
char *cend = c + nmlen - 1;
// remove spaces or non-printing character from start and end
for (j=0; j<nmlen; j++)
{
if (!isgraph(*cbegin)) cbegin++;
else break;
}
for (j=0; j<nmlen; j++)
{
if (!isgraph(*cend)) cend--;
else break;
}
if (cend < cbegin)
{
sprintf(names[i], "null_%d", i);
continue;
}
int newlen = cend - cbegin + 1;
if (newlen < nmlen)
{
for (j=0; j<newlen; j++)
{
*c++ = *cbegin++;
}
*c = '\0';
}
}
}
//-----------------------------------------------------------------------------
void vtkExodusIIReaderPrivate::ClearConnectivityCaches()
{
vtkstd::map<int,vtkstd::vector<BlockInfoType> >::iterator blksit;
for ( blksit = this->BlockInfo.begin(); blksit != this->BlockInfo.end(); ++ blksit )
{
vtkstd::vector<BlockInfoType>::iterator blkit;
for ( blkit = blksit->second.begin(); blkit != blksit->second.end(); ++ blkit )
{
if ( blkit->CachedConnectivity )
{
blkit->CachedConnectivity->Delete();
blkit->CachedConnectivity = 0;
}
}
}
vtkstd::map<int,vtkstd::vector<SetInfoType> >::iterator setsit;
for ( setsit = this->SetInfo.begin(); setsit != this->SetInfo.end(); ++ setsit )
{
vtkstd::vector<SetInfoType>::iterator setit;
for ( setit = setsit->second.begin(); setit != setsit->second.end(); ++ setit )
{
if ( setit->CachedConnectivity )
{
setit->CachedConnectivity->Delete();
setit->CachedConnectivity = 0;
}
}
}
}
//-----------------------------------------------------------------------------
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<int>( 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;
vtkstd::vector<int> blkIndices = this->PartInfo[idx].BlockIndices;
for (unsigned int i=0;i<blkIndices.size();i++)
{
sprintf(buffer,"%d, ",blkIndices[i]);
blocks += buffer;
}
blocks.erase(blocks.size()-2,blocks.size()-1);
return blocks.c_str();
}
//-----------------------------------------------------------------------------
int vtkExodusIIReaderPrivate::GetPartStatus(int idx)
{
//a part is only active if all its blocks are active
vtkstd::vector<int> blkIndices = this->PartInfo[idx].BlockIndices;
for (unsigned int i=0;i<blkIndices.size();i++)
{
if (!this->GetUnsortedObjectStatus(vtkExodusIIReader::ELEM_BLOCK,blkIndices[i]))
{
return 0;
}
}
return 1;
}
//-----------------------------------------------------------------------------
int vtkExodusIIReaderPrivate::GetPartStatus(vtkStdString name)
{
for (unsigned int i=0;i<this->PartInfo.size();i++)
{
if (this->PartInfo[i].Name==name)
{
return this->GetPartStatus(i);
}
}
return -1;
}
//-----------------------------------------------------------------------------
void vtkExodusIIReaderPrivate::SetPartStatus(int idx, int on)
{
//update the block status for all the blocks in this part
vtkstd::vector<int> blkIndices = this->PartInfo[idx].BlockIndices;
for (unsigned int i=0;i<blkIndices.size();i++)
{
this->SetUnsortedObjectStatus(vtkExodusIIReader::ELEM_BLOCK, blkIndices[i], on);
}
}
//-----------------------------------------------------------------------------
void vtkExodusIIReaderPrivate::SetPartStatus(vtkStdString name, int flag)
{
for(unsigned int idx=0; idx<this->PartInfo.size(); ++idx)
{
if ( name == this->PartInfo[idx].Name )
{
this->SetPartStatus(idx,flag);
return;
}
}
}
//-----------------------------------------------------------------------------
int vtkExodusIIReaderPrivate::GetNumberOfMaterials()
{
return static_cast<int>( this->MaterialInfo.size() );
}
//-----------------------------------------------------------------------------
const char* vtkExodusIIReaderPrivate::GetMaterialName(int idx)
{
return this->MaterialInfo[idx].Name.c_str();
}
//-----------------------------------------------------------------------------
int vtkExodusIIReaderPrivate::GetMaterialStatus(int idx)
{
vtkstd::vector<int> blkIndices = this->MaterialInfo[idx].BlockIndices;
for (unsigned int i=0;i<blkIndices.size();i++)
{
if (!this->GetUnsortedObjectStatus(vtkExodusIIReader::ELEM_BLOCK,blkIndices[i]))
{
return 0;
}
}
return 1;
}
//-----------------------------------------------------------------------------
int vtkExodusIIReaderPrivate::GetMaterialStatus(vtkStdString name)
{
for (unsigned int i=0;i<this->MaterialInfo.size();i++)
{
if (this->MaterialInfo[i].Name==name)
{
return this->GetMaterialStatus(i);
}
}
return -1;
}
//-----------------------------------------------------------------------------
void vtkExodusIIReaderPrivate::SetMaterialStatus(int idx, int on)
{
//update the block status for all the blocks in this material
vtkstd::vector<int> blkIndices = this->MaterialInfo[idx].BlockIndices;
for (unsigned int i=0;i<blkIndices.size();i++)
{
this->SetUnsortedObjectStatus(vtkExodusIIReader::ELEM_BLOCK,blkIndices[i],on);
}
}
//-----------------------------------------------------------------------------
void vtkExodusIIReaderPrivate::SetMaterialStatus(vtkStdString name, int flag)
{
for(unsigned int idx=0; idx<this->MaterialInfo.size(); ++idx)
{
if ( name == this->MaterialInfo[idx].Name )
{
this->SetMaterialStatus(idx,flag);
return;
}
}
}
//-----------------------------------------------------------------------------
int vtkExodusIIReaderPrivate::GetNumberOfAssemblies()
{
return static_cast<int>( this->AssemblyInfo.size() );
}
//-----------------------------------------------------------------------------
const char* vtkExodusIIReaderPrivate::GetAssemblyName(int idx)
{
return this->AssemblyInfo[idx].Name.c_str();
}
//-----------------------------------------------------------------------------
int vtkExodusIIReaderPrivate::GetAssemblyStatus(int idx)
{
vtkstd::vector<int> blkIndices = this->AssemblyInfo[idx].BlockIndices;
for (unsigned int i=0;i<blkIndices.size();i++)
{
if (!this->GetUnsortedObjectStatus(vtkExodusIIReader::ELEM_BLOCK,blkIndices[i]))
{
return 0;
}
}
return 1;
}
//-----------------------------------------------------------------------------
int vtkExodusIIReaderPrivate::GetAssemblyStatus(vtkStdString name)
{
for (unsigned int i=0;i<this->AssemblyInfo.size();i++)
{
if (this->AssemblyInfo[i].Name==name)
{
return this->GetAssemblyStatus(i);
}
}
return -1;
}
//-----------------------------------------------------------------------------
void vtkExodusIIReaderPrivate::SetAssemblyStatus(int idx, int on)
{
vtkstd::vector<int> blkIndices = this->AssemblyInfo[idx].BlockIndices;
//update the block status for all the blocks in this material
for (unsigned int i=0;i<blkIndices.size();i++)
{
this->SetUnsortedObjectStatus(vtkExodusIIReader::ELEM_BLOCK,blkIndices[i],on);
}
}
//-----------------------------------------------------------------------------
void vtkExodusIIReaderPrivate::SetAssemblyStatus(vtkStdString name, int flag)
{
for(unsigned int idx=0; idx<this->AssemblyInfo.size(); ++idx)
{
if ( name == this->AssemblyInfo[idx].Name )
{
this->SetAssemblyStatus(idx,flag);
return;
}
}
}
//-----------------------------------------------------------------------------
// Normally, this would be below with all the other vtkExodusIIReader member definitions,
// but the 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 << "ExodusModelMetadata: " << (this->ExodusModelMetadata ? "ON" : "OFF" ) << "\n";
os << indent << "PackExodusModelOntoOutput: " << (this->PackExodusModelOntoOutput ? "ON" : "OFF" ) << "\n";
os << indent << "ExodusModel: " << this->ExodusModel << "\n";
os << indent << "SILUpdateStamp: " << this->SILUpdateStamp << "\n";
os << indent << "ProducedFastPathOutput: " << this->ProducedFastPathOutput << "\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 << "TimeStep: " << this->TimeStep << "\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 ].size() > 0 )
{
os << indent << "Nodal Arrays:\n";
vtkstd::vector<ArrayInfoType>::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";
vtkstd::map<int,vtkstd::vector<BlockInfoType> >::iterator bti;
for ( bti = this->BlockInfo.begin(); bti != this->BlockInfo.end(); ++bti )
{
vtkstd::vector<BlockInfoType>::iterator bi;
for ( bi = bti->second.begin(); bi != bti->second.end(); ++bi )
{
printBlock( os, indent.GetNextIndent(), bti->first, *bi );
}
if ( this->ArrayInfo[ bti->first ].size() > 0 )
{
os << indent << " Results variables:\n";
vtkstd::vector<ArrayInfoType>::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";
vtkstd::map<int,vtkstd::vector<SetInfoType> >::iterator sti;
for ( sti = this->SetInfo.begin(); sti != this->SetInfo.end(); ++sti )
{
vtkstd::vector<SetInfoType>::iterator si;
for ( si = sti->second.begin(); si != sti->second.end(); ++si )
{
printSet( os, indent.GetNextIndent(), sti->first, *si );
}
if ( this->ArrayInfo[ sti->first ].size() > 0 )
{
os << indent << " Results variables:\n";
vtkstd::vector<ArrayInfoType>::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";
vtkstd::map<int,vtkstd::vector<MapInfoType> >::iterator mti;
for ( mti = this->MapInfo.begin(); mti != this->MapInfo.end(); ++mti )
{
vtkstd::vector<MapInfoType>::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 NULL or pointed to an empty string." );
return 0;
}
if ( this->Exoid >= 0 )
{
this->CloseFile();
}
this->Exoid = ex_open( filename, EX_READ,
&this->AppWordSize, &this->DiskWordSize, &this->ExodusVersion );
if ( this->Exoid <= 0 )
{
vtkErrorMacro( "Unable to open \"" << filename << "\" for reading" );
return 0;
}
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()
{
int exoid = this->Exoid;
int itmp[5];
int num_timesteps;
VTK_EXO_FUNC( ex_inquire( exoid, EX_INQ_TIME, itmp, 0, 0 ), "Inquire for EX_INQ_TIME failed" );
num_timesteps = itmp[0];
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." );
}
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<vtkVariantArray> childEdge =
vtkSmartPointer<vtkVariantArray>::New();
childEdge->InsertNextValue(0);
vtkSmartPointer<vtkVariantArray> crossEdge =
vtkSmartPointer<vtkVariantArray>::New();
crossEdge->InsertNextValue(0);
// CrossEdge is an edge linking hierarchies.
vtkUnsignedCharArray* crossEdgesArray = vtkUnsignedCharArray::New();
crossEdgesArray->SetName("CrossEdges");
this->SIL->GetEdgeData()->AddArray(crossEdgesArray);
crossEdgesArray->Delete();
vtkstd::deque<vtkstd::string> names;
vtkstd::deque<vtkIdType> crossEdgeIds; // ids for edges between trees.
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.
vtkstd::map<vtkstd::string, vtkIdType> blockids;
int numBlocks = this->GetNumberOfObjectsOfType(vtkExodusIIReader::ELEM_BLOCK);
for (cc=0; cc < numBlocks; cc++)
{
vtkIdType child = this->SIL->AddChild(blocksRoot, childEdge);
vtkstd::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();
vtkstd::deque<vtkstd::string>::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 = 0;
char** var_names = 0;
int have_var_names;
int num_vars = 0; /* number of variables per object */
char tmpName[256];
tmpName[255] = '\0';
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];
vtkstd::vector<BlockInfoType> bitBlank;
vtkstd::vector<SetInfoType> sitBlank;
vtkstd::vector<MapInfoType> mitBlank;
vtkstd::vector<ArrayInfoType> aitBlank;
num_timesteps = static_cast<int>( 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;
vtkstd::map<int,int> sortedObjects;
int* truth_tab = 0;
have_var_names = 0;
VTK_EXO_FUNC( ex_inquire( exoid, obj_sizes[i], &nids, 0, 0 ), "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( (MAX_STR_LENGTH + 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( (MAX_STR_LENGTH + 1) * sizeof(char) );
obj_typenames[obj][0] = '\0';
}
}
}
else
{
ids = 0;
obj_names = 0;
obj_typenames = 0;
}
if ( nids == 0 && ! OBJTYPE_IS_MAP(i) )
continue;
if ( nids )
{
VTK_EXO_FUNC( ex_get_ids( exoid, static_cast<ex_entity_type>( 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<ex_entity_type>( 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]] = bitBlank;
this->BlockInfo[obj_types[i]].reserve( nids );
}
else if ( OBJTYPE_IS_SET(i) )
{
this->SetInfo[obj_types[i]] = sitBlank;
this->SetInfo[obj_types[i]].reserve( nids );
}
else
{
this->MapInfo[obj_types[i]] = mitBlank;
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( (MAX_STR_LENGTH + 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);
have_var_names = 1;
}
}
if ( !have_var_names)
var_names = 0;
for (obj = 0; obj < nids; ++obj)
{
if ( OBJTYPE_IS_BLOCK(i))
{
binfo.Name = obj_names[obj];
binfo.Id = ids[obj];
binfo.CachedConnectivity = 0;
binfo.NextSqueezePoint = 0;
if (obj_types[i] == vtkExodusIIReader::ELEM_BLOCK)
{
VTK_EXO_FUNC( ex_get_block( exoid, static_cast<ex_entity_type>( 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<ex_entity_type>( 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, 255, "Unnamed block ID: %d Type: %s Size: %d",
ids[obj], binfo.TypeName.length() ? binfo.TypeName.c_str() : "NULL", binfo.Size );
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( (MAX_STR_LENGTH + 1) * sizeof(char));
VTK_EXO_FUNC( ex_get_attr_names( exoid, static_cast<ex_entity_type>( 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<int>( 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;k<this->PartInfo.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<int>( this->PartInfo.size() );
// //binfo.PartId = k;
// pinfo.BlockIndices.push_back(blockIdx);
// this->PartInfo.push_back(pinfo);
// }
//
//found=0;
//for (k=0;k<this->MaterialInfo.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<int>( this->MaterialInfo.size() );
// //binfo.MaterialId = k;
// matinfo.BlockIndices.push_back(blockIdx);
// this->MaterialInfo.push_back(matinfo);
// }
//