Cloned library of VTK-5.0.0 with extra build files for internal package management.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

642 lines
15 KiB

/*=========================================================================
Program: Visualization Toolkit
Module: $RCSfile: vtkPChacoReader.cxx,v $
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 "vtkToolkits.h"
#include "vtkPChacoReader.h"
#include "vtkDataSetWriter.h"
#include "vtkDataSetReader.h"
#include "vtkExtractCells.h"
#include "vtkPKdTree.h"
#include "vtkObjectFactory.h"
#include "vtkUnstructuredGrid.h"
#include "vtkDoubleArray.h"
#include "vtkCharArray.h"
#include "vtkIntArray.h"
#include "vtkInformation.h"
#include "vtkInformationVector.h"
#include "vtkIntArray.h"
#include "vtkPointData.h"
#include "vtkCellData.h"
#include "vtkMultiProcessController.h"
#include "vtkStreamingDemandDrivenPipeline.h"
#ifdef VTK_USE_MPI
#include "vtkMPIController.h"
#include "vtkMPIGroup.h"
#endif
vtkCxxRevisionMacro(vtkPChacoReader, "$Revision: 1.8 $");
vtkStandardNewMacro(vtkPChacoReader);
//----------------------------------------------------------------------------
vtkPChacoReader::vtkPChacoReader()
{
this->Controller = NULL;
this->SetController(vtkMultiProcessController::GetGlobalController());
}
//----------------------------------------------------------------------------
vtkPChacoReader::~vtkPChacoReader()
{
this->SetController(NULL);
}
//----------------------------------------------------------------------------
void vtkPChacoReader::SetController(vtkMultiProcessController *c)
{
if ((c == NULL) || (c->GetNumberOfProcesses() == 0))
{
this->NumProcesses = 1;
this->MyId = 0;
}
if (this->Controller == c)
{
return;
}
this->Modified();
if (this->Controller != NULL)
{
this->Controller->UnRegister(this);
this->Controller = NULL;
}
if (c == NULL)
{
return;
}
this->Controller = c;
c->Register(this);
this->NumProcesses = c->GetNumberOfProcesses();
this->MyId = c->GetLocalProcessId();
}
//----------------------------------------------------------------------------
int vtkPChacoReader::RequestInformation(
vtkInformation *request,
vtkInformationVector **inputVector,
vtkInformationVector *outputVector)
{
if (!this->BaseName)
{
vtkErrorMacro(<< "No BaseName specified");
return 0;
}
// Setting maximum number of pieces to -1 indicates to the
// upstream consumer that I can provide the same number of pieces
// as there are number of processors
// get the info object
vtkInformation *outInfo = outputVector->GetInformationObject(0);
outInfo->Set(vtkStreamingDemandDrivenPipeline::MAXIMUM_NUMBER_OF_PIECES(),
-1);
if (!this->Controller->IsA("vtkMPIController"))
{
vtkErrorMacro(<< "parallel vtkPChacoReader requires MPI");
return 0;
}
int retVal = 1;
if (this->MyId == 0)
{
retVal =
this->Superclass::RequestInformation(request, inputVector, outputVector);
}
if (this->NumProcesses == 1)
{
return retVal;
}
unsigned long metadata[8];
if (this->MyId == 0)
{
metadata[0] = static_cast<unsigned long>(retVal);
if (retVal)
{
metadata[1] = static_cast<unsigned long>(this->RemakeDataCacheFlag);
if (this->RemakeDataCacheFlag)
{
metadata[2] = static_cast<unsigned long>(this->Dimensionality);
metadata[3] = static_cast<unsigned long>(this->NumberOfVertices);
metadata[4] = static_cast<unsigned long>(this->NumberOfEdges);
metadata[5] = static_cast<unsigned long>(this->NumberOfVertexWeights);
metadata[6] = static_cast<unsigned long>(this->NumberOfEdgeWeights);
metadata[7] = static_cast<unsigned long>(this->GraphFileHasVertexNumbers);
}
}
}
#ifdef VTK_USE_MPI
vtkMPICommunicator *comm =
vtkMPICommunicator::SafeDownCast(this->Controller->GetCommunicator());
comm->Broadcast(metadata, 8, 0);
#endif
if (this->MyId > 0)
{
retVal = metadata[0];
if (retVal)
{
this->RemakeDataCacheFlag = static_cast<int>(metadata[1]);
if (this->RemakeDataCacheFlag)
{
this->Dimensionality = static_cast<int>(metadata[2]);
this->NumberOfVertices = static_cast<vtkIdType>(metadata[3]);
this->NumberOfEdges = static_cast<vtkIdType>(metadata[4]);
this->NumberOfVertexWeights = static_cast<int>(metadata[5]);
this->NumberOfEdgeWeights = static_cast<int>(metadata[6]);
this->GraphFileHasVertexNumbers = static_cast<int>(metadata[7]);
this->MakeWeightArrayNames(this->NumberOfVertexWeights,
this->NumberOfEdgeWeights);
this->SetCurrentBaseName(this->BaseName);
}
}
}
return retVal;
}
//----------------------------------------------------------------------------
int vtkPChacoReader::RequestData(
vtkInformation *vtkNotUsed(request),
vtkInformationVector **vtkNotUsed(inputVector),
vtkInformationVector *outputVector)
{
if (!this->BaseName)
{
vtkErrorMacro(<< "No BaseName specified");
return 0;
}
vtkInformation* outInfo = outputVector->GetInformationObject(0);
vtkUnstructuredGrid *output = vtkUnstructuredGrid::SafeDownCast(
outInfo->Get(vtkDataObject::DATA_OBJECT()));
int piece =
outInfo->Get(vtkStreamingDemandDrivenPipeline::UPDATE_PIECE_NUMBER());
int numPieces =
outInfo->Get(vtkStreamingDemandDrivenPipeline::UPDATE_NUMBER_OF_PIECES());
int pieceZeroProc = 0;
vtkMultiProcessController *contr = this->Controller;
#ifdef VTK_USE_MPI
int i=0;
vtkMPICommunicator *comm =
vtkMPICommunicator::SafeDownCast(contr->GetCommunicator());
int oops = ((piece != this->MyId) || (numPieces != this->NumProcesses));
int sum = 0;
comm->ReduceSum(&oops, &sum, 1, 0);
comm->Broadcast(&sum, 1, 0);
if (sum > 0)
{
// I don't know if this situation can occur, but we'll try to handle it.
int *myPiece = new int [this->NumProcesses];
comm->AllGather(&piece, myPiece, 1);
vtkMPICommunicator *subComm = vtkMPICommunicator::New();
vtkMPIGroup *group = vtkMPIGroup::New();
vtkMPIController *subController = NULL;
group->Initialize(vtkMPIController::SafeDownCast(contr));
int nparticipants = 0;
for (i=0; i<this->NumProcesses; i++)
{
if ((myPiece[i] >= 0) && (myPiece[i] < numPieces))
{
group->AddProcessId(i);
if (i == this->MyId)
{
subController = vtkMPIController::New();
}
if (myPiece[i] == 0)
{
pieceZeroProc = nparticipants;
}
nparticipants++;
}
}
delete [] myPiece;
if (nparticipants < numPieces) // Can this happen?
{
subComm->Delete();
group->Delete();
if (subController)
{
subController->Delete();
}
output->Initialize();
vtkErrorMacro("<<vtkPChacoReader can't produce less than entire file");
return 0;
}
subComm->Initialize(comm, group);
group->Delete();
if (subController)
{
subController->SetCommunicator(subComm);
contr = subController;
comm = subComm;
}
else
{
subComm->Delete();
contr = NULL;
comm = NULL;
}
}
#endif
if ( !contr)
{
// This process doesn't participate (can this happen?)
this->SetUpEmptyGrid(output);
return 1;
}
int retVal = 1;
if (piece == 0)
{
// "piece" 0 reads in the entire mesh
retVal = this->BuildOutputGrid(output);
}
if (numPieces > 1)
{
#ifdef VTK_USE_MPI
comm->Broadcast(&retVal, 1, pieceZeroProc);
#endif
if (retVal == 1)
{
retVal = this->DivideCells(contr, output, pieceZeroProc);
}
}
if (contr != this->Controller)
{
#ifdef VTK_USE_MPI
comm->Delete();
#endif
contr->Delete();
}
return retVal;
}
//----------------------------------------------------------------------------
void vtkPChacoReader::SetUpEmptyGrid(vtkUnstructuredGrid *output)
{
int i;
// Note: The cell and point arrays should be added in the same order in
// which they are added in vtkChacoReader::BuildOutputGrid. See "Note" in
// vtkChacoReader.cxx.
output->Initialize();
if (this->GetGenerateVertexWeightArrays())
{
for (i=0; i < this->NumberOfVertexWeights; i++)
{
vtkDoubleArray *da = vtkDoubleArray::New();
da->SetNumberOfTuples(0);
da->SetNumberOfComponents(1);
da->SetName(this->GetVertexWeightArrayName(i+1));
output->GetPointData()->AddArray(da);
da->Delete();
}
this->NumberOfPointWeightArrays = this->NumberOfVertexWeights;
}
if (this->GetGenerateEdgeWeightArrays())
{
for (i=0; i < this->NumberOfEdgeWeights; i++)
{
vtkDoubleArray *da = vtkDoubleArray::New();
da->SetNumberOfTuples(0);
da->SetNumberOfComponents(1);
da->SetName(this->GetEdgeWeightArrayName(i+1));
output->GetCellData()->AddArray(da);
da->Delete();
}
this->NumberOfCellWeightArrays = this->NumberOfEdgeWeights;
}
if (this->GetGenerateGlobalElementIdArray())
{
vtkIntArray *ia = vtkIntArray::New();
ia->SetNumberOfTuples(0);
ia->SetNumberOfComponents(1);
ia->SetName(this->GetGlobalElementIdArrayName());
output->GetCellData()->AddArray(ia);
}
if (this->GetGenerateGlobalNodeIdArray())
{
vtkIntArray *ia = vtkIntArray::New();
ia->SetNumberOfTuples(0);
ia->SetNumberOfComponents(1);
ia->SetName(this->GetGlobalNodeIdArrayName());
output->GetPointData()->AddArray(ia);
}
}
//----------------------------------------------------------------------------
int vtkPChacoReader::DivideCells(vtkMultiProcessController *contr,
vtkUnstructuredGrid *output, int source)
{
int retVal = 1;
#ifdef VTK_USE_MPI
int i=0;
vtkMPICommunicator *comm =
vtkMPICommunicator::SafeDownCast(contr->GetCommunicator());
int nprocs = contr->GetNumberOfProcesses();
int myrank = contr->GetLocalProcessId();
vtkUnstructuredGrid *mygrid = NULL;
if (source == myrank)
{
vtkIdType ntotalcells = output->GetNumberOfCells();
vtkIdType nshare = ntotalcells / nprocs;
vtkIdType leftover = ntotalcells - (nprocs * nshare);
vtkIdType startId = 0;
for (i=0; i < nprocs; i++)
{
if (!retVal && (i != myrank))
{
this->SendGrid(contr, i, NULL); // we failed
continue;
}
vtkIdType ncells = ((i < leftover) ? nshare + 1 : nshare);
vtkIdType endId = startId + ncells - 1;
vtkUnstructuredGrid *ug = this->SubGrid(output, startId, endId);
if (i != myrank)
{
retVal = this->SendGrid(contr, i, ug);
ug->Delete();
}
else
{
mygrid = ug;
}
startId += ncells;
}
}
else
{
mygrid = this->GetGrid(contr, source);
if (mygrid == NULL)
{
retVal = 0;
}
}
int vote = 0;
comm->ReduceSum(&retVal, &vote, 1, 0);
comm->Broadcast(&vote, 1, 0);
if (vote < nprocs)
{
retVal = 0;
}
output->Initialize();
if (retVal)
{
output->ShallowCopy(mygrid);
}
else if (mygrid)
{
mygrid->Delete();
}
#else
vtkErrorMacro(<< "vtkPChacoReader::DivideCells requires MPI");
(void)source;
(void)contr;
(void)output;
#endif
return retVal;
}
int vtkPChacoReader::SendGrid(vtkMultiProcessController *c,
int to, vtkUnstructuredGrid *grid)
{
int retVal = 1;
#ifdef VTK_USE_MPI
vtkMPIController *contr = vtkMPIController::SafeDownCast(c);
int bufsize=0, ack = 0;
if (!grid)
{
// sending notice of a failure
contr->Send(&bufsize, 1, to, 0x11);
return retVal;
}
char *buf = this->MarshallDataSet(grid, bufsize);
contr->Send(&bufsize, 1, to, 0x11);
contr->Receive(&ack, 1, to, 0x12);
if (!ack)
{
retVal = 0;
}
else
{
contr->Send(buf, bufsize, to, 0x13);
}
delete [] buf;
#else
vtkErrorMacro(<< "vtkPChacoReader::SendGrid requires MPI");
(void)c;
(void)to;
(void)grid;
#endif
return retVal;
}
vtkUnstructuredGrid *vtkPChacoReader::GetGrid(vtkMultiProcessController *c, int from)
{
vtkUnstructuredGrid *grid = NULL;
#ifdef VTK_USE_MPI
vtkMPIController *contr = vtkMPIController::SafeDownCast(c);
int bufsize=0, ack=1;
contr->Receive(&bufsize, 1, from, 0x11);
if (bufsize == 0)
{
// Node zero is reporting an error
return NULL;
}
char *buf = new char [bufsize];
if (buf)
{
contr->Send(&ack, 1, from, 0x12);
contr->Receive(buf, bufsize, from, 0x13);
grid = this->UnMarshallDataSet(buf, bufsize);
delete [] buf;
}
else
{
ack = 0;
contr->Send(&ack, 1, 0, 0x12);
}
#else
vtkErrorMacro(<< "vtkPChacoReader::GetGrid requires MPI");
(void)c;
(void)from;
#endif
return grid;
}
vtkUnstructuredGrid *
vtkPChacoReader::SubGrid(vtkUnstructuredGrid *ug, vtkIdType from, vtkIdType to)
{
vtkUnstructuredGrid *tmp = vtkUnstructuredGrid::New();
if (from > to)
{
this->SetUpEmptyGrid(tmp);
}
else
{
tmp->ShallowCopy(ug);
vtkExtractCells *ec = vtkExtractCells::New();
ec->AddCellRange(from, to);
ec->SetInput(tmp);
ec->Update();
tmp->Initialize();
tmp->ShallowCopy(ec->GetOutput());
ec->Delete();
}
return tmp;
}
char *vtkPChacoReader::MarshallDataSet(vtkUnstructuredGrid *extractedGrid, int &len)
{
// taken from vtkCommunicator::WriteDataSet
vtkUnstructuredGrid *copy;
vtkDataSetWriter *writer = vtkDataSetWriter::New();
copy = extractedGrid->NewInstance();
copy->ShallowCopy(extractedGrid);
// There is a problem with binary files with no data.
if (copy->GetNumberOfCells() > 0)
{
writer->SetFileTypeToBinary();
}
writer->WriteToOutputStringOn();
writer->SetInput(copy);
writer->Write();
len = writer->GetOutputStringLength();
char *packedFormat = writer->RegisterAndGetOutputString();
writer->Delete();
copy->Delete();
return packedFormat;
}
vtkUnstructuredGrid *vtkPChacoReader::UnMarshallDataSet(char *buf, int size)
{
// taken from vtkCommunicator::ReadDataSet
vtkDataSetReader *reader = vtkDataSetReader::New();
reader->ReadFromInputStringOn();
vtkCharArray* mystring = vtkCharArray::New();
mystring->SetArray(buf, size, 1);
reader->SetInputArray(mystring);
mystring->Delete();
vtkDataSet *output = reader->GetOutput();
output->Update();
vtkUnstructuredGrid *newGrid = vtkUnstructuredGrid::New();
newGrid->ShallowCopy(output);
reader->Delete();
return newGrid;
}
//----------------------------------------------------------------------------
void vtkPChacoReader::PrintSelf(ostream& os, vtkIndent indent)
{
vtkChacoReader::PrintSelf(os,indent);
os << indent << "MyId: " << this->MyId << endl;
os << indent << "NumProcesses: " << this->NumProcesses << endl;
os << indent << "Controller: " << this->Controller << endl;
}