Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
branch: master
Fetching contributors…

Cannot retrieve contributors at this time

5454 lines (4787 sloc) 159.662 kb
/*=========================================================================
Program: Visualization Toolkit
Module: vtkExodusReader.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 "vtkExodusReader.h"
#include "vtkExodusModel.h"
#include "vtkCell.h"
#include "vtkCellData.h"
#include "vtkPointData.h"
#include "vtkFloatArray.h"
#include "vtkIdTypeArray.h"
#include "vtkInformation.h"
#include "vtkInformationDoubleVectorKey.h"
#include "vtkInformationVector.h"
#include "vtkIntArray.h"
#include "vtkMath.h"
#include "vtkObjectFactory.h"
#include "vtkStreamingDemandDrivenPipeline.h"
#include "vtkUnstructuredGrid.h"
#include "vtkXMLParser.h"
#include "vtkWarpVector.h"
#include "vtkDSPFilterDefinition.h"
#include <sys/stat.h>
#include <ctype.h>
#include "vtkExodusII.h"
#include <vtkstd/algorithm>
#include <vtkstd/string>
#include <vtkstd/vector>
#include <vtkstd/map>
#include <vtkstd/list>
#include "vtkStdString.h"
#include <math.h>
#define DEBUG 0
vtkStdString _blocks;
// vtkExodusMetadata is an internal helper class that
// manages the metadata associated with the point and cell
// arrays. This class uses stl
class vtkExodusMetadata
{
private:
int ArrayStatusInitValue[vtkExodusReader::NUM_ARRAY_TYPES];
// Field array stuff
vtkstd::vector<vtkStdString> pointArrayNames;
vtkstd::vector<int> pointArrayComponents;
vtkstd::vector<int> pointArrayStatus;
vtkstd::map<vtkStdString,int> pointArrayInitStatus;
vtkstd::vector<vtkStdString> cellArrayNames;
vtkstd::vector<int> cellArrayComponents;
vtkstd::vector<int> cellArrayStatus;
vtkstd::map<vtkStdString,int> cellArrayInitStatus;
int originalNumberOfPointArrays;
int originalNumberOfCellArrays;
// This is a cruddy hack... because we need to pass a
// char ** pointer to the exodus function
char **pointArrayRawBuffer;
char **cellArrayRawBuffer;
// Block stuff
vtkstd::vector<vtkStdString> blockNames;
vtkstd::vector<int> blockIds;
vtkstd::vector<int> blockStatus;
vtkstd::vector<int> numElementsInBlock;
vtkstd::map<vtkStdString,int> blockInitStatus;
// Node/Side set id stuff
// Store *Ids* for each node/side set
// Store *Size* for each node/side set
// Store number of *Distribution Factors** for each node/side set
// FIXME!!! since node/side set ids should be unique, should this
// be a 'set' instead of a 'vector'?
// FIXME!!! should we store side/edge type along with side set info?
vtkstd::vector<int> nodeSetId;
vtkstd::vector<int> nodeSetSize;
vtkstd::vector<int> nodeSetDistFact;
vtkstd::vector<int> nodeSetStatus;
vtkstd::vector<vtkStdString> nodeSetName;
vtkstd::map<vtkStdString,int> nodeSetInitStatus;
vtkstd::vector<int> sideSetId;
vtkstd::vector<int> sideSetSize;
vtkstd::vector<int> sideSetDistFact;
vtkstd::vector<int> sideSetStatus;
vtkstd::vector<vtkStdString> sideSetName;
vtkstd::map<vtkStdString,int> sideSetInitStatus;
//part stuff. There is no PartStatus array
//a part is active only if all its blocks are active
vtkstd::vector<vtkStdString> partNames;
vtkstd::map<int,int> blockIDToPartID;
vtkstd::map<int,vtkstd::vector<int> > partIDToBlockIDs;
//material stuff. Again, no material array
//a material is active only is all its blocks are active
vtkstd::vector<vtkStdString> materialNames;
vtkstd::map<int,int> blockIDToMaterialID;
vtkstd::map<int,vtkstd::vector<int> > materialIDToBlockIDs;
//assembly stuff
vtkstd::vector<vtkStdString> assemblyNames;
vtkstd::map<int,vtkstd::vector<int> > blockIDToAssemblyIDs;
vtkstd::map<int,vtkstd::vector<int> > assemblyIDToBlockIDs;
//sortedorder[sortedID]=unsortedID
//can do name[sortedOrder[idx]]
vtkstd::map<int,int> sortedOrder;
int DisplayType;
public:
// Constructor
vtkExodusMetadata()
{
pointArrayRawBuffer = NULL;
cellArrayRawBuffer = NULL;
originalNumberOfPointArrays = 0;
originalNumberOfCellArrays = 0;
DisplayType=1;
for ( int i=0;i<vtkExodusReader::NUM_ARRAY_TYPES;i++ )
{
this->ArrayStatusInitValue[i] = 0;
}
}
// Destructor
~vtkExodusMetadata()
{
int i;
for (i=0; i< this->originalNumberOfPointArrays; i++)
{
delete [] this->pointArrayRawBuffer[i];
}
if (this->pointArrayRawBuffer)
{
delete [] this->pointArrayRawBuffer;
}
for (i=0; i< this->originalNumberOfCellArrays; i++)
{
delete [] this->cellArrayRawBuffer[i];
}
if (this->cellArrayRawBuffer)
{
delete [] this->cellArrayRawBuffer;
}
}
// Point array attributes
char** AllocatePointArrayNameBuffer(int num_strings);
char** GetPointArrayNameBuffer();
char *GetPointArrayOriginalName(int i)
{
return pointArrayRawBuffer[i];
}
inline int GetNumberOfPointArrays()
{
return static_cast<int>( pointArrayNames.size() );
}
inline const char* GetPointArrayName(int idx)
{
return pointArrayNames[idx].c_str();
}
inline int GetPointArrayComponents(int idx)
{
return pointArrayComponents[idx];
}
inline int GetPointArrayStatus(int idx)
{
return pointArrayStatus[idx];
}
inline void SetPointArrayInitStatus(vtkStdString name, int on)
{
pointArrayInitStatus[name] = on;
}
inline void SetPointArrayStatus(int idx, int on)
{
pointArrayStatus[idx] = on;
}
inline void SetPointArrayStatus(vtkStdString name, int flag)
{
for(int idx=0; idx<this->GetNumberOfPointArrays(); ++idx)
{
if ( name == this->pointArrayNames[idx] )
{
this->pointArrayStatus[idx] = flag;
return;
}
}
}
inline int GetPointArrayStatus(vtkStdString name)
{
for(int idx=0; idx<this->GetNumberOfPointArrays(); ++idx)
{
if ( name == this->pointArrayNames[idx] )
return this->pointArrayStatus[idx];
}
return -1;
}
// Cell array attributes
char** AllocateCellArrayNameBuffer(int num_strings);
char** GetCellArrayNameBuffer();
char *GetCellArrayOriginalName(int i)
{
return cellArrayRawBuffer[i];
}
inline int GetNumberOfCellArrays()
{
return static_cast<int>( cellArrayNames.size() );
}
inline const char* GetCellArrayName(int idx)
{
return cellArrayNames[idx].c_str();
}
inline int GetCellArrayComponents(int idx)
{
return cellArrayComponents[idx];
}
inline void SetCellArrayInitStatus(vtkStdString name, int on)
{
cellArrayInitStatus[name] = on;
}
inline void SetCellArrayStatus(int idx, int flag)
{
cellArrayStatus[idx] = flag;
}
inline void SetCellArrayStatus(vtkStdString name, int flag)
{
for(int idx=0; idx<this->GetNumberOfCellArrays(); ++idx)
{
if ( name == this->cellArrayNames[idx] )
{
this->cellArrayStatus[idx] = flag;
return;
}
}
}
inline int GetCellArrayStatus(int idx)
{
return cellArrayStatus[idx];
}
inline int GetCellArrayStatus(vtkStdString name) {
for(int idx=0; idx<this->GetNumberOfCellArrays(); ++idx)
{
if ( name == this->cellArrayNames[idx] )
return this->cellArrayStatus[idx];
}
return -1;
}
// These are used when accessing things like truth tables indices
inline int GetOriginalNumberOfPointArrays()
{
return originalNumberOfPointArrays;
}
inline int GetOriginalNumberOfCellArrays()
{
return originalNumberOfCellArrays;
}
//-----------------------------------------------------------------------
// Node/Side set functions
//-----------------------------------------------------------------------
// id - node/side set exodus id
// size - node/side set size
// dist - number of distribution factors
// default node/side set status to 'of' or '0'
inline void AddNodeSet( vtkStdString name, const int id, const int size, const int dist, int status )
{
this->nodeSetId.push_back( id );
this->nodeSetName.push_back( name );
this->nodeSetSize.push_back( size );
this->nodeSetDistFact.push_back( dist );
this->nodeSetStatus.push_back( status );
}
inline void AddSideSet( vtkStdString name, const int id, const int size, const int dist, int status )
{
this->sideSetId.push_back( id );
this->sideSetName.push_back( name );
this->sideSetSize.push_back( size );
this->sideSetDistFact.push_back( dist );
this->sideSetStatus.push_back( status );
}
// Do a bound check and return a non-sensical -1 for a count if the user
// asks for a non-existent id. The return value is not an error value
// per se, but we have to return something instead of overrunning the
// array bounds
//
// FIXME!!! this is simply the number of node/side sets set by
// vtkExodusReader, it *could* be different than the number
// reported by the exodus file. since vtkExodusReader loads
// metadata for all node/side sets this *should* agree with
// the number reported by exodus. Status flags specify which
// node/side sets get loaded and visualized.
inline int GetNumberOfNodeSets() { return static_cast<int>( this->nodeSetId.size() ); }
inline int GetNumberOfSideSets() { return static_cast<int>( this->sideSetId.size() ); }
inline int GetNodeSetId( const int id )
{
return (id>=0 && id<(int)nodeSetId.size()) ? nodeSetId[id] : -1;
}
inline int GetSideSetId( const int id )
{
return (id>=0 && id<(int)sideSetId.size()) ? sideSetId[id] : -1;
}
inline const char* GetNodeSetName( const int id )
{
return nodeSetName[id].c_str();
}
inline const char* GetSideSetName( const int id )
{
return sideSetName[id].c_str();
}
inline int GetNodeSetSize( const int id )
{
return (id>=0 && id<(int)nodeSetSize.size()) ? nodeSetSize[id] : -1;
}
inline int GetSideSetSize( const int id )
{
return (id>=0 && id<(int)sideSetSize.size()) ? sideSetSize[id] : -1;
}
inline int GetNodeSetDistFact( const int id )
{
return (id>=0 && id<(int)nodeSetDistFact.size()) ? nodeSetDistFact[id] : -1;
}
inline int GetSideSetDistFact( const int id )
{
return (id>=0 && id<(int)sideSetDistFact.size()) ? sideSetDistFact[id] : -1;
}
inline int GetNodeSetInitStatus( vtkStdString name )
{
vtkstd::map<vtkStdString,int>::iterator i = nodeSetInitStatus.find(name);
if( i!= nodeSetInitStatus.end() )
{
return (*i).second;
}
else
{
return 0;
}
}
inline void SetNodeSetInitStatus( vtkStdString name, const int status )
{
this->nodeSetInitStatus[name] = status;
}
inline void SetNodeSetStatus( const int id, const int status )
{
if( id>=0 && id<(int)this->nodeSetStatus.size() )
{
this->nodeSetStatus[id] = status;
}
return;
}
inline void SetNodeSetStatus(vtkStdString name, int status)
{
for(vtkstd::vector<int>::size_type id=0; id < this->nodeSetStatus.size(); ++id)
{
if ( name == this->nodeSetName[id] )
{
this->SetNodeSetStatus(static_cast<int>(id),status);
return;
}
}
}
inline int GetSideSetInitStatus( vtkStdString name )
{
vtkstd::map<vtkStdString,int>::iterator i = sideSetInitStatus.find(name);
if( i!= sideSetInitStatus.end() )
{
return (*i).second;
}
else
{
return 0;
}
}
inline void SetSideSetInitStatus( vtkStdString name, const int status )
{
this->sideSetInitStatus[name] = status;
}
inline void SetSideSetStatus( const int id, const int status )
{
if( id>=0 && id<(int)this->sideSetStatus.size() )
{
this->sideSetStatus[id] = status;
}
return;
}
inline void SetSideSetStatus(vtkStdString name, int status)
{
for(vtkstd::vector<int>::size_type id=0; id < this->sideSetStatus.size(); ++id)
{
if ( name == this->sideSetName[id] )
{
this->SetSideSetStatus(static_cast<int>(id),status);
return;
}
}
}
// Return node/side set status if the id corresponds to a real node/side set.
// I the user asks for the status of a node/side set that doesn't exist, return
// zero and let the philosophers debate whether a node/side set that doesn't exist
// is on or off; that's at least 3 Phd thesies right there!
inline int GetNodeSetStatus(const int id )
{
return (id>=0 && id<(int)nodeSetStatus.size()) ? nodeSetStatus[id] : 0;
}
inline int GetNodeSetStatus(vtkStdString name)
{
for(vtkstd::vector<int>::size_type id=0; id < this->nodeSetStatus.size(); ++id)
{
if ( name == this->nodeSetName[id] )
{
return this->GetNodeSetStatus(static_cast<int>(id));
}
}
return 0;
}
inline int GetSideSetStatus( const int id )
{
return (id>=0 && id<(int)sideSetStatus.size()) ? sideSetStatus[id] : 0;
}
inline int GetSideSetStatus(vtkStdString name)
{
for(vtkstd::vector<int>::size_type id=0; id < this->sideSetStatus.size(); ++id)
{
if ( name == this->sideSetName[id] )
{
return this->GetSideSetStatus(static_cast<int>(id));
}
}
return 0;
}
//-----------------------------------------------------------------------
// End Node/Side set functions
//-----------------------------------------------------------------------
// Block attributes
inline void AddBlock(vtkStdString blockName, vtkStdString partName,
vtkStdString materialName,
vtkstd::vector<vtkStdString> localAssemblyNames,
int id, int num_elem, int status)
{
blockNames.push_back(blockName);
blockIds.push_back(id);
blockStatus.push_back(status);
numElementsInBlock.push_back(num_elem);
unsigned int i;
int found=0;
int blockID=static_cast<int>(blockNames.size())-1;
sortedOrder[blockID]=blockID;
//set up the Part Arrays
for (i=0;i<partNames.size();i++){
if (partNames[i]==partName)
{
blockIDToPartID[blockID]=i;
partIDToBlockIDs[i].push_back(blockID);
found=1;
}
}
if (!found)
{
int partID=static_cast<int>(partNames.size());
partNames.push_back(partName);
blockIDToPartID[blockID]=partID;
partIDToBlockIDs[partID]=vtkstd::vector<int>();
partIDToBlockIDs[partID].push_back(blockID);
}
//set up the material arrays
found=0;
for (i=0;i<materialNames.size();i++)
{
if (materialNames[i]==materialName)
{
blockIDToMaterialID[blockID]=i;
materialIDToBlockIDs[i].push_back(blockID);
found=1;
}
}
if (!found)
{
int materialID=static_cast<int>(materialNames.size());
materialNames.push_back(materialName);
blockIDToMaterialID[blockID]=materialID;
materialIDToBlockIDs[materialID]=vtkstd::vector<int>();
materialIDToBlockIDs[materialID].push_back(blockID);
}
//handle assembly stuff
for (i=0;i<localAssemblyNames.size();i++)
{
vtkStdString assemblyName=localAssemblyNames[i];
found=0;
for (vtkStdString::size_type j=0;j<assemblyNames.size();j++)
{
if (assemblyNames[j]==assemblyName){
blockIDToAssemblyIDs[blockID].push_back(static_cast<int>(j));
assemblyIDToBlockIDs[static_cast<int>(j)].push_back(blockID);
found=1;
}
}
if (!found)
{
int assemblyID=static_cast<int>(assemblyNames.size());
assemblyNames.push_back(assemblyName);
blockIDToAssemblyIDs[blockID]=vtkstd::vector<int>();
blockIDToAssemblyIDs[blockID].push_back(assemblyID);
assemblyIDToBlockIDs[assemblyID]=vtkstd::vector<int>();
assemblyIDToBlockIDs[assemblyID].push_back(blockID);
}
}
}
inline void ResetBlocks()
{
blockNames.erase(blockNames.begin(), blockNames.end());
blockIds.erase(blockIds.begin(), blockIds.end());
blockStatus.erase(blockStatus.begin(), blockStatus.end());
numElementsInBlock.erase(numElementsInBlock.begin(), numElementsInBlock.end());
partNames.erase(partNames.begin(),partNames.end());
materialNames.erase(materialNames.begin(),materialNames.end());
unsigned int i;
for (i=0;i<materialIDToBlockIDs.size();i++)
{
materialIDToBlockIDs[i].erase(materialIDToBlockIDs[i].begin(),
materialIDToBlockIDs[i].end());
}
materialIDToBlockIDs.erase(materialIDToBlockIDs.begin(),
materialIDToBlockIDs.end());
for (i=0;i<partIDToBlockIDs.size();i++)
{
partIDToBlockIDs[i].erase(partIDToBlockIDs[i].begin(),
partIDToBlockIDs[i].end());
}
for (i=0;i<assemblyIDToBlockIDs.size();i++)
{
assemblyIDToBlockIDs[i].erase(assemblyIDToBlockIDs[i].begin(),
assemblyIDToBlockIDs[i].end());
}
for (i=0;i<blockIDToAssemblyIDs.size();i++)
{
blockIDToAssemblyIDs[i].erase(blockIDToAssemblyIDs[i].begin(),
blockIDToAssemblyIDs[i].end());
}
partIDToBlockIDs.erase(partIDToBlockIDs.begin(),
partIDToBlockIDs.end());
blockIDToPartID.erase(blockIDToPartID.begin(),blockIDToPartID.end());
blockIDToMaterialID.erase(blockIDToMaterialID.begin(),
blockIDToMaterialID.end());
assemblyNames.erase(assemblyNames.begin(),assemblyNames.end());
blockIDToAssemblyIDs.erase(
blockIDToAssemblyIDs.begin(),blockIDToAssemblyIDs.end());
assemblyIDToBlockIDs.erase(
assemblyIDToBlockIDs.begin(),assemblyIDToBlockIDs.end());
sortedOrder.erase(sortedOrder.begin(),sortedOrder.end());
}
inline void SetDisplayType(int type)
{
DisplayType=type;
}
inline int GetNumberOfBlocks()
{
return static_cast<int>(blockNames.size());
}
inline int GetSortedOrder(int idx)
{
return sortedOrder[idx];
}
inline const char* GetBlockName(int idx)
{
return blockNames[sortedOrder[idx]].c_str();
}
inline int GetBlockId(int idx)
{
return blockIds[sortedOrder[idx]];
}
inline int GetNumElementsInBlock(int idx)
{
return numElementsInBlock[sortedOrder[idx]];
}
inline void SetBlockInitStatus( vtkStdString name, const int status )
{
this->blockInitStatus[name] = status;
}
inline int GetBlockInitStatus( vtkStdString name )
{
vtkstd::map<vtkStdString,int>::iterator i = blockInitStatus.find(name);
if( i!= blockInitStatus.end() )
{
return (*i).second;
}
else
{
return 1;
}
}
inline void SetBlockStatus(int idx, int flag)
{
blockStatus[sortedOrder[idx]] = flag;
}
inline void SetBlockStatus(vtkStdString name, int flag)
{
for(int idx=0; idx<this->GetNumberOfBlocks(); ++idx)
{
if ( name == this->blockNames[idx] )
{
this->blockStatus[idx] = flag;
return;
}
}
}
inline void SetUnsortedBlockStatus(int idx, int flag)
{
if (idx >= 0 && static_cast<int>(blockStatus.size()) > idx)
{
blockStatus[idx] = flag;
}
}
inline int GetUnsortedBlockStatus(int idx)
{
if (idx >= 0 && static_cast<int>(blockStatus.size()) > idx)
{
return blockStatus[idx];
}
return 0;
}
inline int GetBlockStatus(int idx)
{
return blockStatus[sortedOrder[idx]];
}
inline int GetBlockStatus(vtkStdString name)
{
for(int idx=0; idx<this->GetNumberOfBlocks(); ++idx)
{
if ( name == this->blockNames[idx] )
return this->blockStatus[idx];
}
return -1;
}
//Parts and Materials need to act directly on the
//blockStatus array. Otherwise the index is put through
//the sortedOrder array, which gives us garbage since we have a
//valid index already
inline int GetNumberOfParts()
{
return static_cast<int>(partNames.size());
}
inline const char* GetPartName(int idx)
{
return partNames[idx].c_str();
}
inline const char* GetPartBlockInfo(int idx)
{
_blocks.erase();
char buffer[80];
for (unsigned int i=0;i<partIDToBlockIDs[idx].size();i++)
{
sprintf(buffer,"%d, ",blockIds[partIDToBlockIDs[idx][i]]);
_blocks += buffer;
}
_blocks.erase(_blocks.size()-2,_blocks.size()-1);
return _blocks.c_str();
}
inline int GetPartStatus(int idx)
{
//a part is only active if all its blocks are active
for (unsigned int i=0;i<partIDToBlockIDs[idx].size();i++)
{
if (!blockStatus[partIDToBlockIDs[idx][i]])
{
return 0;
}
}
return 1;
}
inline int GetPartStatus(vtkStdString name)
{
for (unsigned int i=0;i<partNames.size();i++)
{
if (partNames[i]==name)
{
return GetPartStatus(i);
}
}
return -1;
}
inline void SetPartStatus(int idx, int on)
{
//update the block status for all the blocks in this part
for (unsigned int i=0;i<partIDToBlockIDs[idx].size();i++)
{
this->blockStatus[partIDToBlockIDs[idx][i]]=on;
}
}
inline void SetPartStatus(vtkStdString name, int flag)
{
for(int idx=0; idx<this->GetNumberOfParts(); ++idx)
{
if ( name == this->partNames[idx] )
{
this->SetPartStatus(idx,flag);
return;
}
}
}
inline int GetNumberOfMaterials()
{
return static_cast<int>(materialNames.size());
}
inline const char* GetMaterialName(int idx)
{
return materialNames[idx].c_str();
}
inline int GetMaterialStatus(int idx)
{
for (unsigned int i=0;i<materialIDToBlockIDs[idx].size();i++)
{
if (!blockStatus[materialIDToBlockIDs[idx][i]])
{
return 0;
}
}
return 1;
}
inline int GetMaterialStatus(vtkStdString name)
{
for (unsigned int i=0;i<materialNames.size();i++)
{
if (materialNames[i]==name)
{
return GetMaterialStatus(i);
}
}
return -1;
}
inline void SetMaterialStatus(int idx, int on)
{
//update the block status for all the blocks in this material
for (unsigned int i=0;i<materialIDToBlockIDs[idx].size();i++)
{
this->blockStatus[materialIDToBlockIDs[idx][i]]=on;
}
}
inline void SetMaterialStatus(vtkStdString name, int flag)
{
for(int idx=0; idx<this->GetNumberOfMaterials(); ++idx)
{
if ( name == this->materialNames[idx] )
{
this->SetMaterialStatus(idx,flag);
return;
}
}
}
//Assembly stuff
inline int GetNumberOfAssemblies()
{
return static_cast<int>(assemblyNames.size());
}
inline const char* GetAssemblyName(int idx)
{
return assemblyNames[idx].c_str();
}
inline int GetAssemblyStatus(int idx)
{
for (unsigned int i=0;i<assemblyIDToBlockIDs[idx].size();i++)
{
if (!blockStatus[assemblyIDToBlockIDs[idx][i]])
{
return 0;
}
}
return 1;
}
inline int GetAssemblyStatus(vtkStdString name)
{
for (unsigned int i=0;i<assemblyNames.size();i++)
{
if (assemblyNames[i]==name)
{
return GetAssemblyStatus(i);
}
}
return -1;
}
inline void SetAssemblyStatus(int idx, int on)
{
//update the block status for all the blocks in this material
for (unsigned int i=0;i<assemblyIDToBlockIDs[idx].size();i++)
{
this->blockStatus[assemblyIDToBlockIDs[idx][i]]=on;
}
}
inline void SetAssemblyStatus(vtkStdString name, int flag)
{
for(int idx=0; idx<this->GetNumberOfAssemblies(); ++idx)
{
if ( name == this->assemblyNames[idx] )
{
this->SetAssemblyStatus(idx,flag);
return;
}
}
}
//performs a mapping from the exodus block ID to the block ID used by
//Set/GetUnsortedBlockStatus
inline int GetBlockIndex(int exodusID)
{
for (vtkstd::vector<int>::size_type i=0;i<blockIds.size();i++)
{
if (exodusID==blockIds[i])
{
return static_cast<int>(i);
}
}
return -1;
}
// This method is important to call when your done setting metadata
void Finalize();
//BTX
static int VectorizeArrays(
int numOriginalNames, char **originalNames,
vtkstd::vector<vtkStdString> *newNames, vtkstd::vector<int> *newSize);
//ETX
void SortBlocks()
{
int i;
for (i=static_cast<int>(blockIds.size())-1;i>=0;i--)
{
for (int j=1;j<=i;j++)
{
if (blockIds[sortedOrder[j-1]]>blockIds[sortedOrder[j]])
{
int t=sortedOrder[j-1];
sortedOrder[j-1]=sortedOrder[j];
sortedOrder[j]=t;
}
}
}
}
void SetArrayStatusInitValue( vtkExodusReader::ArrayType type, int value )
{
this->ArrayStatusInitValue[type] = value;
}
int GetArrayStatusInitValue( vtkExodusReader::ArrayType type )
{
return this->ArrayStatusInitValue[type];
}
};
class vtkExodusXMLParser: public vtkXMLParser
{
private:
vtkstd::map<vtkStdString,vtkStdString> MaterialSpecifications;
vtkstd::map<vtkStdString,vtkStdString> MaterialDescriptions;
vtkstd::map<vtkStdString,vtkStdString> PartDescriptions;
vtkstd::vector<vtkStdString> MaterialNames;
vtkstd::vector<vtkStdString> BlockNames;
vtkStdString PartNumber;
vtkStdString InstanceNumber;
int ParseMaterials;
vtkstd::map<int,vtkStdString> BlockIDToPartNumber;
vtkstd::map<vtkStdString,vtkstd::vector<vtkStdString> > PartNumberToAssemblyNumbers;
vtkstd::map<vtkStdString,vtkstd::vector<vtkStdString> > PartNumberToAssemblyDescriptions;
vtkstd::map<vtkStdString,vtkStdString> AssemblyDescriptions;
vtkstd::vector<vtkStdString> CurrentAssemblyNumbers;
vtkstd::vector<vtkStdString> CurrentAssemblyDescriptions;
//mappings for as-tested materials
vtkstd::map<vtkStdString,vtkStdString> MaterialSpecificationsBlocks; //maps material name to spec
vtkstd::map<vtkStdString,vtkStdString> MaterialDescriptionsBlocks; //maps material name to desc
vtkstd::map<int,vtkStdString> BlockIDToMaterial; //maps block id to material
//hierarchical list mappings
vtkstd::list<vtkStdString> apbList;
vtkstd::map<vtkStdString,vtkstd::vector<int> > apbToBlocks;
vtkstd::map<vtkStdString,int> apbIndents;
public:
vtkTypeMacro(vtkExodusXMLParser,vtkXMLParser);
static vtkExodusXMLParser* New();
// Description:
// Parse the XML input.
virtual int Parse(const char* inputString)
{
return this->Superclass::Parse(inputString);
}
virtual int Parse(const char* inputString, unsigned int length)
{
return this->Superclass::Parse(inputString, length);
}
virtual int Parse()
{
int retVal = this->Superclass::Parse();
this->PartNumber="";
this->InstanceNumber="";
this->ParseMaterials=0;
return retVal;
}
virtual vtkStdString GetPartNumber(int block)
{
return this->BlockIDToPartNumber[block];
}
virtual vtkStdString GetPartDescription(int block)
{
return this->PartDescriptions[this->BlockIDToPartNumber[block]];
}
virtual vtkStdString GetMaterialDescription(int block)
{
return this->MaterialDescriptions[this->BlockIDToPartNumber[block]];
}
virtual vtkStdString GetMaterialSpecification(int block)
{
return this->MaterialSpecifications[this->BlockIDToPartNumber[block]];
}
virtual vtkstd::vector<vtkStdString> GetAssemblyNumbers(int block)
{
return this->PartNumberToAssemblyNumbers[this->BlockIDToPartNumber[block]];
}
virtual vtkstd::vector<vtkStdString> GetAssemblyDescriptions(int block)
{
return this->PartNumberToAssemblyDescriptions[this->BlockIDToPartNumber[block]];
}
virtual int GetNumberOfHierarchyEntries()
{
return static_cast<int>(this->apbList.size());
}
virtual vtkStdString GetHierarchyEntry(int num)
{
//since it's an STL list, we need to get the correct entry
vtkstd::list<vtkStdString>::iterator iter=this->apbList.begin();
for(int i=0;i<num;i++)
{
iter++;
}
return (*iter);
}
virtual vtkstd::vector<int> GetBlocksForEntry(int num)
{
return this->apbToBlocks[this->GetHierarchyEntry(num)];
}
virtual vtkstd::vector<int> GetBlocksForEntry(vtkStdString entry)
{
return this->apbToBlocks[entry];
}
protected:
vtkExodusXMLParser()
{
this->FileName = 0;
this->PartNumber="";
this->InstanceNumber="";
this->ParseMaterials=0;
}
virtual ~vtkExodusXMLParser()
{
this->SetFileName(0);
}
virtual void StartElement(const char* tname, const char** attrs)
{
const char* name=strrchr(tname,':');
if (!name)
{
name=tname;
}
else
{
name++;
}
// ***********Assembly
if (strcmp(name,"assembly")==0)
{
const char* assemblyNumber=this->GetValue("number",attrs);
if (assemblyNumber)
{
this->CurrentAssemblyNumbers.push_back(vtkStdString(assemblyNumber));
}
const char* assemblyDescription=this->GetValue("description",attrs);
if (assemblyDescription)
{
this->CurrentAssemblyDescriptions.push_back(vtkStdString(assemblyDescription));
}
//make the entry for the hierarchical list
vtkStdString result=vtkStdString("");
for (vtkstd::vector<int>::size_type i=0;
i<this->CurrentAssemblyNumbers.size()-1;
i++)
{
result+=vtkStdString(" ");
}
result+=vtkStdString("Assembly: ")+
assemblyDescription+vtkStdString(" (")+
assemblyNumber+vtkStdString(")");
apbList.push_back(result);
//record the indent level, used when we add blocks
apbIndents[result]=static_cast<int>(this->CurrentAssemblyNumbers.size())-1;
//make the blocks array
apbToBlocks[result]=vtkstd::vector<int>();
}
// ***********Part
if (strcmp(name,"part")==0)
{
const char* instance=this->GetValue("instance",attrs);
vtkStdString instanceString=vtkStdString("");
if (instance)
{
instanceString=vtkStdString(instance);
}
const char* partString=this->GetValue("number",attrs);
if (partString)
{
this->PartNumber=vtkStdString(partString)+
vtkStdString(" Instance: ")+
instanceString;
}
const char* partDescString=this->GetValue("description",attrs);
if (partDescString && this->PartNumber!="")
{
this->PartDescriptions[this->PartNumber]=
partDescString;
}
//copy the current assemblies to the assemblies list for this part.
this->PartNumberToAssemblyNumbers[this->PartNumber]=
vtkstd::vector<vtkStdString>(this->CurrentAssemblyNumbers);
this->PartNumberToAssemblyDescriptions[this->PartNumber]=
vtkstd::vector<vtkStdString>(this->CurrentAssemblyDescriptions);
//make the hierarchical display entry
vtkStdString result=vtkStdString("");
for (vtkstd::vector<int>::size_type i=0;
i<this->CurrentAssemblyNumbers.size();
i++)
{
result+=vtkStdString(" ");
}
result+=vtkStdString("Part: ")+
partDescString+vtkStdString(" (")+
partString+vtkStdString(")")+vtkStdString(" Instance: ")+
instanceString;
apbList.push_back(result);
//record the indent level
apbIndents[result]=static_cast<int>(this->CurrentAssemblyNumbers.size());
apbToBlocks[result]=vtkstd::vector<int>();
}
// ***********Material-specification
else if (strcmp(name,"material-specification")==0)
{
if (this->PartNumber!="")
{
const char * materialDescriptionString=
GetValue("description",attrs);
if (materialDescriptionString)
{
this->MaterialDescriptions[this->PartNumber]=
vtkStdString(materialDescriptionString);
}
const char * materialSpecificationString=
GetValue("specification",attrs);
if (materialSpecificationString)
{
this->MaterialSpecifications[this->PartNumber]=
vtkStdString(materialSpecificationString);
}
}
}
// *********** blocks
else if (strcmp(name,"blocks")==0)
{
const char* instance=this->GetValue("part-instance",attrs);
vtkStdString instanceString=vtkStdString("");
if (instance)
{
this->InstanceNumber=vtkStdString(instance);
}
const char* partString=this->GetValue("part-number",attrs);
if (partString)
{
this->PartNumber=vtkStdString(partString);
}
}
// *********** block
else if (strcmp(name,"block")==0)
{
const char* blockString=this->GetValue("id",attrs);
int id=-1;
if (blockString)
{
id=atoi(blockString);
}
if (this->PartNumber!="" && id>=0)
{
this->BlockIDToPartNumber[id]=this->PartNumber+
vtkStdString(" Instance: ")+this->InstanceNumber;
//first insert block entry into apblist
vtkStdString apbIndexString=this->PartNumber+
vtkStdString(") Instance: ")+this->InstanceNumber;
vtkStdString partEntry=findEntry(this->apbList,apbIndexString);
vtkStdString blockEntry=vtkStdString("");
if (partEntry!=vtkStdString(""))
{
//insert into apbList
vtkstd::list<vtkStdString>::iterator pos=
vtkstd::find(this->apbList.begin(),this->apbList.end(),partEntry);
pos++;
vtkStdString result=vtkStdString("");
for (int i=0;i<apbIndents[partEntry]+1;i++)
{
result+=vtkStdString(" ");
}
result+=vtkStdString("Block: ")+vtkStdString(blockString);
blockEntry=result;
this->apbList.insert(pos,result);
apbToBlocks[result]=vtkstd::vector<int>();
}
if (partEntry!=vtkStdString("") && blockEntry!=vtkStdString(""))
{
//update mapping
//we know block number, so can get part number to update that.
//using part number, we can update assembly mappings
vtkStdString partIndexString=this->PartNumber+
vtkStdString(" Instance: ")+this->InstanceNumber;
//we know the part entry
//add block ID to block entry
apbToBlocks[blockEntry].push_back(id);
//add block ID to part
apbToBlocks[partEntry].push_back(id);
//get the assemblies
vtkstd::vector<vtkStdString> assemblies=
this->PartNumberToAssemblyNumbers[partIndexString];
//add block ID to assemblies
for (vtkstd::vector<vtkStdString>::size_type j=0;j<assemblies.size();j++)
{
vtkStdString assemblyEntry=findEntry(this->apbList,assemblies[j]);
apbToBlocks[assemblyEntry].push_back(id);
}
}
}
//parse material information if this block tag is part of a
//material-assignments tag
if (this->ParseMaterials==1 && id>=0)
{
const char* tmaterialName=this->GetValue("material-name",attrs);
if (tmaterialName)
{
this->BlockIDToMaterial[id]=vtkStdString(tmaterialName);
}
}
}
// ***********Material-assignments
else if (strcmp(name,"material-assignments")==0 )
{
this->ParseMaterials=1;
}
// ***********Material
else if (strcmp(name,"material")==0 )
{
const char* material=this->GetValue("name",attrs);
const char* spec=this->GetValue("specification",attrs);
const char* desc=this->GetValue("description",attrs);
if (material && spec)
{
this->MaterialSpecificationsBlocks[vtkStdString(material)]=vtkStdString(spec);
}
if (material && desc)
{
this->MaterialDescriptionsBlocks[vtkStdString(material)]=vtkStdString(desc);
}
}
}
//returns the first string that contains sstring
virtual vtkStdString findEntry(vtkstd::list<vtkStdString> slist,
vtkStdString sstring){
for (vtkstd::list<vtkStdString>::iterator i=slist.begin();
i!=slist.end();
i++)
{
if ((*i).find(sstring)!=vtkStdString::npos)
{
return (*i);
}
}
return vtkStdString("");
}
virtual void EndElement(const char* tname)
{
const char* name=strrchr(tname,':');
if (!name)
{
name=tname;
}
else
{
name++;
}
if (strcmp(name,"assembly")==0)
{
this->CurrentAssemblyNumbers.pop_back();
this->CurrentAssemblyDescriptions.pop_back();
}
else if (strcmp(name,"blocks")==0)
{
this->PartNumber="";
}
else if (strcmp(name,"material-assignments")==0)
{
this->ParseMaterials=0;
}
}
virtual int ParsingComplete()
{
//if we have as-tested materials, overwrite MaterialDescriptions
//and MaterialSpecifications
if (this->BlockIDToMaterial.size()>0)
{
this->MaterialSpecifications.clear();
this->MaterialDescriptions.clear();
for (vtkstd::map<int,vtkStdString>::iterator i=this->BlockIDToPartNumber.begin();i!=this->BlockIDToPartNumber.end();i++)
{
int blockID=(*i).first;
this->MaterialSpecifications[this->BlockIDToPartNumber[blockID]]=
this->MaterialSpecificationsBlocks[this->BlockIDToMaterial[blockID]];
this->MaterialDescriptions[this->BlockIDToPartNumber[blockID]]=
this->MaterialDescriptionsBlocks[this->BlockIDToMaterial[blockID]];
}
}
//if we have no assembly information, we need to generate a bunch
//of items from the BlockIDToPartNumber array
if (this->apbList.size()==0)
{
for (vtkstd::map<int,vtkStdString>::iterator i=this->BlockIDToPartNumber.begin();i!=this->BlockIDToPartNumber.end();i++)
{
int id=(*i).first;
vtkStdString part=(*i).second;
vtkStdString partSpec=vtkStdString("");
vtkStdString instance=vtkStdString("");
//get part spec and instance from part
int pos=static_cast<int>(part.find(" Instance: "));
if (pos!=(int)vtkStdString::npos)
{
partSpec.assign(part,0,pos);
instance.assign(part,pos+11,part.size()-(pos+11));
}
this->PartDescriptions[part]=vtkStdString("None");
//convert id to a string
char buffer[20];
sprintf(buffer,"%d",id);
//find the Part entry in the apbList
vtkStdString apbPartEntry=vtkStdString("Part: None (")+partSpec+vtkStdString(") Instance: ")+instance;
vtkStdString apbBlockEntry=vtkStdString(" ")+vtkStdString("Block: ")+vtkStdString(buffer);
vtkStdString foundEntry=this->findEntry(this->apbList,apbPartEntry);
if (foundEntry==vtkStdString(""))
{
this->apbList.push_back(apbPartEntry);
this->apbToBlocks[apbPartEntry]=vtkstd::vector<int>();
this->apbToBlocks[apbPartEntry].push_back(id);
this->AssemblyDescriptions[apbPartEntry]=vtkStdString("None");
}
//insert into apbList
vtkstd::list<vtkStdString>::iterator positer=
vtkstd::find(this->apbList.begin(),this->apbList.end(),apbPartEntry);
positer++;
this->apbList.insert(positer,apbBlockEntry);
this->apbToBlocks[apbBlockEntry]=vtkstd::vector<int>();
this->apbToBlocks[apbBlockEntry].push_back(id);
}
}
return vtkXMLParser::ParsingComplete();
}
virtual const char* GetValue(const char* attr,const char** attrs)
{
int i;
for (i=0;attrs[i];i+=2)
{
const char* name=strrchr(attrs[i],':');
if (!name)
{
name=attrs[i];
}
else
{
name++;
}
if (strcmp(attr,name)==0)
{
return attrs[i+1];
}
}
return NULL;
}
private:
vtkExodusXMLParser(const vtkExodusXMLParser&); // Not implemented
void operator=(const vtkExodusXMLParser&); // Not implemented
};
vtkStandardNewMacro(vtkExodusXMLParser);
// This is a cruddy hack... because we need to pass a
// char ** pointer to the exodus function
char** vtkExodusMetadata::GetPointArrayNameBuffer()
{
return this->pointArrayRawBuffer;
}
char** vtkExodusMetadata::AllocatePointArrayNameBuffer(int num_strings)
{
int idx;
if (this->pointArrayRawBuffer)
{
for (idx = 0; idx < this->originalNumberOfPointArrays; ++idx)
{
delete [] this->pointArrayRawBuffer[idx];
}
delete [] this->pointArrayRawBuffer;
this->pointArrayRawBuffer = NULL;
this->originalNumberOfPointArrays = 0;
}
if (num_strings > 0)
{
this->originalNumberOfPointArrays = num_strings;
this->pointArrayRawBuffer = new char*[num_strings];
for (idx = 0; idx < num_strings; ++idx)
{
this->pointArrayRawBuffer[idx] = new char[MAX_STR_LENGTH+1];
}
}
return this->pointArrayRawBuffer;
}
char** vtkExodusMetadata::GetCellArrayNameBuffer()
{
return this->cellArrayRawBuffer;
}
char** vtkExodusMetadata::AllocateCellArrayNameBuffer(int num_strings)
{
int idx;
if (this->cellArrayRawBuffer)
{
for (idx = 0; idx < this->originalNumberOfCellArrays; ++idx)
{
delete [] this->cellArrayRawBuffer[idx];
}
delete [] this->cellArrayRawBuffer;
this->cellArrayRawBuffer = NULL;
this->originalNumberOfCellArrays = 0;
}
if (num_strings > 0)
{
this->originalNumberOfCellArrays = num_strings;
this->cellArrayRawBuffer = new char*[num_strings];
for (idx = 0; idx < num_strings; ++idx)
{
this->cellArrayRawBuffer[idx] = new char[MAX_STR_LENGTH+1];
}
}
return this->cellArrayRawBuffer;
}
int vtkExodusMetadata::VectorizeArrays(
int numOriginalNames, char **originalNames,
vtkstd::vector<vtkStdString> *newNames, vtkstd::vector<int> *newSize)
{
newNames->erase(newNames->begin(),newNames->end());
newSize->erase(newSize->begin(),newSize->end());
// Go through names and combine any vectors
//
// namex )
// namey )-> name
// namez )
int idx = 0;
while (idx < numOriginalNames)
{
int len = static_cast<int>(strlen(originalNames[idx]));
char last_char = toupper(originalNames[idx][len-1]);
char *newName = vtkExodusReader::StrDupWithNew(originalNames[idx]);
int nextIdx = idx + 1;
if (last_char=='X')
{
if ((nextIdx < numOriginalNames) &&
(toupper(originalNames[nextIdx][len-1])=='Y') &&
!(strncmp(newName, originalNames[nextIdx], len-1)))
{
nextIdx++;
newName[len-1] = '\0';
if ((nextIdx < numOriginalNames) &&
(toupper(originalNames[nextIdx][len-1])=='Z') &&
!(strncmp(newName, originalNames[nextIdx], len-1)))
{
nextIdx++;
}
}
}
int numComponents = nextIdx - idx;
newNames->push_back(newName);
delete []newName;
newSize->push_back(numComponents);
idx = nextIdx;
}
return static_cast<int>(newNames->size());
}
void vtkExodusMetadata::Finalize()
{
int i;
vtkstd::map<vtkStdString,int>::iterator iter;
////////////////////////////////
// Point Arrays
////////////////////////////////
int numNewArrays = vtkExodusMetadata::VectorizeArrays(
originalNumberOfPointArrays, pointArrayRawBuffer,
&pointArrayNames, &pointArrayComponents);
pointArrayStatus.erase(pointArrayStatus.begin(), pointArrayStatus.end());
for (i=0; i<numNewArrays; i++)
{
pointArrayStatus.push_back(
this->GetArrayStatusInitValue( vtkExodusReader::POINT ) );
}
// Check to see if any initial values have been set for this array
for (iter=pointArrayInitStatus.begin();iter!=pointArrayInitStatus.end();iter++)
{
this->SetPointArrayStatus((*iter).first,(*iter).second);
}
// Delete the values when we're done
pointArrayInitStatus.erase(pointArrayInitStatus.begin(),pointArrayInitStatus.end());
////////////////////////////////
// Cell Arrays
////////////////////////////////
numNewArrays = vtkExodusMetadata::VectorizeArrays(
originalNumberOfCellArrays, cellArrayRawBuffer,
&cellArrayNames, &cellArrayComponents);
cellArrayStatus.erase(cellArrayStatus.begin(), cellArrayStatus.end());
for (i=0; i<numNewArrays; i++)
{
cellArrayStatus.push_back(
this->GetArrayStatusInitValue( vtkExodusReader::CELL ) );
}
// Check to see if any initial values have been set for this array
for (iter=cellArrayInitStatus.begin();iter!=cellArrayInitStatus.end();iter++)
{
this->SetCellArrayStatus((*iter).first,(*iter).second);
}
// Delete the values when we're done:
cellArrayInitStatus.erase(cellArrayInitStatus.begin(),cellArrayInitStatus.end());
this->SortBlocks();
}
vtkStandardNewMacro(vtkExodusReader);
#ifdef ARRAY_TYPE_NAMES_IN_CXX_FILE
const char *ArrayTypeNames[vtkExodusReader::NUM_ARRAY_TYPES] = {
"CELL",
"POINT",
"BLOCK",
"PART",
"MATERIAL",
"ASSEMBLY",
"HIERARCHY"
};
const char *
vtkExodusReader::GetArrayTypeName( vtkExodusReader::ArrayType type )
{
return ArrayTypeNames[ type ];
}
#else // method in .h file
const char *vtkExodusReader::ArrayTypeNames[NUM_ARRAY_TYPES] = {
"CELL",
"POINT",
"BLOCK",
"PART",
"MATERIAL",
"ASSEMBLY",
"HIERARCHY"
};
#endif
// Helper function
int vtkExodusReaderFileExist(const char *file_name)
{
struct stat fs;
if (file_name)
{
return (stat(file_name, &fs) != -1);
}
else
{
return 0;
}
}
// Description:
// Determine if the file can be readed with this reader.
int vtkExodusReader::CanReadFile(const char* fname)
{
// First see if the file exists at all
if (vtkExodusReaderFileExist(fname) == 0)
{
return 0;
}
// Okay now see if it's really an exodus file
int returnVal = ex_open( fname, EX_READ,
&(this->ExodusCPUWordSize),
&(this->ExodusIOWordSize),
&(this->ExodusVersion));
// Failure
if (returnVal < 0)
{
return 0;
}
// close the file opened for testing.
ex_close(returnVal);
// Success
return 1;
}
//----------------------------------------------------------------------------
// Description:
// Instantiate object with NULL filename.
vtkExodusReader::vtkExodusReader()
{
this->FileName = NULL;
this->XMLFileName=NULL;
this->TimeStep = 0;
this->ActualTimeStep = 0;
this->TimeSteps = 0;
this->GenerateBlockIdCellArray = 1;
this->GenerateGlobalElementIdArray = 1;
this->GenerateGlobalNodeIdArray = 1;
this->ApplyDisplacements = 1;
this->DisplacementMagnitude = 1;
this->Title = new char[MAX_LINE_LENGTH+1];
this->Title[0] = (char)'\0';
this->Dimensionality = 0;
this->NumberOfUsedElements = 0;
this->NumberOfElementsInFile = 0;
this->NumberOfBlocks = 0;
this->NumberOfUsedNodes = 0;
this->NumberOfNodesInFile = 0;
this->NumberOfNodeSets = 0;
this->NumberOfSideSets = 0;
this->NumberOfTimeSteps = 0;
this->ExodusCPUWordSize = 0;
this->ExodusIOWordSize = 0;
this->ExodusVersion = 0.0;
this->CurrentHandle = -1;
this->CurrentFileName = NULL;
this->CurrentXMLFileName = NULL;
this->TimeStepRange[0] = 0;
this->TimeStepRange[1] = 0;
this->DataCache = vtkUnstructuredGrid::New();
this->MetaData = new vtkExodusMetadata;
this->RemakeDataCacheFlag = 1;
this->NewGeometryCount = 0;
this->CellVarTruthTable = vtkIntArray::New();
this->PointMap = vtkIntArray::New();
this->ReversePointMap = vtkIntArray::New();
this->HasModeShapes = 0;
this->ExodusModel = NULL;
this->ExodusModelMetadata = 0;
this->PackExodusModelOntoOutput = 1;
this->DisplayType=1;
this->Parser=NULL;
this->GlobalElementIdCache=NULL;
//begin USE_EXO_DSP_FILTERS
this->DSPFilteringIsEnabled=0;
this->DSPFilters=NULL;
this->AddingFilter = vtkDSPFilterDefinition::New();
//end USE_EXO_DSP_FILTERS
this->ProgressOffset = 0.0;
this->ProgressScale = 1.0;
this->SetNumberOfInputPorts(0);
}
//----------------------------------------------------------------------------
vtkExodusReader::~vtkExodusReader()
{
this->SetFileName(NULL);
this->SetXMLFileName(NULL);
this->SetCurrentXMLFileName(NULL);
this->SetTitle(NULL);
this->SetCurrentFileName(NULL);
this->DataCache->Delete();
this->DataCache = NULL;
this->CellVarTruthTable->Delete();
this->CellVarTruthTable = NULL;
this->PointMap->Delete();
this->PointMap = NULL;
this->ReversePointMap->Delete();
this->ReversePointMap = NULL;
if (this->ExodusModel)
{
this->ExodusModel->Delete();
this->ExodusModel = NULL;
}
this->SetGlobalElementIdCache(NULL);
//begin USE_EXO_DSP_FILTERS
if(this->DSPFilters)
{
for(int i=0;i<this->GetNumberOfBlockArrays();i++)
{
this->DSPFilters[i]->Delete();
}
delete[] this->DSPFilters ;
this->DSPFilters=NULL;
}
//end USE_EXO_DSP_FILTERS
if (this->Parser)
{
this->Parser->Delete();
this->Parser=NULL;
}
delete this->MetaData;
//begin USE_EXO_DSP_FILTERS
if (this->AddingFilter)
{
this->AddingFilter->Delete();
}
//end USE_EXO_DSP_FILTERS
if (this->TimeSteps)
{
delete [] this->TimeSteps;
this->TimeSteps = 0;
this->NumberOfTimeSteps = 0;
}
}
void vtkExodusReader::NewExodusModel()
{
// These arrays are required by vtkExodusIIWriter
this->GenerateBlockIdCellArrayOn();
this->GenerateGlobalElementIdArrayOn();
this->GenerateGlobalNodeIdArrayOn();
if (this->ExodusModel)
{
this->ExodusModel->Reset();
return;
}
this->ExodusModel = vtkExodusModel::New();
}
void vtkExodusReader::SetGlobalElementIdCache(int *list)
{
if (this->GlobalElementIdCache)
{
delete [] this->GlobalElementIdCache;
this->GlobalElementIdCache = NULL;
}
if (list)
{
this->GlobalElementIdCache = list;
}
}
// Point array info accessors
int vtkExodusReader::GetNumberOfPointArrays()
{
return this->MetaData->GetNumberOfPointArrays();
}
const char* vtkExodusReader::GetPointArrayName(int arrayIdx)
{
return this->MetaData->GetPointArrayName(arrayIdx);
}
int vtkExodusReader::GetPointArrayNumberOfComponents(int arrayIdx)
{
return this->MetaData->GetPointArrayComponents(arrayIdx);
}
void vtkExodusReader::SetPointArrayStatus(int index, int flag)
{
int n = this->MetaData->GetOriginalNumberOfPointArrays();
if ((index >= 0) && (index < n))
{
this->MetaData->SetPointArrayStatus(index, flag);
this->Modified();
}
}
void vtkExodusReader::SetPointArrayStatus(const char* name, int flag)
{
if(this->MetaData->GetNumberOfPointArrays()==0)
{
// The point array status is being set before the meta data has been finalized
// so cache this value for later and use as the initial value
// If the number of arrays really is zero then this doesn't do any harm.
this->MetaData->SetPointArrayInitStatus(name, flag);
}
this->MetaData->SetPointArrayStatus(name, flag);
this->Modified();
}
int vtkExodusReader::GetPointArrayStatus(int index)
{
int n = this->MetaData->GetOriginalNumberOfPointArrays();
if ((index >= 0) && (index < n))
{
return this->MetaData->GetPointArrayStatus(index);
}
return 0;
}
int vtkExodusReader::GetPointArrayStatus(const char* name)
{
return this->MetaData->GetPointArrayStatus(name);
}
// Cell array info accessors
int vtkExodusReader::GetNumberOfCellArrays()
{
return this->MetaData->GetNumberOfCellArrays();
}
const char* vtkExodusReader::GetCellArrayName(int arrayIdx)
{
return this->MetaData->GetCellArrayName(arrayIdx);
}
int vtkExodusReader::GetCellArrayNumberOfComponents(int arrayIdx)
{
return this->MetaData->GetCellArrayComponents(arrayIdx);
}
void vtkExodusReader::SetCellArrayStatus(int index, int flag)
{
int n = this->MetaData->GetOriginalNumberOfCellArrays();
if ((index >= 0) && (index < n))
{
this->MetaData->SetCellArrayStatus(index, flag);
this->Modified();
}
}
void vtkExodusReader::SetCellArrayStatus(const char* name, int flag)
{
if(this->MetaData->GetNumberOfCellArrays()==0)
{
// The cell array status is being set before the meta data has been finalized
// so cache this value for later and use as the initial value
// If the number of arrays really is zero then this doesn't do any harm.
this->MetaData->SetCellArrayInitStatus(name, flag);
}
this->MetaData->SetCellArrayStatus(name, flag);
this->Modified();
}
int vtkExodusReader::GetCellArrayStatus(int index)
{
int n = this->MetaData->GetOriginalNumberOfCellArrays();
if ((index >= 0) && (index < n))
{
return this->MetaData->GetCellArrayStatus(index);
}
return 0;
}
int vtkExodusReader::GetCellArrayStatus(const char* name)
{
return this->MetaData->GetCellArrayStatus(name);
}
// Block info accessors
int vtkExodusReader::GetNumberOfBlockArrays()
{
return this->MetaData->GetNumberOfBlocks();
}
const char* vtkExodusReader::GetBlockArrayName(int arrayIdx)
{
return this->MetaData->GetBlockName(arrayIdx);
}
void vtkExodusReader::SetBlockArrayStatus(int index, int flag)
{
// Only modify if we are 'out of sync'
//cout << "called SetBlockArrayStatus " << index << endl;
if (this->MetaData->GetBlockStatus(index) != flag)
{
this->MetaData->SetBlockStatus(index, flag);
// Because which blocks are on/off affects the
// geometry we need to remake the mesh cache
this->RemakeDataCacheFlag = 1;
this->Modified();
}
}
void vtkExodusReader::SetBlockArrayStatus(const char* name, int flag)
{
if(this->MetaData->GetNumberOfBlocks()==0)
{
// The value is being set before the metadata has been finalized
// So store for later and use as the initial value if needed
this->MetaData->SetBlockInitStatus(name,flag);
}
// Only modify if we are 'out of sync'
if (this->MetaData->GetBlockStatus(name) != flag)
{
this->MetaData->SetBlockStatus(name, flag);
// Because which blocks are on/off affects the
// geometry we need to remake the mesh cache
this->RemakeDataCacheFlag = 1;
this->Modified();
}
}
int vtkExodusReader::GetBlockArrayStatus(int index)
{
return this->MetaData->GetBlockStatus(index);
}
int vtkExodusReader::GetBlockArrayStatus(const char* name)
{
return this->MetaData->GetBlockStatus(name);
}
int vtkExodusReader::GetNumberOfElementsInBlock(int block_idx)
{
return this->MetaData->GetNumElementsInBlock(block_idx);
}
//----------------------------
// Node/Side set accessors
//----------------------------
void vtkExodusReader::SetNodeSetArrayStatus(int index, int flag)
{
// Only modify if we are 'out of sync'
if (this->MetaData->GetNodeSetStatus(index) != flag)
{
this->MetaData->SetNodeSetStatus(index, flag);
// Because which node sets are on/off affects the
// geometry we need to remake the mesh cache
this->RemakeDataCacheFlag = 1;
this->Modified();
}
}
void vtkExodusReader::SetNodeSetArrayStatus(const char* name, int flag)
{
if(this->MetaData->GetNumberOfNodeSets()==0)
{
// The value is being set before the metadata has been finalized
// So store for later and use as the initial value if needed
this->MetaData->SetNodeSetInitStatus(name,flag);
}
// Only modify if we are 'out of sync'
if (this->MetaData->GetNodeSetStatus(name) != flag)
{
this->MetaData->SetNodeSetStatus(name, flag);
// Because which node sets are on/off affects the
// geometry we need to remake the mesh cache
this->RemakeDataCacheFlag = 1;
this->Modified();
}
}
int vtkExodusReader::GetNodeSetArrayStatus(int index )
{
return this->MetaData->GetNodeSetStatus( index );
}
int vtkExodusReader::GetNodeSetArrayStatus(const char* name )
{
return this->MetaData->GetNodeSetStatus( name );
}
const char* vtkExodusReader::GetNodeSetArrayName(int index)
{
return this->MetaData->GetNodeSetName(index);
}
void vtkExodusReader::SetSideSetArrayStatus(int index, int flag)
{
// Only modify if we are 'out of sync'
if (this->MetaData->GetSideSetStatus(index) != flag)
{
this->MetaData->SetSideSetStatus(index, flag);
// Because which side sets are on/off affects the
// geometry we need to remake the mesh cache
this->RemakeDataCacheFlag = 1;
this->Modified();
}
}
void vtkExodusReader::SetSideSetArrayStatus(const char* name, int flag)
{
if(this->MetaData->GetNumberOfSideSets()==0)
{
// The value is being set before the metadata has been finalized
// So store for later and use as the initial value if needed
this->MetaData->SetSideSetInitStatus(name,flag);
}
// Only modify if we are 'out of sync'
if (this->MetaData->GetSideSetStatus(name) != flag)
{
this->MetaData->SetSideSetStatus(name, flag);
// Because which side sets are on/off affects the
// geometry we need to remake the mesh cache
this->RemakeDataCacheFlag = 1;
this->Modified();
}
}
int vtkExodusReader::GetSideSetArrayStatus(int index)
{
return this->MetaData->GetSideSetStatus( index );
}
int vtkExodusReader::GetSideSetArrayStatus(const char* name)
{
return this->MetaData->GetSideSetStatus( name );
}
const char* vtkExodusReader::GetSideSetArrayName(int index)
{
return this->MetaData->GetSideSetName(index);
}
//----------------------------
// End Node/Side set accessors
//----------------------------
// Part info accessors
int vtkExodusReader::GetNumberOfPartArrays()
{
return this->MetaData->GetNumberOfParts();
}
const char* vtkExodusReader::GetPartArrayName(int arrayIdx)
{
return this->MetaData->GetPartName(arrayIdx);
}
const char* vtkExodusReader::GetPartBlockInfo(int arrayIdx)
{
return this->MetaData->GetPartBlockInfo(arrayIdx);
}
void vtkExodusReader::SetPartArrayStatus(int index, int flag)
{
// Only modify if we are 'out of sync'
if (this->MetaData->GetPartStatus(index) != flag)
{
this->MetaData->SetPartStatus(index, flag);
// Because which parts are on/off affects the
// geometry we need to remake the mesh cache
this->RemakeDataCacheFlag = 1;
this->Modified();
}
}
void vtkExodusReader::SetPartArrayStatus(const char* name, int flag)
{
// Only modify if we are 'out of sync'
if (this->MetaData->GetPartStatus(name) != flag)
{
this->MetaData->SetPartStatus(name, flag);
// Because which parts are on/off affects the
// geometry we need to remake the mesh cache
this->RemakeDataCacheFlag = 1;
this->Modified();
}
}
int vtkExodusReader::GetPartArrayStatus(int index)
{
return this->MetaData->GetPartStatus(index);
}
int vtkExodusReader::GetPartArrayStatus(const char* name)
{
return this->MetaData->GetPartStatus(name);
}
// Material info accessors
int vtkExodusReader::GetNumberOfMaterialArrays()
{
//cout << "reader asked for nummat " << this->MetaData->GetNumberOfMaterials() << endl;
return this->MetaData->GetNumberOfMaterials();
}
const char* vtkExodusReader::GetMaterialArrayName(int arrayIdx)
{
return this->MetaData->GetMaterialName(arrayIdx);
}
void vtkExodusReader::SetMaterialArrayStatus(int index, int flag)
{
// Only modify if we are 'out of sync'
if (this->MetaData->GetMaterialStatus(index) != flag)
{
this->MetaData->SetMaterialStatus(index, flag);
// Because which materials are on/off affects the
// geometry we need to remake the mesh cache
this->RemakeDataCacheFlag = 1;
this->Modified();
}
}
void vtkExodusReader::SetMaterialArrayStatus(const char* name, int flag)
{
// Only modify if we are 'out of sync'
if (this->MetaData->GetMaterialStatus(name) != flag)
{
this->MetaData->SetMaterialStatus(name, flag);
// Because which materials are on/off affects the
// geometry we need to remake the mesh cache
this->RemakeDataCacheFlag = 1;
this->Modified();
}
}
int vtkExodusReader::GetMaterialArrayStatus(int index)
{
return this->MetaData->GetMaterialStatus(index);
}
int vtkExodusReader::GetMaterialArrayStatus(const char* name)
{
return this->MetaData->GetMaterialStatus(name);
}
//end of Material Accessors
// Assembly info accessors
int vtkExodusReader::GetNumberOfAssemblyArrays()
{
return this->MetaData->GetNumberOfAssemblies();
}
const char* vtkExodusReader::GetAssemblyArrayName(int arrayIdx)
{
return this->MetaData->GetAssemblyName(arrayIdx);
}
int vtkExodusReader::GetAssemblyArrayID( char const *name )
{
int numArrays = this->GetNumberOfAssemblyArrays();
for ( int i=0;i<numArrays;i++ )
{
if ( strcmp( name, this->GetAssemblyArrayName( i ) ) == 0 )
{
return i;
}
}
return -1;
}
void vtkExodusReader::SetAssemblyArrayStatus(int index, int flag)
{
// Only modify if we are 'out of sync'
if (this->MetaData->GetAssemblyStatus(index) != flag)
{
this->MetaData->SetAssemblyStatus(index, flag);
// Because which materials are on/off affects the
// geometry we need to remake the mesh cache
this->RemakeDataCacheFlag = 1;
this->Modified();
}
}
void vtkExodusReader::SetAssemblyArrayStatus(const char* name, int flag)
{
// Only modify if we are 'out of sync'
if (this->MetaData->GetAssemblyStatus(name) != flag)
{
this->MetaData->SetAssemblyStatus(name, flag);
// Because which materials are on/off affects the
// geometry we need to remake the mesh cache
this->RemakeDataCacheFlag = 1;
this->Modified();
}
}
int vtkExodusReader::GetAssemblyArrayStatus(int index)
{
return this->MetaData->GetAssemblyStatus(index);
}
int vtkExodusReader::GetAssemblyArrayStatus(const char* name)
{
return this->MetaData->GetAssemblyStatus(name);
}
//end of Assembly Accessor
// Hierarchy Entry info accessors
int vtkExodusReader::GetNumberOfHierarchyArrays()
{
if (this->Parser)
{
return this->Parser->GetNumberOfHierarchyEntries();
}
return 0;
}
const char* vtkExodusReader::GetHierarchyArrayName(int arrayIdx)
{
if (this->Parser)
{
//MEMORY LEAK - without copying the result, the list does not appear on SGI's
char* result=new char[512];
sprintf(result,"%s",this->Parser->GetHierarchyEntry(arrayIdx).c_str());
return result;
//return this->Parser->GetHierarchyEntry(arrayIdx).c_str();
}
return "Should not see this";
}
void vtkExodusReader::SetHierarchyArrayStatus(int index, int flag)
{
// Only modify if we are 'out of sync'
//if (this->GetHierarchyArrayStatus(index) != flag)
// {
if (this->Parser)
{
vtkstd::vector<int> blocks=this->Parser->GetBlocksForEntry(index);
for (vtkstd::vector<int>::size_type i=0;i<blocks.size();i++)
{
//cout << "turning block " << blocks[i] << " " << flag << endl;
this->MetaData->SetUnsortedBlockStatus
(this->MetaData->GetBlockIndex(blocks[i]),flag);
}
// Because which materials are on/off affects the
// geometry we need to remake the mesh cache
this->RemakeDataCacheFlag = 1;
this->Modified();
}
}
void vtkExodusReader::SetHierarchyArrayStatus(const char* name, int flag)
{
// Only modify if we are 'out of sync'
//if (this->GetHierarchyArrayStatus(name) != flag)
//{
if (this->Parser)
{
vtkstd::vector<int> blocks=this->Parser->GetBlocksForEntry
(vtkStdString(name));
for (vtkstd::vector<int>::size_type i=0;i<blocks.size();i++)
{
//cout << "turning block " << blocks[i] << " " << flag << endl;
this->MetaData->SetUnsortedBlockStatus
(this->MetaData->GetBlockIndex(blocks[i]),flag);
}
// Because which materials are on/off affects the
// geometry we need to remake the mesh cache
this->RemakeDataCacheFlag = 1;
this->Modified();
}
}
int vtkExodusReader::GetHierarchyArrayStatus(int index)
{
if (this->Parser)
{
vtkstd::vector<int> blocks=this->Parser->GetBlocksForEntry(index);
for (vtkstd::vector<int>::size_type i=0;i<blocks.size();i++)
{
if (this->MetaData->GetUnsortedBlockStatus
(this->MetaData->GetBlockIndex(blocks[i]))==0)
return 0;
}
}
return 1;
}
int vtkExodusReader::GetHierarchyArrayStatus(const char* name)
{
if (this->Parser)
{
vtkstd::vector<int> blocks=this->Parser->GetBlocksForEntry(name);
for (vtkstd::vector<int>::size_type i=0;i<blocks.size();i++)
{
if (this->MetaData->GetUnsortedBlockStatus
(this->MetaData->GetBlockIndex(blocks[i]))==0)
return 0;
}
}
return 1;
}
//end of Hierarchy Entry Accessors
int vtkExodusReader::GetBlockId(int block_idx)
{
return this->MetaData->GetBlockId(block_idx);
}
void vtkExodusReader::SetDisplayType(int type){
if (this->MetaData)
{
this->MetaData->SetDisplayType(type);
}
this->DisplayType=type;
}
//----------------------------------------------------------------------------
int vtkExodusReader::RequestInformation(
vtkInformation *vtkNotUsed(request),
vtkInformationVector **vtkNotUsed(inputVector),
vtkInformationVector *outputVector)
{
int error;
float fdum;
int num_node_vars, num_ele_vars;
int i;
int num_elem_in_block;
int num_nodes_per_elem;
int num_attr;
char *cdum = NULL;
char elem_type[MAX_STR_LENGTH+1];
// We can skip ExecuteInformation if all of these are true:
// The filename has not changed
// The XML filename has not changed
// The request for metadata has not changed
int newXMLFile = 1;
int newMetaData = 1;
int newFile =
(vtkExodusReader::StringsEqual(this->FileName, this->CurrentFileName) == 0);
if (!newFile)
{
newXMLFile =
(vtkExodusReader::StringsEqual(this->XMLFileName, this->CurrentXMLFileName) == 0);
newMetaData = ((this->ExodusModelMetadata && (this->ExodusModel == NULL)) ||
(!this->ExodusModelMetadata && this->ExodusModel));
}
if ( !newFile && !newXMLFile && !newMetaData)
{
// always set the time step values even if we short circuit
if (!this->HasModeShapes)
{
if (this->NumberOfTimeSteps)
{
vtkInformation* outInfo = outputVector->GetInformationObject(0);
outInfo->Set(vtkStreamingDemandDrivenPipeline::TIME_STEPS(),
this->TimeSteps,
this->NumberOfTimeSteps);
double timeRange[2];
timeRange[0] = this->TimeSteps[0];
timeRange[1] = this->TimeSteps[this->NumberOfTimeSteps-1];
outInfo->Set(vtkStreamingDemandDrivenPipeline::TIME_RANGE(),
timeRange, 2);
}
}
else
{
vtkInformation* outInfo = outputVector->GetInformationObject(0);
outInfo->Remove(vtkStreamingDemandDrivenPipeline::TIME_STEPS());
double timeRange[2];
timeRange[0] = 0;
timeRange[1] = 1;
outInfo->Set(vtkStreamingDemandDrivenPipeline::TIME_RANGE(),
timeRange, 2);
}
return 1;
}
if (newXMLFile)
{
// Clean up any old xml parsers
if (this->Parser)
{
this->Parser->Delete();
this->Parser=NULL;
}
// If the xml file does not exist, try try again
if (!vtkExodusReaderFileExist(this->XMLFileName))
{
// Okay try to create an xml file using exodus file as basename
char tempName[512];
strcpy(tempName,this->FileName);
char* fpt=strrchr(tempName,'.');
if (fpt) strncpy(fpt,".xml\0",5);
// Does the xml file exist?
int XMLfound=0;
if (vtkExodusReaderFileExist(tempName))
{
SetXMLFileName(tempName);
XMLfound=1;
}
if (!XMLfound)
{
//try .dart
fpt=strrchr(tempName,'.');
if (fpt) strncpy(fpt,".dart\0",6);
if (vtkExodusReaderFileExist(tempName))
{
SetXMLFileName(tempName);
XMLfound=1;
}
}
if (!XMLfound)
{
//try artifact.dta
#ifdef _WIN32
fpt=strrchr(tempName,'\\');
if (fpt) strncpy(fpt,"\\artifact.dta\0",14);
#else
fpt=strrchr(tempName,'/');
if (fpt) strncpy(fpt,"/artifact.dta\0",14);
#endif
if (vtkExodusReaderFileExist(tempName))
{
SetXMLFileName(tempName);
XMLfound=1;
}
}
if (!XMLfound)
{
SetXMLFileName(NULL);
}
}
// Okay if we have a valid file create a parser
if (this->XMLFileName)
{
//cout << "parsing: " << this->XMLFileName << endl;
this->Parser = vtkExodusXMLParser::New();
this->Parser->SetFileName(this->XMLFileName);
this->Parser->Parse();
}
// The filename is different so we need to open the file
// and remake the data cache and get all the metadata
this->RemakeDataCacheFlag = 1;
newFile = 1;
this->SetCurrentXMLFileName(this->XMLFileName);
}
if ( this->OpenCurrentFile() != 1 )
{
return 0;
}
if (newMetaData)
{
if (this->ExodusModelMetadata)
{
// Write the global metadata now. This is all the information
// which does not depend on which cells, timestep, or field data
// we are going to read in.
this->NewExodusModel();
this->ExodusModel->SetGlobalInformation( this->CurrentHandle,
this->ExodusCPUWordSize );
}
else
{
if (this->ExodusModel)
{
this->ExodusModel->Delete();
this->ExodusModel = NULL;
}
}
}
// **KEN** Why not have vtkExodusMetadata do all of this instead.
// Encapsulate the functionality of reading it along with the data.
// That's the whole idea behind object oriented programming, right?
if (newFile)
{
this->SetGlobalElementIdCache(NULL);
// Get metadata
error = ex_get_init(this->CurrentHandle, this->Title, &this->Dimensionality,
&this->NumberOfNodesInFile, &this->NumberOfElementsInFile,
&this->NumberOfBlocks, &this->NumberOfNodeSets, &this->NumberOfSideSets);
if (error < 0)
{
vtkErrorMacro("Error: " << error << " calling ex_get_init " << this->FileName);
this->CloseCurrentFile();
return 0;
}
// Read the number of time steps available.
error = ex_inquire(this->CurrentHandle,
EX_INQ_TIME, &this->NumberOfTimeSteps, &fdum,cdum);
if (error < 0)
{
vtkErrorMacro("Error: " << error << " calling ex_inquire " << this->FileName);
this->CloseCurrentFile();
return 0;
}
this->TimeStepRange[0] = 0;
this->TimeStepRange[1] = this->NumberOfTimeSteps-1;
this->GetAllTimes(outputVector);
// Read element block paramemters.
this->MetaData->ResetBlocks();
int *ids = new int[this->NumberOfBlocks];
char block_name_buffer[80];
int status = 1;
ex_get_elem_blk_ids (this->CurrentHandle, ids);
for (i = 0; i < this->NumberOfBlocks; ++i)
{
error = ex_get_elem_block (this->CurrentHandle, ids[i], elem_type,
&(num_elem_in_block),
&(num_nodes_per_elem), &(num_attr));
if (error < 0)
{
vtkErrorMacro(
"Error: " << error << " calling ex_get_elem_blk_ids " << this->FileName);
this->CloseCurrentFile();
delete [] ids;
return 0;
}
// Check for empty block
if (!strcmp(elem_type,"NULL"))
{
strcpy(elem_type,"empty");
}
sprintf(block_name_buffer,"Block: %d (%s)",ids[i],elem_type);
// Get whether an initial state for this block has been specified
// If none is found, the default value is 'on'
status = this->MetaData->GetBlockInitStatus(block_name_buffer);
if (this->Parser && this->Parser->GetPartDescription(ids[i])!="")
{
//construct assembly names from number and description arrays
vtkstd::vector<vtkStdString> assemblyNumbers=
this->Parser->GetAssemblyNumbers(ids[i]);
vtkstd::vector<vtkStdString> assemblyDescriptions=
this->Parser->GetAssemblyDescriptions(ids[i]);
vtkstd::vector<vtkStdString> assemblyNames;
for (vtkstd::vector<int>::size_type j=0;j<assemblyNumbers.size();j++)
{
assemblyNames.push_back(assemblyDescriptions[j]+vtkStdString(" (")+
assemblyNumbers[j]+vtkStdString(")"));
}
sprintf(block_name_buffer,"Block: %d (%s) %s",ids[i],
this->Parser->GetPartDescription(ids[i]).c_str(),
this->Parser->GetPartNumber(ids[i]).c_str());
this->MetaData->AddBlock(block_name_buffer,
this->Parser->GetPartDescription(ids[i])+" ("+
this->Parser->GetMaterialDescription(ids[i])+")"+" : "+
this->Parser->GetPartNumber(ids[i]),
this->Parser->GetMaterialDescription(ids[i])+" : "+
this->Parser->GetMaterialSpecification(ids[i]),
assemblyNames,
ids[i], num_elem_in_block, status);
}
else
{
vtkstd::vector<vtkStdString> assemblyNames;
assemblyNames.push_back(vtkStdString("Default Assembly"));
this->MetaData->AddBlock(block_name_buffer,"Default Part",
"Default Material", assemblyNames,ids[i],
num_elem_in_block, status);
}
}
delete [] ids;
// Read the number of node arrays
error = ex_get_var_param(this->CurrentHandle, "n", &(num_node_vars));
if (error < 0)
{
vtkErrorMacro(
"Error: " << error << " calling ex_get_var_param " << this->FileName);
this->CloseCurrentFile();
return 0;
}
// Get node array information
if (num_node_vars > 0)
{
error = ex_get_var_names(this->CurrentHandle, "n", num_node_vars,
MetaData->AllocatePointArrayNameBuffer(num_node_vars));
if (error < 0)
{
vtkErrorMacro(
"Error: " << error << " reading point array names " << this->FileName);
this->CloseCurrentFile();
return 0;
}
this->RemoveBeginningAndTrailingSpaces(
MetaData->GetPointArrayNameBuffer(),num_node_vars);
}
// Read the number of cell arrays
error = ex_get_var_param(this->CurrentHandle, "e", &(num_ele_vars));
if (error < 0)
{
vtkErrorMacro(
"Error: " << error << " calling ex_get_var_param " << this->FileName);
this->CloseCurrentFile();
return 0;
}
// Get cell array information
if (num_ele_vars > 0)
{
// Not all cell variables exist over all element blocks. A "truth table"
// will say whether a variable is defined for a certain block.
this->CellVarTruthTable->Resize(num_ele_vars*this->NumberOfBlocks);
int *ptr = CellVarTruthTable->GetPointer(0);
ex_get_elem_var_tab(this->CurrentHandle, this->NumberOfBlocks,
num_ele_vars, ptr);
error = ex_get_var_names (this->CurrentHandle, "e", num_ele_vars,
MetaData->AllocateCellArrayNameBuffer(num_ele_vars));
if (error < 0)
{
vtkErrorMacro("Error: " << error << " calling ex_get_var_names " << this->FileName);
this->CloseCurrentFile();
return 0;
}
this->RemoveBeginningAndTrailingSpaces(
MetaData->GetCellArrayNameBuffer(),num_ele_vars);
}
// Read Node Set and Side Set metadata
this->ReadNodeSetMetadata();
this->ReadSideSetMetadata();
}
// Close the exodus file
this->CloseCurrentFile();
if (newFile)
{
// Call finalize on the array metadata. This is important
// otherwise does not work at all
MetaData->Finalize();
}
return 1;
}
//------------------------------------------------------------------------
// Read Node Set and Side Set MetaData for future use
// Set ids
// Set size
// number of distribution factors in each set
//------------------------------------------------------------------------
void vtkExodusReader::ReadNodeSetMetadata()
{
// Stop if there are no Node Sets
if ( this->NumberOfNodeSets <= 0 )
{
return;
}
// allocate memory for node set ids
vtkstd::vector<int> nodeSetId( this->NumberOfNodeSets, -1 );
int size = 0;
int dist = 0;
// read node set ids
int error = ex_get_node_set_ids( this->CurrentHandle, &nodeSetId[0] );
if (error < 0)
{
vtkErrorMacro("Error: " << error << " calling ex_get_node_set_ids " << this->FileName);
}
// read meta data for each node set
int i = 0;
char bufferName[80];
int status = 0;
for( i = 0; i < this->NumberOfNodeSets; i++ )
{
error = ex_get_node_set_param( this->CurrentHandle, nodeSetId[i], &size, &dist );
if (error < 0)
{
vtkErrorMacro("Error: " << error << " calling ex_get_node_set_param " << this->FileName);
}
// Add a node set's metadata to vtkExodusMetaData
// Store it's Exodus Id, size, and number of distribution factors
sprintf(bufferName, "NodeSet %d",nodeSetId[i]);
// Get whether an initial state has been given for this node set
// If none is found, the default is "off"
status = this->MetaData->GetNodeSetInitStatus(bufferName);
this->MetaData->AddNodeSet( bufferName, nodeSetId[i], size, dist, status );
}
}
void vtkExodusReader::ReadSideSetMetadata()
{
// Stop if there are no Side Sets
if ( this->NumberOfSideSets <= 0 )
{
return;
}
// allocate memory for side set ids
vtkstd::vector<int> sideSetId( this->NumberOfSideSets, -1 );
int size = 0;
int dist = 0;
// read side set ids
int error = ex_get_side_set_ids( this->CurrentHandle, &sideSetId[0] );
if (error < 0)
{
vtkErrorMacro(<< "Error: " << error
<< " calling ex_get_side_set_ids " << this->FileName);
}
// read meta data for each side set
int i = 0;
char bufferName[80];
int status = 0;
for( i = 0; i < this->NumberOfSideSets; i++ )
{
error = ex_get_side_set_param( this->CurrentHandle, sideSetId[i], &size, &dist );
if (error < 0)
{
vtkErrorMacro(<< "Error: " << error
<< " calling ex_get_side_set_param " << this->FileName);
}
// Add a side set's metadate to vtkExodusMetaData
// Store it's Exodus Id, size, and number of distribution factors
sprintf(bufferName, "SideSet %d",sideSetId[i]);
status = this->MetaData->GetSideSetInitStatus(bufferName);
// Get whether an initial state has been given for this side set
// If none is found, the default is "off"
this->MetaData->AddSideSet( bufferName, sideSetId[i], size, dist, status );
}
}
//----------------------------------------------------------------------------
int vtkExodusReader::RequestData(
vtkInformation *vtkNotUsed(request),
vtkInformationVector **vtkNotUsed(inputVector),
vtkInformationVector *outputVector)
{
if ( this->OpenCurrentFile() != 1 )
{
vtkWarningMacro(<< "Can't open file");
return 0;
}
this->ActualTimeStep = this->TimeStep;
vtkInformation* outInfo = outputVector->GetInformationObject(0);
// get the ouptut
vtkUnstructuredGrid *output = vtkUnstructuredGrid::SafeDownCast(
outInfo->Get(vtkDataObject::DATA_OBJECT()));
int tsLength =
outInfo->Length(vtkStreamingDemandDrivenPipeline::TIME_STEPS());
double* steps =
outInfo->Get(vtkStreamingDemandDrivenPipeline::TIME_STEPS());
// Check if a particular time was requested.
if(outInfo->Has(vtkStreamingDemandDrivenPipeline::UPDATE_TIME_STEPS()))
{
// Get the requested time step. We only supprt requests of a single time
// step in this reader right now
double *requestedTimeSteps =
outInfo->Get(vtkStreamingDemandDrivenPipeline::UPDATE_TIME_STEPS());
this->TimeValue = requestedTimeSteps[0];
if (!this->HasModeShapes)
{
//find the timestep with the closest value to the requested time
//value
int cnt = 0;
int closestStep=0;
double minDist=-1;
for (cnt=0;cnt<tsLength-1;cnt++)
{
double tdist=(steps[cnt]-this->TimeValue>this->TimeValue-steps[cnt])?steps[cnt]-this->TimeValue:this->TimeValue-steps[cnt];
if (minDist<0 || tdist<minDist)
{
minDist=tdist;
closestStep=cnt;
}
}
this->ActualTimeStep=closestStep;
// find the first time value larger than requested time value
// this logic could be improved
//while (cnt < tsLength-1 && steps[cnt] < this->TimeValue)
// {
//
// cnt++;
// }
//this->ActualTimeStep = cnt;
}
}
// Force TimeStep into the "known good" range. Although this
// could be accomplished inside SetTimeStep(),
// - we'd rather not override a VTK macro-defined method
// because the macro might change
// - it might be good to allow out-of-range values in
// places
if ( this->ActualTimeStep < this->TimeStepRange[0] )
{
this->ActualTimeStep = this->TimeStepRange[0];
}
else if ( this->ActualTimeStep > this->TimeStepRange[1] )
{
this->ActualTimeStep = this->TimeStepRange[1];
}
// Okay because they may have changed which blocks are on/off
// we need to recompute the actual number of elements
int actualElements=0;
for (int i=0; i < this->MetaData->GetNumberOfBlocks(); ++i)
{
// Do we read this block?
if (this->MetaData->GetBlockStatus(i)==1)
actualElements += this->MetaData->GetNumElementsInBlock(i);
}
#if DEBUG
vtkWarningMacro(<< "NumElements: " << NumberOfElements
<< " actualElements: " << actualElements);
#endif
this->NumberOfUsedElements = actualElements;
// In general the geometry of an exodus file remains the same
// So often you can just read in new field array
// The 'RemakeDataCacheFlag' is set if you need to read
// in the geometry again for some reason (eg new file or a
// change which blocks get read in etc)
if ( RemakeDataCacheFlag )
{
this->ReadGeometry(this->CurrentHandle, output);
this->NewGeometryCount++;
// **KEN** Would it make sense to relase the DataCache data BEFORE
// reading the new geometry? That might reduce the amount of memory
// needed at one time.
// Make a shallowcopy to the my DataCache
this->DataCache->ReleaseData(); // FIXME Do I need this?
this->DataCache->ShallowCopy(output);
// Okay I don't need to do this again until someone
// says 'Hey you need to remake this mesh data!'
this->RemakeDataCacheFlag = 0;
#if DEBUG
vtkWarningMacro("Remade data cache");
#endif
}
else
{
// Just copy (shallow) the points and cells from the DataCache.
// The points and cell information is always the same for exodus
// Also copy the generated arrays which also stay the same
output->ShallowCopy(this->DataCache);
}
// Save the time value in the output data information.
if (steps)
{
if (!this->HasModeShapes)
{
output->GetInformation()->Set(vtkDataObject::DATA_TIME_STEPS(),
steps+this->ActualTimeStep, 1);
}
else
{
output->GetInformation()->Remove(vtkDataObject::DATA_TIME_STEPS());
}
}
// Read in the arrays.
// If we are in the execution method then either the file, the time
// step or array selections changed. In all cases we have to reload arrays.
this->ReadArrays(this->CurrentHandle, output);
//begin USE_EXO_DSP_FILTERS
this->GetDSPOutputArrays(this->CurrentHandle, output);
//end USE_EXO_DSP_FILTERS
// If the user wants the apply displacements then add here
// TODO: This is recalled everytime a user changes arrays
// look into avoiding this if possible
if (ApplyDisplacements)
{
AddDisplacements(output);
}
// Generated arrays include block id, global node id, global element id
this->GenerateExtraArrays(output);
// This just makes sure the arrays are the same size as the number
// of nodes or cell
output->CheckAttributes();
// We may have some mem that can be condensed
output->Squeeze();
if (this->ExodusModel)
{
int rc = this->ExodusModel->SetLocalInformation(
output,
this->CurrentHandle, this->ActualTimeStep,
this->NewGeometryCount, this->ExodusIOWordSize);
if (rc)
{
vtkErrorMacro(<< "Can't create the local model information");
}
if (this->PackExodusModelOntoOutput)
{
// The metadata will be written to field arrays and added
// to the output.
this->ExodusModel->GetModelMetadata()->Pack(output);
}
}
// Close the exodus file
this->CloseCurrentFile();
return 1;
}
//----------------------------------------------------------------------------
void vtkExodusReader::ReadGeometry(int handle, vtkUnstructuredGrid* output)
{
// Reset the entire unstructured grid
output->Reset();
this->ProgressOffset = 0;
this->ProgressScale = 0.4;
// Read in cell topology
this->ReadCells(handle, output);
this->UpdateProgress(0.4);
this->ProgressOffset = 0.4;
this->ProgressScale = 0.2;
// Read in node and side sets
this->ReadNodeAndSideSets(handle, output);
this->UpdateProgress(0.6);
this->ProgressOffset = 0.6;
this->ProgressScale = 0.4;
// Now read in the points
// Note: This should come after reading in
// the cells and node/side set so that
// we know which points should actually be
// stored and put in the output
this->ReadPoints(handle, output);
}
// Read in node and side set data
void vtkExodusReader::ReadNodeAndSideSets(int handle, vtkUnstructuredGrid* output)
{
int i, j, k;
int *indexPtr;
vtkIdList *cellIds=vtkIdList::New();
vtkIntArray *counts=vtkIntArray::New();
vtkIntArray *nodeIndexes=vtkIntArray::New();
int cellType;
int cellNumPoints;
// Read in all the node sets that are 'on'
for (i=0; i < this->GetNumberOfNodeSets(); ++i)
{
// Do we read this node set?
if (this->MetaData->GetNodeSetStatus(i))
{
// Allocate storage for node indexes
nodeIndexes->Reset();
nodeIndexes->SetNumberOfValues(this->MetaData->GetNodeSetSize(i));
// Get the node indexes
ex_get_node_set(handle, this->MetaData->GetNodeSetId(i),
nodeIndexes->GetPointer(0));
// Okay now loop though the nodes indexes and insert into the output
for(j=0; j < this->MetaData->GetNodeSetSize(i); ++j)
{
cellIds->Reset();
cellIds->InsertNextId(GetPointMapIndex(nodeIndexes->GetValue(j)-1));
output->InsertNextCell(VTK_VERTEX, cellIds);
}
}
}
this->UpdateProgress(this->ProgressOffset + this->ProgressScale*0.5);
// Read in all the side sets that are 'on'
for (i=0; i < this->GetNumberOfSideSets(); ++i)
{
// Do we read this side set?
if (this->MetaData->GetSideSetStatus(i))
{
// Allocate storage for 'counts' (element size) array and
// node indexes (connectivity)
// Assumption: Side set elements will not be more than 4 nodes :)
counts->Reset();
counts->SetNumberOfValues(this->MetaData->GetSideSetSize(i));
nodeIndexes->Reset();
nodeIndexes->SetNumberOfValues(this->MetaData->GetSideSetSize(i)*4);
// Get the counts (element size) array and the node indexes
ex_get_side_set_node_list(handle, this->MetaData->GetSideSetId(i),
counts->GetPointer(0), nodeIndexes->GetPointer(0));
indexPtr = nodeIndexes->GetPointer(0);
// Okay now loop though for each element and set up the cells
for(j=0; j < this->MetaData->GetSideSetSize(i); ++j)
{
// What kind of cell do we have
cellNumPoints = counts->GetValue(j);
switch (cellNumPoints)
{
case 1:
cellType=VTK_VERTEX;
break;
case 2:
cellType=VTK_LINE;
break;
case 3:
cellType=VTK_TRIANGLE;
break;
case 4:
cellType=VTK_QUAD;
break;
default:
vtkErrorMacro("Unknown side side element with: " <<
counts->GetValue(j) << " nodes");
return;
}
// Now set up connectivity for cell
cellIds->Reset();
for (k=0; k<cellNumPoints; ++k)
{
cellIds->InsertNextId(GetPointMapIndex(indexPtr[k]-1));
}
indexPtr+=cellNumPoints;
// Now insert the cell
output->InsertNextCell(cellType, cellIds);
}
}
}
// Delete any allocated stuff
cellIds->Delete();
counts->Delete();
nodeIndexes->Delete();
}
// Read in connectivity information
void vtkExodusReader::ReadCells(int handle, vtkUnstructuredGrid* output)
{
int i, j, k;
int num_elem_in_block;
int num_nodes_per_elem;
int num_attr;
char sm_elem_type[MAX_STR_LENGTH+1];
int *connect, *pConnect;
vtkIdList *cellIds=vtkIdList::New();
int cellType;
int cellNumPoints;
// Allocate memory in the output
output->Allocate(this->NumberOfUsedElements);
// **KEN** The point maps can be really big. Therefore, they should be
// deleted as soon as possible.
// Set up point map
this->SetUpPointMap(this->NumberOfNodesInFile);
// Initialize using the type of cells.
// A block contains only one type of cell.
int num_of_blocks = this->MetaData->GetNumberOfBlocks();
for (i=0; i < num_of_blocks; ++i)
{
// Do we read this block?
if (this->MetaData->GetBlockStatus(i)==0)
{
continue;
}
// Read in the metadata about this block
ex_get_elem_block(handle, this->MetaData->GetBlockId(i), sm_elem_type,
&num_elem_in_block, &num_nodes_per_elem, &num_attr);
// If for some weird reason the block has no elements go to next block
if (num_elem_in_block == 0)
{
continue;
}
// Okay allocate memory for connectivity data
connect = new int [num_nodes_per_elem*num_elem_in_block];
ex_get_elem_conn (handle, this->MetaData->GetBlockId(i), connect);
// Grab the element type
char *elem_type = new char[MAX_STR_LENGTH];
this->StringUppercase(sm_elem_type, elem_type);
// Check for quadratic elements
if (!strncmp(elem_type,"TRI",3) && (num_nodes_per_elem==6))
{cellType=VTK_QUADRATIC_TRIANGLE; cellNumPoints=6;}
else if (!strncmp(elem_type,"SHE",3) && (num_nodes_per_elem==8))
{cellType=VTK_QUADRATIC_QUAD; cellNumPoints=8;}
else if (!strncmp(elem_type,"SHE",3) && (num_nodes_per_elem==9))
{cellType=VTK_QUADRATIC_QUAD; cellNumPoints=8;}
else if (!strncmp(elem_type,"TET",3) && (num_nodes_per_elem==10))
{cellType=VTK_QUADRATIC_TETRA; cellNumPoints=10;}
else if (!strncmp(elem_type,"TET",3) && (num_nodes_per_elem==11))
{cellType=VTK_QUADRATIC_TETRA; cellNumPoints=10;}
else if (!strncmp(elem_type,"HEX",3) && (num_nodes_per_elem==20))
{cellType=VTK_QUADRATIC_HEXAHEDRON; cellNumPoints=20;}
else if (!strncmp(elem_type,"HEX",3) && (num_nodes_per_elem==21))
{cellType=VTK_QUADRATIC_HEXAHEDRON; cellNumPoints=20;}
else if (!strncmp(elem_type,"HEX",3) && (num_nodes_per_elem==27))
{cellType=VTK_TRIQUADRATIC_HEXAHEDRON; cellNumPoints=27;}
else if (!strncmp(elem_type,"QUA",3) && (num_nodes_per_elem==8))
{cellType=VTK_QUADRATIC_QUAD; cellNumPoints=8;}
else if (!strncmp(elem_type,"QUA",3) && (num_nodes_per_elem==9))
{cellType=VTK_QUADRATIC_QUAD; cellNumPoints=8;}
else if (!strncmp(elem_type,"TRU",3) && (num_nodes_per_elem==3))
{cellType=VTK_QUADRATIC_EDGE; cellNumPoints=3;}
else if (!strncmp(elem_type,"BEA",3) && (num_nodes_per_elem==3))
{cellType=VTK_QUADRATIC_EDGE; cellNumPoints=3;}
else if (!strncmp(elem_type,"BAR",3) && (num_nodes_per_elem==3))
{cellType=VTK_QUADRATIC_EDGE; cellNumPoints=3;}
else if (!strncmp(elem_type,"EDG",3) && (num_nodes_per_elem==3))
{cellType=VTK_QUADRATIC_EDGE; cellNumPoints=3;}
// Check for regular elements
else if (!strncmp(elem_type,"CIR",3)) {cellType=VTK_VERTEX; cellNumPoints=1;}
else if (!strncmp(elem_type,"SPH",3)) {cellType=VTK_VERTEX; cellNumPoints=1;}
else if (!strncmp(elem_type,"BAR",3)) {cellType=VTK_LINE; cellNumPoints=2;}
else if (!strncmp(elem_type,"TRU",3)) {cellType=VTK_LINE; cellNumPoints=2;}
else if (!strncmp(elem_type,"BEA",3)) {cellType=VTK_LINE; cellNumPoints=2;}
else if (!strncmp(elem_type,"EDG",3)) {cellType=VTK_LINE; cellNumPoints=2;}
else if (!strncmp(elem_type,"TRI",3)) {cellType=VTK_TRIANGLE; cellNumPoints=3;}
else if (!strncmp(elem_type,"QUA",3)) {cellType=VTK_QUAD; cellNumPoints=4;}
else if (!strncmp(elem_type,"TET",3)) {cellType=VTK_TETRA; cellNumPoints=4;}
else if (!strncmp(elem_type,"PYR",3)) {cellType=VTK_PYRAMID; cellNumPoints=5;}
else if (!strncmp(elem_type,"WED",3)) {cellType=VTK_WEDGE; cellNumPoints=6;}
else if (!strncmp(elem_type,"HEX",3)) {cellType=VTK_HEXAHEDRON; cellNumPoints=8;}
else if (!strncmp(elem_type,"SHE",3) && (num_nodes_per_elem==3)) {cellType=VTK_TRIANGLE; cellNumPoints=3;}
else if (!strncmp(elem_type,"SHE",3) && (num_nodes_per_elem==4)) {cellType=VTK_QUAD; cellNumPoints=4;}
else if (!strncmp(elem_type,"SUPER",5)) {cellType=VTK_POLY_VERTEX; cellNumPoints=num_nodes_per_elem;}
else
{
vtkErrorMacro("Unsupported element type: " << elem_type);
delete [] connect;
continue;
}
delete []elem_type;
//cell types not currently handled
//quadratic wedge - 15,16 nodes
//quadratic pyramid - 13 nodes
// Now save the cells in a cell array.
pConnect = connect;
for (j = 0; j < num_elem_in_block; ++j)
{
cellIds->Reset();
// Build up a list of cell pt ids to insert in to the output data set.
// Note: The '-1' is because Exodus stores ids starting from 1 not 0.
// Special setup for quadratic hex because exodus node numbering
// for this cell type is different than vtk node numbering
if (cellType==VTK_QUADRATIC_HEXAHEDRON)
{
for (k=0; k<12; ++k)
cellIds->InsertNextId(GetPointMapIndex(pConnect[k]-1));
for (k=12; k<16; ++k)
cellIds->InsertNextId(GetPointMapIndex(pConnect[k+4]-1));
for (k=16; k<20; ++k)
cellIds->InsertNextId(GetPointMapIndex(pConnect[k-4]-1));
}
else if (cellType==VTK_TRIQUADRATIC_HEXAHEDRON)
{
for (k=0; k<12; ++k)
cellIds->InsertNextId(GetPointMapIndex(pConnect[k]-1));
for (k=12; k<16; ++k)
cellIds->InsertNextId(GetPointMapIndex(pConnect[k+4]-1));
for (k=16; k<20; ++k)
cellIds->InsertNextId(GetPointMapIndex(pConnect[k-4]-1));
cellIds->InsertNextId(GetPointMapIndex(pConnect[23]-1));
cellIds->InsertNextId(GetPointMapIndex(pConnect[24]-1));
cellIds->InsertNextId(GetPointMapIndex(pConnect[25]-1));
cellIds->InsertNextId(GetPointMapIndex(pConnect[26]-1));
cellIds->InsertNextId(GetPointMapIndex(pConnect[21]-1));
cellIds->InsertNextId(GetPointMapIndex(pConnect[22]-1));
cellIds->InsertNextId(GetPointMapIndex(pConnect[20]-1));
}
// All the rest of the cells have the same node numbering
else
{
for (k=0; k<cellNumPoints; ++k)
cellIds->InsertNextId(GetPointMapIndex(pConnect[k]-1));
}
// Skip to next element.
pConnect += num_nodes_per_elem;
// Insert cell into output.
output->InsertNextCell(cellType, cellIds);
if (j%1000==0)
{
double prog =
static_cast<double>(i*j)/(num_elem_in_block * num_of_blocks);
this->UpdateProgress(this->ProgressOffset + this->ProgressScale*prog);
}
}
delete [] connect;
connect = NULL;
}
cellIds->Delete();
cellIds = NULL;
}
void vtkExodusReader::ReadPoints(int handle, vtkUnstructuredGrid* output)
{
vtkPoints *newPoints;
int pointId, point_index;
// Sanity Check
if (this->NumberOfUsedNodes == 0)
{
#if DEBUG
vtkWarningMacro("The number of used nodes is zero\n");
#endif
return;
}
// Allocate point arrays
float *x = new float[this->NumberOfNodesInFile];
float *y = new float[this->NumberOfNodesInFile];
float *z = new float[this->NumberOfNodesInFile];
// Clear z values in case you don't really use them
memset(z,0,this->NumberOfNodesInFile*sizeof(float));
// Get node coordinates
ex_get_coord(handle, x, y, z);
// Create new points
newPoints = vtkPoints::New();
newPoints->SetNumberOfPoints(this->NumberOfUsedNodes);
// Set up points
for (pointId=0; pointId<this->NumberOfUsedNodes; ++pointId)
{
point_index = this->ReversePointMap->GetValue(pointId);
newPoints->InsertPoint(pointId, x[point_index], y[point_index], z[point_index]);
if (pointId%1000 == 0)
{
this->UpdateProgress(this->ProgressOffset +
static_cast<double>(pointId)/this->NumberOfUsedNodes * this->ProgressScale);
}
}
output->SetPoints(newPoints);
delete [] x;
delete [] y;
delete [] z;
newPoints->Delete();
newPoints = NULL;
// **KEN** I think this would be a good place to clear out the point
// map and squeeze the reverse map.
}
//----------------------------------------------------------------------------
void vtkExodusReader::ReadArrays(int handle, vtkUnstructuredGrid* output)
{
vtkDataArray *array;
int dim, arrayIdx, idx;
int haveArray, getArray;
char arrayName[MAX_STR_LENGTH];
char arrayNameUpper[MAX_STR_LENGTH];
// Read point arrays.
// The first vector array encounters is set to vectors,
// and the first array encountered is set to scalars.
arrayIdx = 0;
for (idx = 0; idx < this->GetNumberOfPointArrays(); ++idx)
{
// Get the name of the array
strcpy(arrayName,this->GetPointArrayName(idx));
// Do I already have this array?
if (output->GetPointData()->GetArray(arrayName) != NULL)
{
haveArray=1;
}
else
{
haveArray=0;
}
// Does user want displacements
this->StringUppercase(arrayName,arrayNameUpper);
if ((this->ApplyDisplacements || /* user wants displacement field */
this->ExodusModelMetadata) /* user may plan to write out file */
&&
!strncmp(arrayNameUpper,"DIS",3))
{
// Add it to the arrays I want
this->MetaData->SetPointArrayStatus(idx, 1);
}
// Does the user want this array?
getArray = this->GetPointArrayStatus(idx);
// If I have the array and the user DOESN'T want it
// then remove the array from the output
if (haveArray && !getArray)
{
output->GetPointData()->RemoveArray(arrayName);
if (this->ExodusModel)
{
this->ExodusModel->RemoveUGridNodeVariable(arrayName);
}
}
// If the user wants this array AND I don't already have it
// then read in the data
else if (getArray && !haveArray)
{
// How many dimensions is this array
dim = this->GetPointArrayNumberOfComponents(idx);
if (dim == 1)
{
array = this->ReadPointArray(handle, arrayIdx);
}
else
{
array = this->ReadPointVector(handle, arrayIdx, dim);
}
// Opps some sort of problem
if (array == NULL)
{
vtkErrorMacro("Problem reading node array " << this->GetPointArrayName(idx));
// Do not try loading this again
this->MetaData->SetPointArrayStatus(idx,0);
}
else
{
array->SetName(this->GetPointArrayName(idx));
output->GetPointData()->AddArray(array);
// Delete array memory (FIXME this seems inefficient)
array->Delete();
array = NULL;
if (this->ExodusModel)
{
// So ExodusIIWriter can map names in UGrid back to names in
// Exodus II file.
char *origName =
vtkExodusReader::StrDupWithNew(
this->MetaData->GetPointArrayOriginalName(arrayIdx));
char *newName =
vtkExodusReader::StrDupWithNew(this->GetPointArrayName(idx));
this->ExodusModel->AddUGridNodeVariable(newName, origName, dim);
}
}
}
// The array index needs to be incremented by the dimension
dim = this->GetPointArrayNumberOfComponents(idx);
arrayIdx += dim;
}
// Read cell arrays.
arrayIdx = 0;
for (idx = 0; idx < this->GetNumberOfCellArrays(); ++idx)
{
// Get the name of the array
strcpy(arrayName,this->GetCellArrayName(idx));
// Do I already have this array?
if (output->GetCellData()->GetArray(arrayName) != NULL)
haveArray=1;
else
haveArray=0;
// Does the user want this array?
getArray = this->GetCellArrayStatus(idx);
// If I have the array and the user DOESN'T want it
// then remove the array from the output
if (haveArray && !getArray)
{
output->GetCellData()->RemoveArray(arrayName);
if (this->ExodusModel)
{
this->ExodusModel->RemoveUGridElementVariable(arrayName);
}
}
// If the user wants this array AND I don't already have it
// then read in the data
else if (getArray && !haveArray)
{
// How many dimensions is this array
dim = this->GetCellArrayNumberOfComponents(idx);
if (dim == 1)
{
array = this->ReadCellArray(handle, arrayIdx);
}
else
{
array = this->ReadCellVector(handle, arrayIdx, dim);
}
// Opps some sort of problem
if (array == NULL)
{
vtkErrorMacro("Problem reading cell array " << this->GetCellArrayName(idx));
// Do not try loading this again
this->MetaData->SetCellArrayStatus(idx, 0);
}
else
{
array->SetName(this->GetCellArrayName(idx));
output->GetCellData()->AddArray(array);
array->Delete();
array = NULL;
if (this->ExodusModel)
{
// So ExodusIIWriter can map names in UGrid back to names in
// Exodus II file.
char *origName =
vtkExodusReader::StrDupWithNew(
this->MetaData->GetCellArrayOriginalName(arrayIdx));
char *newName =
vtkExodusReader::StrDupWithNew(this->GetCellArrayName(idx));
this->ExodusModel->AddUGridElementVariable(newName, origName, dim);
}
}
}
// The array index needs to be incremented by the dimension
dim = this->GetCellArrayNumberOfComponents(idx);
arrayIdx += dim;
}
}
void vtkExodusReader::AddDisplacements(vtkUnstructuredGrid* output)
{
char arrayName[MAX_STR_LENGTH];
char arrayNameUpper[MAX_STR_LENGTH];
int FOUND = 0;
// Now find the displacement array
strcpy(arrayName, "None");
for (int idx = 0; idx < this->GetNumberOfPointArrays(); ++idx)
{
// Is this array displacement?
strcpy(arrayName, this->GetPointArrayName(idx));
this->StringUppercase(arrayName,arrayNameUpper);
if (!strncmp(arrayNameUpper,"DIS",3))
{
FOUND = 1;
break;
}
}
// If I did not find displacements then just return
if (!FOUND) return;
// Create warp vector filter
vtkWarpVector *warp = vtkWarpVector::New();
vtkUnstructuredGrid *geom = vtkUnstructuredGrid::New();
geom->ShallowCopy(output);
warp->SetInput(geom);
warp->SetInputArrayToProcess(
0, 0, 0, vtkDataObject::FIELD_ASSOCIATION_POINTS, arrayName);
if (this->HasModeShapes)
{
warp->SetScaleFactor(
this->DisplacementMagnitude*cos(2*vtkMath::Pi()*this->TimeValue));
}
else
{
warp->SetScaleFactor(this->DisplacementMagnitude);
}
warp->Update();
geom->Delete();
// Copy warped mesh and cell/point data to my output
output->CopyStructure(warp->GetUnstructuredGridOutput());
output->GetCellData()->PassData(warp->GetUnstructuredGridOutput()->GetCellData());
output->GetPointData()->PassData(warp->GetUnstructuredGridOutput()->GetPointData());
// Delete warp filter
warp->Delete();
}
vtkDataArray *vtkExodusReader::ReadPointVector(int handle, int varIndex, int dim)
{
// Sanity check
if (dim !=2 && dim!=3)
{
vtkErrorMacro("Error: Only support 2 or 3 dim vectors var_index:" \
<< varIndex << " dim:" << dim<< " file: " << this->FileName);
return NULL;
}
// Create vector array
vtkFloatArray *vectors = vtkFloatArray::New();
vectors->SetNumberOfComponents(3);
vectors->SetNumberOfTuples(this->NumberOfUsedNodes);
// Grab first two arrays
vtkFloatArray *dim1 = (vtkFloatArray*)ReadPointArray(handle,varIndex);
vtkFloatArray *dim2 = (vtkFloatArray*)ReadPointArray(handle,varIndex+1);
// Do they need a third
vtkFloatArray *dim3 = NULL;
if (dim == 3)
dim3 = (vtkFloatArray*)ReadPointArray(handle,varIndex+2);
// Okay now set up memory pointers
float *vector_ptr = vectors->GetPointer(0);
float *dim1_ptr = dim1->GetPointer(0);
float *dim2_ptr = dim2->GetPointer(0);
float *dim3_ptr = NULL; if(dim==3) dim3_ptr = dim3->GetPointer(0);
// Okay now swizzle into vector array
if (dim==2)
{
for(int i=0; i<this->NumberOfUsedNodes; ++i)
{
*vector_ptr++ = *dim1_ptr++;
*vector_ptr++ = *dim2_ptr++;
*vector_ptr++ = 0;
}
}
else
{
for(int i=0; i<this->NumberOfUsedNodes; ++i)
{
*vector_ptr++ = *dim1_ptr++;
*vector_ptr++ = *dim2_ptr++;
*vector_ptr++ = *dim3_ptr++;
}
}
dim1->Delete();
dim2->Delete();
if ( dim3 )
{
dim3->Delete();
}
// Okay all done
return vectors;
}
vtkDataArray *vtkExodusReader::ReadPointArray(int handle, int varIndex)
{
// Temp float array
float *exo_array_data;
exo_array_data = new float[this->NumberOfNodesInFile];
// Create data array
vtkFloatArray *array = vtkFloatArray::New();
array->SetNumberOfValues(this->NumberOfUsedNodes);
// Read in data into temp array (note that Exodus is 1 based)
int error = ex_get_nodal_var (handle,
this->ActualTimeStep+1,
varIndex+1,
this->NumberOfNodesInFile,
exo_array_data);
// Opps something bad happened
if (error < 0)
{
vtkErrorMacro("Error: " << error << " ex_get_nodal_var timestep:"
<< this->ActualTimeStep << " var_index: " << varIndex
<< " file: " << this->FileName);
return NULL;
}
// Okay copy the points that are actually used into the vtk array
int point_index;
for(int i=0; i<this->NumberOfUsedNodes; i++)
{
point_index = this->ReversePointMap->GetValue(i);
array->SetValue(i, exo_array_data[point_index]);
}
// Clean up temp float array
delete [] exo_array_data;
return array;
}
vtkDataArray *vtkExodusReader::ReadCellVector(int handle, int varIndex, int dim)
{
// Sanity check
if (dim !=2 && dim!=3)
{
vtkErrorMacro("Error: Only support 2 or 3 dim vectors var_index:" \
<< varIndex << " dim:" << dim<< " file: " << this->FileName);
return NULL;
}
// Create vector array
vtkFloatArray *vectors = vtkFloatArray::New();
vectors->SetNumberOfComponents(3);
vectors->SetNumberOfTuples(this->NumberOfUsedElements);
// Grab first two arrays
vtkFloatArray *dim1 = (vtkFloatArray*)ReadCellArray(handle,varIndex);
vtkFloatArray *dim2 = (vtkFloatArray*)ReadCellArray(handle,varIndex+1);
// Do they need a third
vtkFloatArray *dim3 = NULL;
if (dim == 3)
{
dim3 = (vtkFloatArray*)ReadCellArray(handle,varIndex+2);
}
// Okay now set up memory pointers
float *vector_ptr = vectors->GetPointer(0);
float *dim1_ptr = dim1->GetPointer(0);
float *dim2_ptr = dim2->GetPointer(0);
float *dim3_ptr = NULL; if(dim==3) dim3_ptr = dim3->GetPointer(0);
// Okay now swizzle into vector array
if (dim==2)
{
for(int i=0; i<this->NumberOfUsedElements; ++i)
{
*vector_ptr++ = *dim1_ptr++;
*vector_ptr++ = *dim2_ptr++;
*vector_ptr++ = 0;
}
}
else
{
for(int i=0; i<this->NumberOfUsedElements; ++i)
{
*vector_ptr++ = *dim1_ptr++;
*vector_ptr++ = *dim2_ptr++;
*vector_ptr++ = *dim3_ptr++;
}
}
dim1->Delete();
dim2->Delete();
if ( dim3 )
{
dim3->Delete();
}
// Okay all done
return vectors;
}
void vtkExodusReader::FixMetadataTruthTable(int *table, int len)
{
if (this->ExodusModelMetadata && this->ExodusModel)
{
// vtkModelMetadata will free table when it is destroyed
int *newtable = new int [len];
memcpy(newtable, table, len * sizeof(int));
this->ExodusModel->GetModelMetadata()->SetElementVariableTruthTable(newtable);
}
}
// Read in the cell array specified by index 'varIndex'
vtkDataArray *vtkExodusReader::ReadCellArray(int handle, int varIndex)
{
int i;
int error;
int blockIdx;
// Create the data array
vtkFloatArray *array = vtkFloatArray::New();
array->SetNumberOfValues(this->NumberOfUsedElements);
float *arrayPtr = array->GetPointer(0);
int nblocks = this->MetaData->GetNumberOfBlocks();
// Loop through the blocks.
for (blockIdx=0; blockIdx < nblocks; ++blockIdx)
{
// Do we read this block?
if (this->MetaData->GetBlockStatus(blockIdx)==0)
{
continue;
}
// Get number of elements in block
int numBlockElements = this->MetaData->GetNumElementsInBlock(blockIdx);
// Truth Table may say no variables on this block for this variable
int cell_arrays = this->MetaData->GetOriginalNumberOfCellArrays();
int truthTableIdx =
this->MetaData->GetSortedOrder(blockIdx)*cell_arrays + varIndex;
if (this->CellVarTruthTable->GetValue(truthTableIdx) == 1)
{
error =
ex_get_elem_var (handle, this->ActualTimeStep+1, varIndex+1,
this->MetaData->GetBlockId(blockIdx), numBlockElements,
arrayPtr);
if (error < 0)
{
vtkWarningMacro("Warning: Truth Table indicated that cell variable " <<
this->GetCellArrayName(varIndex) <<
" appears in block " << this->MetaData->GetBlockId(blockIdx) <<
",\nhowever it is not there. "
"Truth table has been modified (in VTK memory only).");
// Assume the truth table is wrong. (Because we have seen this occur.)
// Change our table and change the one saved in the metadata.
this->CellVarTruthTable->SetValue(truthTableIdx, 0);
this->FixMetadataTruthTable(this->CellVarTruthTable->GetPointer(0),
nblocks * cell_arrays);
}
}
if (this->CellVarTruthTable->GetValue(truthTableIdx) == 0)
{
for(i=0; i<numBlockElements; ++i)
{
arrayPtr[i] = 0;
}
}
arrayPtr += numBlockElements;
}
// Padding cell arrays to have 'some' value for the addition
// of nodesets and sidesets
for(i=0;i<GetExtraCellCountForNodeSideSets();++i)
{
array->InsertNextValue(0);
}
// AOK so return array
return array;
}
int vtkExodusReader::GetExtraCellCountForNodeSideSets()
{
int i;
int count=0;
// Count number of additional 'cells' for nodesets
for (i=0; i < this->GetNumberOfNodeSets(); ++i)
{
// Do we read this node set?
if (this->MetaData->GetNodeSetStatus(i))
{
count += this->MetaData->GetNodeSetSize(i);
}
}
// Count number of additional 'cells' for sidesets
for (i=0; i < this->GetNumberOfSideSets(); ++i)
{
// Do we read this node set?
if (this->MetaData->GetSideSetStatus(i))
{
count += this->MetaData->GetSideSetSize(i);
}
}
// Return number of additional cell values needed
// to accommodate scalar fields count
return count;
}
//----------------------------------------------------------------------------
void vtkExodusReader::GenerateExtraArrays(vtkUnstructuredGrid* output)
{
vtkIntArray *array;
int count;
int blockId;
int i, j, numBlockElem;
int haveArray, getArray;
///////////////////////////////////////
// Get block array
///////////////////////////////////////
// Do I already have this array?
if (output->GetPointData()->GetArray( this->GetBlockIdArrayName() ) != NULL)
haveArray=1;
else
haveArray=0;
// Does the user want this array?
getArray = this->GenerateBlockIdCellArray;
// If I have the array and the user DOESN'T want it
// then remove the array from the output
if (haveArray && !getArray)
{
output->GetPointData()->RemoveArray( this->GetBlockIdArrayName() );
}
// If the user wants this array AND I don't already have it
// then read in the data
else if (getArray && !haveArray)
{
array = vtkIntArray::New();
array->SetNumberOfValues(this->NumberOfUsedElements);
count = 0;
for (i=0; i < this->MetaData->GetNumberOfBlocks(); ++i)
{
// Do we read this block?
if (this->MetaData->GetBlockStatus(i)==0)
continue;
numBlockElem = this->MetaData->GetNumElementsInBlock(i);
blockId = this->MetaData->GetBlockId(i);
for (j = 0; j < numBlockElem; ++j)
{
array->SetValue(count++,blockId);
}
}
// Padding cell arrays to have 'some' value for the addition
// of nodesets and sidesets
for(i=0;i<GetExtraCellCountForNodeSideSets();++i)
{
array->InsertNextValue(0);
}
array->SetName( this->GetBlockIdArrayName() );
output->GetCellData()->AddArray(array);
// Block IDs will be the default cell data
output->GetCellData()->SetScalars(array);
array->Delete();
array = NULL;
}
///////////////////////////////////////
// Get node id array
///////////////////////////////////////
// Do I already have this array?
if ( output->GetPointData()->GetArray(
this->GetGlobalNodeIdArrayName() ) != NULL)
{
haveArray = 1;
}
else
{
haveArray = 0;
}
// Does the user want this array?
getArray = this->GenerateGlobalNodeIdArray;
// If I have the array and the user DOESN'T want it
// then remove the array from the output
if (haveArray && !getArray)
{
output->GetPointData()->RemoveArray( this->GetGlobalNodeIdArrayName() );
}
// If the user wants this array AND I don't already have it
// then read in the data
else if (getArray && !haveArray)
{
// Temp int array
int *exo_array_data;
exo_array_data = new int[this->NumberOfNodesInFile];
// Temp vtk array
vtkIdTypeArray* idarray = vtkIdTypeArray::New();
idarray->SetNumberOfValues(this->NumberOfUsedNodes);
// Get the data into the temp int array
ex_get_node_num_map(this->CurrentHandle, exo_array_data);
cerr << "node num map : ";
for (i = 0; i < this->NumberOfNodesInFile; i ++)
{
cerr << exo_array_data[i] << " ";
}
cerr << endl;
// Okay copy the points that are actually used into the vtk array
int point_index;
for (i=0; i<this->NumberOfUsedNodes; i++)
{
point_index = this->ReversePointMap->GetValue(i);
idarray->SetValue(i, exo_array_data[point_index]);
}
// Clean up temp int array
delete [] exo_array_data;
// Set up array and 'give' to output
idarray->SetName( this->GetGlobalNodeIdArrayName() );
vtkIdTypeArray* pedigree = vtkIdTypeArray::New();
pedigree->DeepCopy(idarray);
pedigree->SetName(this->GetPedigreeNodeIdArrayName());
output->GetPointData()->AddArray(pedigree);
output->GetPointData()->SetGlobalIds(idarray);
// Delete my copy of the array
pedigree->Delete();
pedigree = NULL;
idarray->Delete();
idarray = NULL;
}
///////////////////////////////////////
// Get element id array
///////////////////////////////////////
// Do I already have this array?
if (output->GetPointData()->GetArray(
this->GetGlobalElementIdArrayName() ) != NULL)
{
haveArray=1;
}
else
{
haveArray=0;
}
// Does the user want this array?
getArray = this->GenerateGlobalElementIdArray;
// If I have the array and the user DOESN'T want it
// then remove the array from the output
if (haveArray && !getArray)
{
output->GetPointData()->RemoveArray( this->GetGlobalElementIdArrayName() );
}
// If the user wants this array AND I don't already have it
// then read in the data
else if (getArray && !haveArray)
{
int nblocks = this->GetNumberOfBlockArrays();
int nblocksUsed = 0;
for (i=0; i<nblocks; i++)
{
if (this->GetBlockArrayStatus(i) == 1)
{
nblocksUsed++;
}
}
if (!this->GlobalElementIdCache)
{
int *tmp = new int [this->NumberOfElementsInFile];
ex_get_elem_num_map(this->CurrentHandle, tmp);
this->GlobalElementIdCache = tmp;
}
int *idList = (int*)malloc(this->NumberOfUsedElements*sizeof(int));
if (nblocksUsed < nblocks)
{
int *from = this->GlobalElementIdCache;
int *to = idList;
for (i=0; i<nblocks; i++)
{
int used = this->GetBlockArrayStatus(i);
int bsize = this->GetNumberOfElementsInBlock(i);
if (used)
{