/*========================================================================= Program: Visualization Toolkit Module: vtkPLSDynaReader.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. ----------------------------------------------------------------------------*/ // NOTE TO DEVELOPERS: ======================================================== // // This is a parallel version of the LSDynaReader. // Its primary tasks are to determine which parts should be read on each process // and to send the relevant information from the master node to all slave nodes #include "vtkPLSDynaReader.h" #include "LSDynaMetaData.h" #include "LSDynaFamily.h" #include "vtkLSDynaPartCollection.h" #include "vtkIntArray.h" #include "vtkInformation.h" #include "vtkInformationVector.h" #include "vtkObjectFactory.h" #include "vtkMultiProcessController.h" #include "vtkMultiBlockDataSet.h" #include "vtkStreamingDemandDrivenPipeline.h" #include "vtkUnstructuredGrid.h" vtkStandardNewMacro(vtkPLSDynaReader); struct vtkPLSDynaReader::vtkPLSDynaReaderInternal { unsigned int MinDataset; unsigned int MaxDataset; unsigned int UpdatePiece; unsigned int UpdateNumPieces; vtkIdType NumProcesses; vtkIdType ProcessRank; vtkPLSDynaReaderInternal(): MinDataset(0), MaxDataset(0), UpdatePiece(0), UpdateNumPieces(0) {} }; //----------------------------------------------------------------------------- vtkPLSDynaReader::vtkPLSDynaReader() { this->Controller = nullptr; //need to construct the internal datastructure before call SetController this->Internal = new vtkPLSDynaReader::vtkPLSDynaReaderInternal(); this->SetController(vtkMultiProcessController::GetGlobalController()); } //----------------------------------------------------------------------------- vtkPLSDynaReader::~vtkPLSDynaReader() { this->SetController(nullptr); delete this->Internal; } void vtkPLSDynaReader::PrintSelf( ostream &os, vtkIndent indent ) { os << indent << "Controller: " << this->Controller << endl; this->Superclass::PrintSelf( os, indent ); } //---------------------------------------------------------------------------- void vtkPLSDynaReader::SetController(vtkMultiProcessController *c) { if ((c == nullptr) || (c->GetNumberOfProcesses() == 0)) { this->Internal->NumProcesses = 1; this->Internal->ProcessRank = 0; } if (this->Controller == c) { return; } this->Modified(); if (this->Controller) { this->Controller->UnRegister(this); this->Controller = nullptr; } if (c == nullptr) { return; } this->Controller = c; c->Register(this); this->Internal->NumProcesses = c->GetNumberOfProcesses(); this->Internal->ProcessRank = c->GetLocalProcessId(); } //----------------------------------------------------------------------------- int vtkPLSDynaReader::CanReadFile( const char* fname ) { return this->Superclass::CanReadFile(fname); } //----------------------------------------------------------------------------- int vtkPLSDynaReader::RequestInformation( vtkInformation* request, vtkInformationVector** iinfo, vtkInformationVector* outputVector ) { vtkInformation* outInfo = outputVector->GetInformationObject(0); //call the parents request information on all the nodes. //This is not optimal, but sooo much information is stored in the //metadata that is read during request information that sending it over the wire //might not be faster than each node contending for the info. Plus it would //be a massive chunk of code this->Superclass::RequestInformation(request,iinfo,outputVector); outInfo->Set(CAN_HANDLE_PIECE_REQUEST(), 1); return 1; } //----------------------------------------------------------------------------- int vtkPLSDynaReader::RequestData(vtkInformation* request, vtkInformationVector** inputVector, vtkInformationVector* outputVector ) { //get the information needed to determine which subsection of the full //data set we need to load vtkInformation* outInfo = outputVector->GetInformationObject(0); this->Internal->UpdatePiece = outInfo->Get(vtkStreamingDemandDrivenPipeline::UPDATE_PIECE_NUMBER()); this->Internal->UpdateNumPieces = outInfo->Get(vtkStreamingDemandDrivenPipeline::UPDATE_NUMBER_OF_PIECES()); return this->Superclass::RequestData(request,inputVector,outputVector); } //---------------------------------------------------------------------------- int vtkPLSDynaReader::ReadTopology() { bool readTopology=false; if(!this->Parts) { readTopology=true; this->Parts = vtkLSDynaPartCollection::New(); vtkIdType* minCellIds = new vtkIdType[LSDynaMetaData::NUM_CELL_TYPES]; vtkIdType* maxCellIds = new vtkIdType[LSDynaMetaData::NUM_CELL_TYPES]; this->GetPartRanges(minCellIds,maxCellIds); this->Parts->InitCollection(this->P,minCellIds,maxCellIds); delete[] minCellIds; delete[] maxCellIds; } if(!readTopology) { return 0; } if( this->ReadPartSizes()) { vtkErrorMacro( "Could not read cell sizes." ); return 1; } if ( this->ReadConnectivityAndMaterial() ) { vtkErrorMacro( "Could not read connectivity." ); return 1; } //finalize the topology on each process, each process will remove //any part that it doesn't have a cell for. this->Parts->FinalizeTopology(); if(this->ReadNodes()) { vtkErrorMacro("Could not read static node values."); return 1; } // we need to read the user ids after we have read the topology // so we know how many cells are in each part if ( this->ReadUserIds() ) { vtkErrorMacro( "Could not read user node/element IDs." ); return 1; } return 0; } //---------------------------------------------------------------------------- //determine which parts will be read by this processor void vtkPLSDynaReader::GetPartRanges(vtkIdType* mins, vtkIdType* maxs) { //1 == load the whole data //determine which domains in this mesh this processor is responsible for if ( this->Internal->UpdateNumPieces > 1 ) { double numCells; for(int i=0; i < LSDynaMetaData::NUM_CELL_TYPES;++i) { numCells = static_cast(this->P->NumberOfCells[i]); if(numCells > 1000) { double percent = (1.0 / this->Internal->UpdateNumPieces) * numCells; mins[i] = static_cast( percent * this->Internal->UpdatePiece); maxs[i] = static_cast( percent * (this->Internal->UpdatePiece+1)); } else { //else not enough cells to worth dividing the reading mins[i]=0; maxs[i]=static_cast( (this->Internal->ProcessRank==0)?numCells:0); } } } else { for(int i=0; i < LSDynaMetaData::NUM_CELL_TYPES;++i) { mins[i] = 0; maxs[i] = this->P->NumberOfCells[i]; } } }