mirror of
https://github.com/OpenFOAM/ThirdParty-6.git
synced 2025-12-08 06:57:43 +00:00
1692 lines
53 KiB
C++
1692 lines
53 KiB
C++
/*=========================================================================
|
|
|
|
Program: Visualization Toolkit
|
|
Module: vtkCommunicator.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.
|
|
|
|
=========================================================================*/
|
|
#include "vtkCommunicator.h"
|
|
|
|
#include "vtkBoundingBox.h"
|
|
#include "vtkCharArray.h"
|
|
#include "vtkCompositeDataSet.h"
|
|
#include "vtkDataObjectTypes.h"
|
|
#include "vtkDataSetAttributes.h"
|
|
#include "vtkDataSetReader.h"
|
|
#include "vtkDataSetWriter.h"
|
|
#include "vtkDoubleArray.h"
|
|
#include "vtkFloatArray.h"
|
|
#include "vtkGenericDataObjectReader.h"
|
|
#include "vtkGenericDataObjectWriter.h"
|
|
#include "vtkIdTypeArray.h"
|
|
#include "vtkImageData.h"
|
|
#include "vtkIntArray.h"
|
|
#include "vtkMultiProcessController.h"
|
|
#include "vtkMultiProcessStream.h"
|
|
#include "vtkNew.h"
|
|
#include "vtkRectilinearGrid.h"
|
|
#include "vtkSmartPointer.h"
|
|
#include "vtkStructuredGrid.h"
|
|
#include "vtkStructuredPoints.h"
|
|
#include "vtkTypeTraits.h"
|
|
#include "vtkTable.h"
|
|
#include "vtkUnsignedCharArray.h"
|
|
#include "vtkUnsignedLongArray.h"
|
|
|
|
#define VTK_CREATE(type, name) \
|
|
vtkSmartPointer<type> name = vtkSmartPointer<type>::New()
|
|
|
|
#include <algorithm>
|
|
#include <vector>
|
|
|
|
|
|
#define EXTENT_HEADER_SIZE 128
|
|
|
|
//=============================================================================
|
|
// Functions and classes that perform the default reduction operations.
|
|
#define STANDARD_OPERATION_DEFINITION(name, op) \
|
|
template<class T> \
|
|
void vtkCommunicator##name##Func(const T *A, T *B, vtkIdType length) \
|
|
{ \
|
|
for (vtkIdType i = 0; i < length; i++) B[i] = (op); \
|
|
} \
|
|
class vtkCommunicator##name##Class \
|
|
: public vtkCommunicator::Operation \
|
|
{ \
|
|
public: \
|
|
void Function(const void *A, void *B, vtkIdType length, int datatype) { \
|
|
switch (datatype) \
|
|
{ \
|
|
vtkTemplateMacro(vtkCommunicator##name##Func \
|
|
(reinterpret_cast<const VTK_TT *>(A), \
|
|
reinterpret_cast<VTK_TT *>(B), \
|
|
length)); \
|
|
} \
|
|
} \
|
|
int Commutative() { return 1; } \
|
|
};
|
|
|
|
#define STANDARD_OPERATION_FLOAT_OVERRIDE(name) \
|
|
static void vtkCommunicator##name##Func(const double *, double *, vtkIdType)\
|
|
{ \
|
|
vtkGenericWarningMacro(<< #name \
|
|
<< " not supported for floating point numbers"); \
|
|
} \
|
|
static void vtkCommunicator##name##Func(const float *, float *, vtkIdType) \
|
|
{ \
|
|
vtkGenericWarningMacro(<< #name \
|
|
<< " not supported for floating point numbers"); \
|
|
}
|
|
|
|
STANDARD_OPERATION_DEFINITION(Max, (A[i] < B[i] ? B[i] : A[i]));
|
|
STANDARD_OPERATION_DEFINITION(Min, (A[i] < B[i] ? A[i] : B[i]));
|
|
STANDARD_OPERATION_DEFINITION(Sum, A[i] + B[i]);
|
|
STANDARD_OPERATION_DEFINITION(Product, A[i] * B[i]);
|
|
STANDARD_OPERATION_FLOAT_OVERRIDE(LogicalAnd);
|
|
STANDARD_OPERATION_DEFINITION(LogicalAnd, A[i] && B[i]);
|
|
STANDARD_OPERATION_FLOAT_OVERRIDE(BitwiseAnd);
|
|
STANDARD_OPERATION_DEFINITION(BitwiseAnd, A[i] & B[i]);
|
|
STANDARD_OPERATION_FLOAT_OVERRIDE(LogicalOr);
|
|
STANDARD_OPERATION_DEFINITION(LogicalOr, A[i] || B[i]);
|
|
STANDARD_OPERATION_FLOAT_OVERRIDE(BitwiseOr);
|
|
STANDARD_OPERATION_DEFINITION(BitwiseOr, A[i] | B[i]);
|
|
STANDARD_OPERATION_FLOAT_OVERRIDE(LogicalXor);
|
|
STANDARD_OPERATION_DEFINITION(LogicalXor, (!A[i] && B[i]) || (A[i] && !B[i]));
|
|
STANDARD_OPERATION_FLOAT_OVERRIDE(BitwiseXor);
|
|
STANDARD_OPERATION_DEFINITION(BitwiseXor, A[i] ^ B[i]);
|
|
|
|
//=============================================================================
|
|
vtkCommunicator::vtkCommunicator()
|
|
{
|
|
this->LocalProcessId = 0;
|
|
this->NumberOfProcesses = 1;
|
|
this->MaximumNumberOfProcesses = vtkTypeTraits<int>::Max();
|
|
this->Count = 0;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
vtkCommunicator::~vtkCommunicator()
|
|
{
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
int vtkCommunicator::UseCopy = 0;
|
|
void vtkCommunicator::SetUseCopy(int useCopy)
|
|
{
|
|
vtkCommunicator::UseCopy = useCopy;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
void vtkCommunicator::PrintSelf(ostream& os, vtkIndent indent)
|
|
{
|
|
this->Superclass::PrintSelf(os, indent);
|
|
|
|
os << indent << "MaximumNumberOfProcesses: "
|
|
<< this->MaximumNumberOfProcesses << endl;
|
|
os << indent << "NumberOfProcesses: " << this->NumberOfProcesses << endl;
|
|
os << indent << "LocalProcessId: " << this->LocalProcessId << endl;
|
|
os << indent << "Count: " << this->Count << endl;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
void vtkCommunicator::SetNumberOfProcesses(int num)
|
|
{
|
|
if (num == this->NumberOfProcesses)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (num < 1 || num > this->MaximumNumberOfProcesses)
|
|
{
|
|
vtkErrorMacro( << num
|
|
<< " is an invalid number of processes try a number from 1 to "
|
|
<< this->NumberOfProcesses );
|
|
return;
|
|
}
|
|
|
|
this->NumberOfProcesses = num;
|
|
this->Modified();
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
// Need to add better error checking
|
|
int vtkCommunicator::Send(vtkDataObject* data, int remoteHandle,
|
|
int tag)
|
|
{
|
|
// If the receiving end is using with ANY_SOURCE, we have a problem because
|
|
// some versions of MPI might deliver the multiple data objects require out of
|
|
// order. To get around this, on the first message we send the actual source
|
|
// and a mangled tag. The remote process then receives the rest of the
|
|
// messages with the specific source and mangled tag, which are guaranteed to
|
|
// be received in the correct order.
|
|
static int tagMangler = 1000;
|
|
int mangledTag = tag + tagMangler++;
|
|
int header[2];
|
|
header[0] = this->LocalProcessId; header[1] = mangledTag;
|
|
this->Send(header, 2, remoteHandle, tag);
|
|
tag = mangledTag;
|
|
|
|
int data_type = data? data->GetDataObjectType() : -1;
|
|
this->Send(&data_type, 1, remoteHandle, tag);
|
|
|
|
switch(data_type)
|
|
{
|
|
case -1:
|
|
// NULL data.
|
|
return 1;
|
|
|
|
//error on types we can't send
|
|
case VTK_DATA_OBJECT:
|
|
case VTK_DATA_SET:
|
|
case VTK_PIECEWISE_FUNCTION:
|
|
case VTK_POINT_SET:
|
|
case VTK_UNIFORM_GRID:
|
|
case VTK_GENERIC_DATA_SET:
|
|
case VTK_HYPER_OCTREE:
|
|
case VTK_COMPOSITE_DATA_SET:
|
|
case VTK_HIERARCHICAL_BOX_DATA_SET: // since we cannot send vtkUniformGrid anyways.
|
|
case VTK_MULTIGROUP_DATA_SET: // obsolete
|
|
case VTK_HIERARCHICAL_DATA_SET: //obsolete
|
|
default:
|
|
vtkWarningMacro(<< "Cannot send " << data->GetClassName());
|
|
return 0;
|
|
|
|
//send elemental data objects
|
|
case VTK_DIRECTED_GRAPH:
|
|
case VTK_UNDIRECTED_GRAPH:
|
|
case VTK_IMAGE_DATA:
|
|
case VTK_POLY_DATA:
|
|
case VTK_RECTILINEAR_GRID:
|
|
case VTK_STRUCTURED_GRID:
|
|
case VTK_STRUCTURED_POINTS:
|
|
case VTK_TABLE:
|
|
case VTK_TREE:
|
|
case VTK_UNSTRUCTURED_GRID:
|
|
case VTK_MULTIBLOCK_DATA_SET:
|
|
case VTK_UNIFORM_GRID_AMR:
|
|
return this->SendElementalDataObject(data, remoteHandle, tag);
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
int vtkCommunicator::SendElementalDataObject(
|
|
vtkDataObject* data, int remoteHandle,
|
|
int tag)
|
|
{
|
|
VTK_CREATE(vtkCharArray, buffer);
|
|
if (vtkCommunicator::MarshalDataObject(data, buffer))
|
|
{
|
|
return this->Send(buffer, remoteHandle, tag);
|
|
}
|
|
|
|
// could not marshal data
|
|
return 0;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
int vtkCommunicator::Send(vtkDataArray* data, int remoteHandle, int tag)
|
|
{
|
|
// If the receiving end is using with ANY_SOURCE, we have a problem because
|
|
// some versions of MPI might deliver the multiple data objects require out of
|
|
// order. To get around this, on the first message we send the actual source
|
|
// and a mangled tag. The remote process then receives the rest of the
|
|
// messages with the specific source and mangled tag, which are guaranteed to
|
|
// be received in the correct order.
|
|
static int tagMangler = 1000;
|
|
int mangledTag = tag + tagMangler++;
|
|
int header[2];
|
|
header[0] = this->LocalProcessId; header[1] = mangledTag;
|
|
this->Send(header, 2, remoteHandle, tag);
|
|
tag = mangledTag;
|
|
|
|
int type = -1;
|
|
if (data == NULL)
|
|
{
|
|
this->Send( &type, 1, remoteHandle, tag);
|
|
return 1;
|
|
}
|
|
|
|
// send array type
|
|
type = data->GetDataType();
|
|
this->Send( &type, 1, remoteHandle, tag);
|
|
|
|
// send array tuples
|
|
vtkIdType numTuples = data->GetNumberOfTuples();
|
|
this->Send( &numTuples, 1, remoteHandle, tag);
|
|
|
|
// send number of components in array
|
|
int numComponents = data->GetNumberOfComponents();
|
|
this->Send( &numComponents, 1, remoteHandle, tag);
|
|
|
|
vtkIdType size = numTuples*numComponents;
|
|
|
|
const char* name = data->GetName();
|
|
int len = 0;
|
|
if (name)
|
|
{
|
|
len = static_cast<int>(strlen(name)) + 1;
|
|
}
|
|
|
|
// send length of name
|
|
this->Send( &len, 1, remoteHandle, tag);
|
|
|
|
if (len > 0)
|
|
{
|
|
// send name
|
|
this->Send( const_cast<char*>(name), len, remoteHandle, tag);
|
|
}
|
|
|
|
// do nothing if size is zero.
|
|
if (size == 0)
|
|
{
|
|
return 1;
|
|
}
|
|
|
|
// now send the raw array
|
|
this->SendVoidArray(data->GetVoidPointer(0), size, type, remoteHandle, tag);
|
|
return 1;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
int vtkCommunicator::Receive(vtkDataObject* data, int remoteHandle,
|
|
int tag)
|
|
{
|
|
//fill in the data object we are given
|
|
return this->ReceiveDataObject(data, remoteHandle, tag, -1);
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
vtkDataObject *vtkCommunicator::ReceiveDataObject(int remoteHandle, int tag)
|
|
{
|
|
// If we are receiving with ANY_SOURCE, we have a problem because some
|
|
// versions of MPI might deliver the multiple data objects require out of
|
|
// order. To get around this, on the first message we receive the actual
|
|
// source and a mangled tag. We then receive the rest of the messages with
|
|
// the specific source and mangled tag, which we are guaranteed to receive in
|
|
// the correct order.
|
|
int header[2];
|
|
this->Receive(header, 2, remoteHandle, tag);
|
|
// Use the specific source and tag.
|
|
if (remoteHandle == vtkMultiProcessController::ANY_SOURCE)
|
|
{
|
|
remoteHandle = header[0];
|
|
}
|
|
tag = header[1];
|
|
|
|
int data_type = 0;
|
|
this->Receive(&data_type, 1, remoteHandle, tag);
|
|
if (data_type < 0)
|
|
{
|
|
// NULL data object.
|
|
return NULL;
|
|
}
|
|
//manufacture a data object of the proper type to fill
|
|
vtkDataObject * dObj = vtkDataObjectTypes::NewDataObject(data_type);
|
|
if (dObj != NULL)
|
|
{
|
|
if (this->ReceiveDataObject(dObj, remoteHandle, tag, data_type) == 1)
|
|
{
|
|
return dObj;
|
|
}
|
|
}
|
|
if (dObj)
|
|
{
|
|
dObj->Delete();
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
int vtkCommunicator::ReceiveDataObject(vtkDataObject* data, int remoteHandle,
|
|
int tag, int dataType)
|
|
{
|
|
// If we have not yet received the data type, get the header and data type.
|
|
int data_type = dataType;
|
|
if (data_type == -1)
|
|
{
|
|
// If we are receiving with ANY_SOURCE, we have a problem because some
|
|
// versions of MPI might deliver the multiple data objects require out of
|
|
// order. To get around this, on the first message we receive the actual
|
|
// source and a mangled tag. We then receive the rest of the messages with
|
|
// the specific source and mangled tag, which we are guaranteed to receive
|
|
// in the correct order.
|
|
int header[2];
|
|
this->Receive(header, 2, remoteHandle, tag);
|
|
// Use the specific source and tag.
|
|
if (remoteHandle == vtkMultiProcessController::ANY_SOURCE)
|
|
{
|
|
remoteHandle = header[0];
|
|
}
|
|
tag = header[1];
|
|
|
|
this->Receive(&data_type, 1, remoteHandle, tag);
|
|
if (data->GetDataObjectType() != data_type)
|
|
{
|
|
vtkErrorMacro("Cannot receive object, type sent is different from destination.");
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
switch(data_type)
|
|
{
|
|
//error on types we can't receive
|
|
case VTK_DATA_OBJECT:
|
|
case VTK_DATA_SET:
|
|
case VTK_PIECEWISE_FUNCTION:
|
|
case VTK_POINT_SET:
|
|
case VTK_UNIFORM_GRID:
|
|
case VTK_GENERIC_DATA_SET:
|
|
case VTK_HYPER_OCTREE:
|
|
case VTK_COMPOSITE_DATA_SET:
|
|
case VTK_HIERARCHICAL_BOX_DATA_SET: // since we cannot send vtkUniformGrid anyways.
|
|
case VTK_MULTIGROUP_DATA_SET: //obsolete.
|
|
case VTK_HIERARCHICAL_DATA_SET: // obsolete.
|
|
default:
|
|
vtkWarningMacro(
|
|
<< "Cannot receive "
|
|
<< vtkDataObjectTypes::GetClassNameFromTypeId(data_type));
|
|
return 0;
|
|
|
|
//receive elemental data objects
|
|
case VTK_DIRECTED_GRAPH:
|
|
case VTK_UNDIRECTED_GRAPH:
|
|
case VTK_IMAGE_DATA:
|
|
case VTK_POLY_DATA:
|
|
case VTK_RECTILINEAR_GRID:
|
|
case VTK_STRUCTURED_GRID:
|
|
case VTK_STRUCTURED_POINTS:
|
|
case VTK_TABLE:
|
|
case VTK_TREE:
|
|
case VTK_UNSTRUCTURED_GRID:
|
|
case VTK_MULTIBLOCK_DATA_SET:
|
|
case VTK_UNIFORM_GRID_AMR:
|
|
return this->ReceiveElementalDataObject(data, remoteHandle, tag);
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
int vtkCommunicator::ReceiveElementalDataObject(
|
|
vtkDataObject* data, int remoteHandle,
|
|
int tag)
|
|
{
|
|
VTK_CREATE(vtkCharArray, buffer);
|
|
if (!this->Receive(buffer, remoteHandle, tag))
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
return vtkCommunicator::UnMarshalDataObject(buffer, data);
|
|
}
|
|
|
|
int vtkCommunicator::Receive(vtkDataArray* data, int remoteHandle, int tag)
|
|
{
|
|
// If we are receiving with ANY_SOURCE, we have a problem because some
|
|
// versions of MPI might deliver the multiple data objects require out of
|
|
// order. To get around this, on the first message we receive the actual
|
|
// source and a mangled tag. We then receive the rest of the messages with
|
|
// the specific source and mangled tag, which we are guaranteed to receive in
|
|
// the correct order.
|
|
int header[2];
|
|
this->Receive(header, 2, remoteHandle, tag);
|
|
// Use the specific source and tag.
|
|
if (remoteHandle == vtkMultiProcessController::ANY_SOURCE)
|
|
{
|
|
remoteHandle = header[0];
|
|
}
|
|
tag = header[1];
|
|
|
|
// First receive the data type.
|
|
int type;
|
|
if (!this->Receive( &type, 1, remoteHandle, tag))
|
|
{
|
|
vtkErrorMacro("Could not receive data!");
|
|
return 0;
|
|
}
|
|
|
|
if (type == -1)
|
|
{ // This indicates a NULL object was sent. Do nothing.
|
|
return 1;
|
|
}
|
|
|
|
if (type != data->GetDataType())
|
|
{
|
|
vtkErrorMacro("Send/receive data types do not match!");
|
|
return 0;
|
|
}
|
|
|
|
// Next receive the number of tuples.
|
|
vtkIdType numTuples;
|
|
if (!this->Receive( &numTuples, 1, remoteHandle, tag))
|
|
{
|
|
vtkErrorMacro("Could not receive data!");
|
|
return 0;
|
|
}
|
|
|
|
// Next receive the number of components.
|
|
int numComponents;
|
|
this->Receive( &numComponents, 1, remoteHandle, tag);
|
|
|
|
vtkIdType size = numTuples*numComponents;
|
|
data->SetNumberOfComponents(numComponents);
|
|
data->SetNumberOfTuples(numTuples);
|
|
|
|
// Next receive the length of the name.
|
|
int nameLength;
|
|
this->Receive( &nameLength, 1, remoteHandle, tag);
|
|
|
|
if ( nameLength > 0 )
|
|
{
|
|
char *str = new char[nameLength];
|
|
|
|
// Receive the name
|
|
this->Receive(str, nameLength, remoteHandle, tag);
|
|
data->SetName(str);
|
|
}
|
|
else
|
|
{
|
|
data->SetName(NULL);
|
|
}
|
|
|
|
if (size < 0)
|
|
{
|
|
vtkErrorMacro("Bad data length");
|
|
return 0;
|
|
}
|
|
|
|
// Do nothing if size is zero.
|
|
if (size == 0)
|
|
{
|
|
return 1;
|
|
}
|
|
|
|
// now receive the raw array.
|
|
this->ReceiveVoidArray(data->GetVoidPointer(0), size, type, remoteHandle,tag);
|
|
|
|
return 1;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
int vtkCommunicator::MarshalDataObject(vtkDataObject *object,
|
|
vtkCharArray *buffer)
|
|
{
|
|
buffer->Initialize();
|
|
buffer->SetNumberOfComponents(1);
|
|
|
|
if (object == NULL)
|
|
{
|
|
buffer->SetNumberOfTuples(0);
|
|
return 1;
|
|
}
|
|
|
|
VTK_CREATE(vtkGenericDataObjectWriter, writer);
|
|
|
|
vtkSmartPointer<vtkDataObject> copy;
|
|
copy.TakeReference(object->NewInstance());
|
|
copy->ShallowCopy(object);
|
|
|
|
writer->SetFileTypeToBinary();
|
|
// There is a problem with binary files with no data.
|
|
if (vtkDataSet::SafeDownCast(copy) != NULL)
|
|
{
|
|
vtkDataSet *ds = vtkDataSet::SafeDownCast(copy);
|
|
if (ds->GetNumberOfCells() + ds->GetNumberOfPoints() == 0)
|
|
{
|
|
writer->SetFileTypeToASCII();
|
|
}
|
|
}
|
|
writer->WriteToOutputStringOn();
|
|
writer->SetInputData(copy);
|
|
|
|
if (!writer->Write())
|
|
{
|
|
vtkGenericWarningMacro("Error detected while marshaling data object.");
|
|
return 0;
|
|
}
|
|
unsigned int size = writer->GetOutputStringLength();
|
|
if (object->GetExtentType() == VTK_3D_EXTENT)
|
|
{
|
|
// You would think that the extent information would be properly saved, but
|
|
// no, it is not.
|
|
int extent[6] = {0,0,0,0,0,0};
|
|
vtkRectilinearGrid* rg = vtkRectilinearGrid::SafeDownCast(object);
|
|
vtkStructuredGrid* sg = vtkStructuredGrid::SafeDownCast(object);
|
|
vtkImageData* id = vtkImageData::SafeDownCast(object);
|
|
if (rg)
|
|
{
|
|
rg->GetExtent(extent);
|
|
}
|
|
else if (sg)
|
|
{
|
|
sg->GetExtent(extent);
|
|
}
|
|
else if (id)
|
|
{
|
|
id->GetExtent(extent);
|
|
}
|
|
char extentHeader[EXTENT_HEADER_SIZE];
|
|
sprintf(extentHeader, "EXTENT %d %d %d %d %d %d",
|
|
extent[0], extent[1], extent[2], extent[3], extent[4], extent[5]);
|
|
|
|
buffer->SetNumberOfTuples(size+EXTENT_HEADER_SIZE);
|
|
memcpy(buffer->GetPointer(0), extentHeader, EXTENT_HEADER_SIZE);
|
|
memcpy(buffer->GetPointer(EXTENT_HEADER_SIZE), writer->GetOutputString(),
|
|
size);
|
|
}
|
|
else
|
|
{
|
|
buffer->SetArray(writer->RegisterAndGetOutputString(),
|
|
size,
|
|
0,
|
|
vtkCharArray::VTK_DATA_ARRAY_DELETE);
|
|
buffer->SetNumberOfTuples(size);
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
int vtkCommunicator::UnMarshalDataObject(vtkCharArray *buffer,
|
|
vtkDataObject *object)
|
|
{
|
|
vtkIdType bufferSize = buffer->GetNumberOfTuples();
|
|
if (bufferSize <= 0)
|
|
{
|
|
object = NULL;
|
|
return 1;
|
|
}
|
|
|
|
// You would think that the extent information would be properly saved, but
|
|
// no, it is not.
|
|
int extent[6] = {0,0,0,0,0,0};
|
|
char *bufferArray = buffer->GetPointer(0);
|
|
if (strncmp(bufferArray, "EXTENT", 6) == 0)
|
|
{
|
|
sscanf(bufferArray, "EXTENT %d %d %d %d %d %d", &extent[0], &extent[1],
|
|
&extent[2], &extent[3], &extent[4], &extent[5]);
|
|
bufferArray += EXTENT_HEADER_SIZE;
|
|
bufferSize -= EXTENT_HEADER_SIZE;
|
|
}
|
|
|
|
// Make a temporary array object holding the part of the buffer that can be
|
|
// parsed by the reader.
|
|
VTK_CREATE(vtkCharArray, objectBuffer);
|
|
objectBuffer->SetNumberOfComponents(1);
|
|
objectBuffer->SetArray(bufferArray, bufferSize, 1);
|
|
|
|
VTK_CREATE(vtkGenericDataObjectReader, reader);
|
|
reader->ReadFromInputStringOn();
|
|
|
|
reader->SetInputArray(objectBuffer);
|
|
|
|
reader->Update();
|
|
if (!reader->GetOutput()->IsA(object->GetClassName()))
|
|
{
|
|
vtkGenericWarningMacro("Type mismatch while unmarshalling data.");
|
|
}
|
|
object->ShallowCopy(reader->GetOutput());
|
|
|
|
if (object->GetExtentType() == VTK_3D_EXTENT)
|
|
{
|
|
vtkRectilinearGrid* rg = vtkRectilinearGrid::SafeDownCast(object);
|
|
vtkStructuredGrid* sg = vtkStructuredGrid::SafeDownCast(object);
|
|
vtkImageData* id = vtkImageData::SafeDownCast(object);
|
|
if (rg)
|
|
{
|
|
rg->SetExtent(extent);
|
|
}
|
|
else if (sg)
|
|
{
|
|
sg->SetExtent(extent);
|
|
}
|
|
else if (id)
|
|
{
|
|
// If we fix the extent, we need to fix the origin too.
|
|
double origin[3];
|
|
id->GetOrigin(origin);
|
|
double spacing[3];
|
|
id->GetSpacing(spacing);
|
|
int readerExt[6];
|
|
id->GetExtent(readerExt);
|
|
for (int i=0; i<3; i++)
|
|
{
|
|
if (readerExt[2*i] != extent[2*i])
|
|
{
|
|
origin[i] = origin[i] - (extent[2*i] - readerExt[2*i])*spacing[i];
|
|
}
|
|
}
|
|
id->SetExtent(extent);
|
|
id->SetOrigin(origin);
|
|
}
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
// The processors are views as a heap tree. The root is the processor of
|
|
// id 0.
|
|
//-----------------------------------------------------------------------------
|
|
int vtkCommunicator::GetParentProcessor(int proc)
|
|
{
|
|
int result;
|
|
if(proc%2==1)
|
|
{
|
|
result=proc>>1; // /2
|
|
}
|
|
else
|
|
{
|
|
result=(proc-1)>>1; // /2
|
|
}
|
|
return result;
|
|
}
|
|
|
|
int vtkCommunicator::GetLeftChildProcessor(int proc)
|
|
{
|
|
return (proc<<1)+1; // *2+1
|
|
}
|
|
|
|
int vtkCommunicator::ComputeGlobalBounds(int processNumber, int numProcessors,
|
|
vtkBoundingBox *bounds,
|
|
int *rhb, int *lhb,
|
|
int hasBoundsTag,
|
|
int localBoundsTag,
|
|
int globalBoundsTag)
|
|
{
|
|
int parent = 0;
|
|
int leftHasBounds = 0, rightHasBounds = 0;
|
|
int left = this->GetLeftChildProcessor(processNumber);
|
|
int right=left+1;
|
|
if(processNumber>0) // not root (nothing to do if root)
|
|
{
|
|
parent=this->GetParentProcessor(processNumber);
|
|
}
|
|
|
|
double otherBounds[6];
|
|
if(left<numProcessors)
|
|
{
|
|
this->Receive(&leftHasBounds, 1, left, hasBoundsTag);
|
|
if (lhb)
|
|
{
|
|
*lhb = leftHasBounds;
|
|
}
|
|
|
|
if(leftHasBounds)
|
|
{
|
|
this->Receive(otherBounds, 6, left, localBoundsTag);
|
|
bounds->AddBounds(otherBounds);
|
|
}
|
|
}
|
|
if(right<numProcessors)
|
|
{
|
|
// Grab the bounds from right child
|
|
this->Receive(&rightHasBounds, 1, right, hasBoundsTag);
|
|
|
|
if (rhb)
|
|
{
|
|
*rhb = rightHasBounds;
|
|
}
|
|
|
|
if(rightHasBounds)
|
|
{
|
|
this->Receive(otherBounds, 6, right, localBoundsTag);
|
|
bounds->AddBounds(otherBounds);
|
|
}
|
|
}
|
|
|
|
// If there are bounds to send do so
|
|
int boundsHaveBeenSet = bounds->IsValid();
|
|
double b[6];
|
|
// Send local to parent, Receive global from the parent.
|
|
if(processNumber > 0) // not root (nothing to do if root)
|
|
{
|
|
this->Send(&boundsHaveBeenSet, 1, parent, hasBoundsTag);
|
|
if(boundsHaveBeenSet)
|
|
{
|
|
// Copy the bounds to an array so we can send them
|
|
|
|
bounds->GetBounds(b);
|
|
this->Send(b, 6, parent, localBoundsTag);
|
|
|
|
this->Receive(b, 6, parent, globalBoundsTag);
|
|
bounds->AddBounds(b);
|
|
}
|
|
}
|
|
|
|
if(!boundsHaveBeenSet) // empty, no bounds, nothing to do
|
|
{
|
|
return 1;
|
|
}
|
|
|
|
// Send it to children.
|
|
bounds->GetBounds(b);
|
|
if(left<numProcessors)
|
|
{
|
|
if(leftHasBounds)
|
|
{
|
|
this->Send(b, 6, left, globalBoundsTag);
|
|
}
|
|
if(right<numProcessors)
|
|
{
|
|
if(rightHasBounds)
|
|
{
|
|
this->Send(b, 6, right, globalBoundsTag);
|
|
}
|
|
}
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
//=============================================================================
|
|
// Collective operations.
|
|
//
|
|
// The implementations of these are very simple and probably inefficient.
|
|
// Most of the time we expect to be using an MPI controller, which has its
|
|
// own special implementations in the underlying API, so there is no good
|
|
// reason to work on creating a really good implementation here.
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void vtkCommunicator::Barrier()
|
|
{
|
|
int junk = 0;
|
|
if (this->LocalProcessId == 0)
|
|
{
|
|
for (int i = 1; i < this->NumberOfProcesses; i++)
|
|
{
|
|
this->Receive(&junk, 1, i, BARRIER_TAG);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
this->Send(&junk, 1, 0, BARRIER_TAG);
|
|
}
|
|
this->Broadcast(&junk, 1, 0);
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
int vtkCommunicator::BroadcastVoidArray(void *data, vtkIdType length,
|
|
int type, int srcProcessId)
|
|
{
|
|
if (srcProcessId == this->LocalProcessId)
|
|
{
|
|
int result = 1;
|
|
for (int i = 0; i < this->NumberOfProcesses; i++)
|
|
{
|
|
if (i != this->LocalProcessId)
|
|
{
|
|
result &= this->SendVoidArray(data, length, type, i, BROADCAST_TAG);
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
else
|
|
{
|
|
return this->ReceiveVoidArray(data, length, type,
|
|
srcProcessId, BROADCAST_TAG);
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
int vtkCommunicator::Broadcast(vtkDataObject *data, int srcProcessId)
|
|
{
|
|
VTK_CREATE(vtkCharArray, buffer);
|
|
if (this->LocalProcessId == srcProcessId)
|
|
{
|
|
if (vtkCommunicator::MarshalDataObject(data, buffer))
|
|
{
|
|
return this->Broadcast(buffer, srcProcessId);
|
|
}
|
|
else
|
|
{
|
|
// Could not marshal data.
|
|
return 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (!this->Broadcast(buffer, srcProcessId))
|
|
{
|
|
return 0;
|
|
}
|
|
return vtkCommunicator::UnMarshalDataObject(buffer, data);
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// We are more careful about duplicating all the metadata in the broadcast than
|
|
// the other collective operations, because it is more like a send/recv.
|
|
int vtkCommunicator::Broadcast(vtkDataArray *data, int srcProcessId)
|
|
{
|
|
int type;
|
|
vtkIdType numTuples;
|
|
int numComponents;
|
|
int nameLength = 0;
|
|
char *name = NULL;
|
|
|
|
// On the source process, extract the metadata.
|
|
if (this->LocalProcessId == srcProcessId)
|
|
{
|
|
type = data->GetDataType();
|
|
numTuples = data->GetNumberOfTuples();
|
|
numComponents = data->GetNumberOfComponents();
|
|
nameLength = 0;
|
|
name = data->GetName();
|
|
if (name)
|
|
{
|
|
nameLength = static_cast<int>(strlen(name))+1;
|
|
}
|
|
}
|
|
|
|
// Broadcast the metadata
|
|
if (!this->Broadcast(&type, 1, srcProcessId)) return 0;
|
|
if (!this->Broadcast(&numTuples, 1, srcProcessId)) return 0;
|
|
if (!this->Broadcast(&numComponents, 1, srcProcessId)) return 0;
|
|
if (!this->Broadcast(&nameLength, 1, srcProcessId)) return 0;
|
|
|
|
// On the destinations, allocate buffers.
|
|
if (this->LocalProcessId != srcProcessId)
|
|
{
|
|
if (data->GetDataType() != type)
|
|
{
|
|
vtkErrorMacro("Broadcast data types do not match!");
|
|
return 0;
|
|
}
|
|
name = (nameLength > 0) ? new char[nameLength] : NULL;
|
|
data->SetNumberOfComponents(numComponents);
|
|
data->SetNumberOfTuples(numTuples);
|
|
}
|
|
|
|
// Send the actual data.
|
|
if (nameLength > 0)
|
|
{
|
|
if (!this->Broadcast(name, nameLength, srcProcessId)) return 0;
|
|
}
|
|
if (!this->BroadcastVoidArray(data->GetVoidPointer(0),
|
|
numTuples*numComponents,
|
|
data->GetDataType(), srcProcessId)) return 0;
|
|
|
|
// Cleanup
|
|
if (this->LocalProcessId != srcProcessId)
|
|
{
|
|
if (nameLength > 0)
|
|
{
|
|
data->SetName(name);
|
|
delete[] name;
|
|
}
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
int vtkCommunicator::GatherVoidArray(const void *sendBuffer,
|
|
void *recvBuffer,
|
|
vtkIdType length,
|
|
int type,
|
|
int destProcessId)
|
|
{
|
|
if (this->LocalProcessId == destProcessId)
|
|
{
|
|
int result = 1;
|
|
char *dest = reinterpret_cast<char *>(recvBuffer);
|
|
int typeSize = 1;
|
|
switch (type)
|
|
{
|
|
vtkTemplateMacro(typeSize = sizeof(VTK_TT));
|
|
}
|
|
// Copy local data first in case buffers are the same.
|
|
memmove(dest + this->LocalProcessId*length*typeSize, sendBuffer,
|
|
length*typeSize);
|
|
// Receive everything else.
|
|
for (int i = 0; i < this->NumberOfProcesses; i++)
|
|
{
|
|
if (this->LocalProcessId != i)
|
|
{
|
|
result &= this->ReceiveVoidArray(dest + i*length*typeSize,
|
|
length, type, i,
|
|
GATHER_TAG);
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
else
|
|
{
|
|
return this->SendVoidArray(sendBuffer, length, type,
|
|
destProcessId, GATHER_TAG);
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
int vtkCommunicator::Gather(vtkDataArray *sendBuffer,
|
|
vtkDataArray *recvBuffer,
|
|
int destProcessId)
|
|
{
|
|
int type = sendBuffer->GetDataType();
|
|
const void *sb = sendBuffer->GetVoidPointer(0);
|
|
void *rb = NULL;
|
|
int numComponents = sendBuffer->GetNumberOfComponents();
|
|
vtkIdType numTuples = sendBuffer->GetNumberOfTuples();
|
|
if (this->LocalProcessId == destProcessId)
|
|
{
|
|
if (type != recvBuffer->GetDataType())
|
|
{
|
|
vtkErrorMacro(<< "Data type mismatch.");
|
|
return 0;
|
|
}
|
|
recvBuffer->SetNumberOfComponents(numComponents);
|
|
recvBuffer->SetNumberOfTuples(numTuples*this->NumberOfProcesses);
|
|
rb = recvBuffer->GetVoidPointer(0);
|
|
}
|
|
return this->GatherVoidArray(sb, rb, numComponents*numTuples, type,
|
|
destProcessId);
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
int vtkCommunicator::GatherV(vtkDataArray *sendBuffer,
|
|
vtkDataArray* recvBuffer,
|
|
vtkSmartPointer<vtkDataArray> *recvBuffers,
|
|
int destProcessId)
|
|
{
|
|
vtkNew<vtkIdTypeArray> recvLengths;
|
|
vtkNew<vtkIdTypeArray> offsets;
|
|
int retValue = this->GatherV(
|
|
sendBuffer, recvBuffer,
|
|
recvLengths.GetPointer(), offsets.GetPointer(), destProcessId);
|
|
if (destProcessId == this->LocalProcessId)
|
|
{
|
|
int numComponents = sendBuffer->GetNumberOfComponents();
|
|
for (int i = 0; i < this->NumberOfProcesses; ++i)
|
|
{
|
|
recvBuffers[i]->SetNumberOfComponents(numComponents);
|
|
recvBuffers[i]->SetVoidArray(
|
|
static_cast<unsigned char*>(recvBuffer->GetVoidPointer(0)) +
|
|
offsets->GetValue(i) * recvBuffer->GetElementComponentSize(),
|
|
recvLengths->GetValue(i) * recvBuffer->GetElementComponentSize(), 1);
|
|
}
|
|
}
|
|
return retValue;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
int vtkCommunicator::GatherVElementalDataObject(
|
|
vtkDataObject* sendData, vtkSmartPointer<vtkDataObject>* receiveData,
|
|
int destProcessId)
|
|
{
|
|
vtkNew<vtkCharArray> sendBuffer;
|
|
vtkNew<vtkCharArray> recvBuffer;
|
|
std::vector<vtkSmartPointer<vtkDataArray> > recvBuffers(
|
|
this->NumberOfProcesses);
|
|
|
|
vtkCommunicator::MarshalDataObject(sendData, sendBuffer.GetPointer());
|
|
if (this->LocalProcessId == destProcessId)
|
|
{
|
|
for (int i = 0; i < this->NumberOfProcesses; ++i)
|
|
{
|
|
recvBuffers[i] = vtkSmartPointer<vtkCharArray>::New();
|
|
}
|
|
}
|
|
if (this->GatherV(sendBuffer.GetPointer(), recvBuffer.GetPointer(),
|
|
&recvBuffers[0], destProcessId))
|
|
{
|
|
if (this->LocalProcessId == destProcessId)
|
|
{
|
|
for (int i = 0; i < this->NumberOfProcesses; ++i)
|
|
{
|
|
if (! vtkCommunicator::UnMarshalDataObject(
|
|
vtkCharArray::SafeDownCast(recvBuffers[i].GetPointer()),
|
|
receiveData[i]))
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return 0;
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
int vtkCommunicator::GatherV(vtkDataObject *sendData,
|
|
vtkSmartPointer<vtkDataObject>* receiveData,
|
|
int destProcessId)
|
|
{
|
|
int sendType = sendData? sendData->GetDataObjectType() : -1;
|
|
switch(sendType)
|
|
{
|
|
case -1:
|
|
// NULL data.
|
|
return 1;
|
|
|
|
//error on types we can't send
|
|
case VTK_DATA_OBJECT:
|
|
case VTK_DATA_SET:
|
|
case VTK_PIECEWISE_FUNCTION:
|
|
case VTK_POINT_SET:
|
|
case VTK_UNIFORM_GRID:
|
|
case VTK_GENERIC_DATA_SET:
|
|
case VTK_HYPER_OCTREE:
|
|
case VTK_COMPOSITE_DATA_SET:
|
|
case VTK_HIERARCHICAL_BOX_DATA_SET: // since we cannot send vtkUniformGrid anyways.
|
|
case VTK_MULTIGROUP_DATA_SET: // obsolete
|
|
case VTK_HIERARCHICAL_DATA_SET: //obsolete
|
|
default:
|
|
vtkErrorMacro(<< "Cannot gather " << sendData->GetClassName());
|
|
return 0;
|
|
|
|
//send elemental data objects
|
|
case VTK_DIRECTED_GRAPH:
|
|
case VTK_UNDIRECTED_GRAPH:
|
|
case VTK_IMAGE_DATA:
|
|
case VTK_POLY_DATA:
|
|
case VTK_RECTILINEAR_GRID:
|
|
case VTK_STRUCTURED_GRID:
|
|
case VTK_STRUCTURED_POINTS:
|
|
case VTK_TABLE:
|
|
case VTK_TREE:
|
|
case VTK_UNSTRUCTURED_GRID:
|
|
case VTK_MULTIBLOCK_DATA_SET:
|
|
case VTK_UNIFORM_GRID_AMR:
|
|
return this->GatherVElementalDataObject(
|
|
sendData, receiveData, destProcessId);
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
int vtkCommunicator::GatherVVoidArray(const void *sendBuffer,
|
|
void *recvBuffer,
|
|
vtkIdType sendLength,
|
|
vtkIdType *recvLengths,
|
|
vtkIdType *offsets,
|
|
int type,
|
|
int destProcessId)
|
|
{
|
|
if (this->LocalProcessId == destProcessId)
|
|
{
|
|
int result = 1;
|
|
char *dest = reinterpret_cast<char *>(recvBuffer);
|
|
int typeSize = 1;
|
|
switch (type)
|
|
{
|
|
vtkTemplateMacro(typeSize = sizeof(VTK_TT));
|
|
}
|
|
// Copy local data first in case buffers are the same.
|
|
memmove(dest + offsets[this->LocalProcessId]*typeSize, sendBuffer,
|
|
sendLength*typeSize);
|
|
// Receive everything else.
|
|
for (int i = 0; i < this->NumberOfProcesses; i++)
|
|
{
|
|
if (this->LocalProcessId != i)
|
|
{
|
|
result &= this->ReceiveVoidArray(dest + offsets[i]*typeSize,
|
|
recvLengths[i], type, i,
|
|
GATHERV_TAG);
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
else
|
|
{
|
|
return this->SendVoidArray(sendBuffer, sendLength, type,
|
|
destProcessId, GATHERV_TAG);
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
int vtkCommunicator::GatherV(vtkDataArray *sendBuffer, vtkDataArray *recvBuffer,
|
|
int destProcessId)
|
|
{
|
|
vtkNew<vtkIdTypeArray> recvLengths;
|
|
vtkNew<vtkIdTypeArray> offsets;
|
|
return this->GatherV(sendBuffer, recvBuffer, recvLengths.GetPointer(),
|
|
offsets.GetPointer(), destProcessId);
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
int vtkCommunicator::GatherV(vtkDataArray *sendBuffer, vtkDataArray *recvBuffer,
|
|
vtkIdType *recvLengths, vtkIdType *offsets,
|
|
int destProcessId)
|
|
{
|
|
int type = sendBuffer->GetDataType();
|
|
if (recvBuffer && (type != recvBuffer->GetDataType()))
|
|
{
|
|
vtkErrorMacro("Send/receive buffers do not match!");
|
|
return 0;
|
|
}
|
|
return this->GatherVVoidArray(sendBuffer->GetVoidPointer(0),
|
|
( recvBuffer
|
|
? recvBuffer->GetVoidPointer(0) : NULL ),
|
|
( sendBuffer->GetNumberOfComponents()
|
|
* sendBuffer->GetNumberOfTuples() ),
|
|
recvLengths, offsets, type,
|
|
destProcessId);
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
int vtkCommunicator::GatherV(vtkDataArray *sendBuffer, vtkDataArray *recvBuffer,
|
|
vtkIdTypeArray* recvLengthsArray,
|
|
vtkIdTypeArray* offsetsArray,
|
|
int destProcessId)
|
|
{
|
|
vtkIdType* recvLengths =
|
|
recvLengthsArray->WritePointer(0, this->GetNumberOfProcesses());
|
|
vtkIdType* offsets =
|
|
offsetsArray->WritePointer(0, this->GetNumberOfProcesses() + 1);
|
|
int numComponents = sendBuffer->GetNumberOfComponents();
|
|
vtkIdType numTuples = sendBuffer->GetNumberOfTuples();
|
|
vtkIdType sendLength = numComponents*numTuples;
|
|
if (!this->Gather(&sendLength, recvLengths, 1, destProcessId))
|
|
{
|
|
return 0;
|
|
}
|
|
if (destProcessId == this->LocalProcessId)
|
|
{
|
|
offsets[0] = 0;
|
|
for (int i = 0; i < this->NumberOfProcesses; i++)
|
|
{
|
|
if ((recvLengths[i] % numComponents) != 0)
|
|
{
|
|
vtkWarningMacro(<< "Not all send buffers have same tuple size.");
|
|
}
|
|
offsets[i+1] = offsets[i] + recvLengths[i];
|
|
}
|
|
recvBuffer->SetNumberOfComponents(numComponents);
|
|
recvBuffer->SetNumberOfTuples(
|
|
offsets[this->NumberOfProcesses]/numComponents);
|
|
}
|
|
return this->GatherV(sendBuffer, recvBuffer,
|
|
recvLengths, offsets, destProcessId);
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
int vtkCommunicator::ScatterVoidArray(const void *sendBuffer,
|
|
void *recvBuffer,
|
|
vtkIdType length,
|
|
int type,
|
|
int srcProcessId)
|
|
{
|
|
if (this->LocalProcessId == srcProcessId)
|
|
{
|
|
int result = 1;
|
|
const char *src = reinterpret_cast<const char *>(sendBuffer);
|
|
int typeSize = 1;
|
|
switch (type)
|
|
{
|
|
vtkTemplateMacro(typeSize = sizeof(VTK_TT));
|
|
}
|
|
// Send to everywhere.
|
|
for (int i = 0; i < this->NumberOfProcesses; i++)
|
|
{
|
|
if (this->LocalProcessId == i)
|
|
{
|
|
memmove(recvBuffer, src + this->LocalProcessId*length*typeSize,
|
|
length*typeSize);
|
|
}
|
|
else
|
|
{
|
|
result &= this->SendVoidArray(src + i*length*typeSize,
|
|
length, type, i, SCATTER_TAG);
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
else
|
|
{
|
|
return this->ReceiveVoidArray(recvBuffer, length, type,
|
|
srcProcessId, SCATTER_TAG);
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
int vtkCommunicator::Scatter(vtkDataArray *sendBuffer,
|
|
vtkDataArray *recvBuffer,
|
|
int srcProcessId)
|
|
{
|
|
int type = recvBuffer->GetDataType();
|
|
const void *sb = NULL;
|
|
void *rb = recvBuffer->GetVoidPointer(0);
|
|
int numComponents = recvBuffer->GetNumberOfComponents();
|
|
vtkIdType numTuples = recvBuffer->GetNumberOfTuples();
|
|
if (this->LocalProcessId == srcProcessId)
|
|
{
|
|
if (type != sendBuffer->GetDataType())
|
|
{
|
|
vtkErrorMacro(<< "Data type mismatch.");
|
|
return 0;
|
|
}
|
|
if ( sendBuffer->GetNumberOfComponents()*sendBuffer->GetNumberOfTuples()
|
|
< numComponents*numTuples )
|
|
{
|
|
vtkErrorMacro(<< "Send buffer not large enough for requested data.");
|
|
return 0;
|
|
}
|
|
sb = sendBuffer->GetVoidPointer(0);
|
|
}
|
|
return this->ScatterVoidArray(sb, rb, numComponents*numTuples, type,
|
|
srcProcessId);
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
int vtkCommunicator::ScatterVVoidArray(const void *sendBuffer,
|
|
void *recvBuffer,
|
|
vtkIdType *sendLengths,
|
|
vtkIdType *offsets,
|
|
vtkIdType recvLength, int type,
|
|
int srcProcessId)
|
|
{
|
|
if (this->LocalProcessId == srcProcessId)
|
|
{
|
|
int result = 1;
|
|
const char *src = reinterpret_cast<const char *>(sendBuffer);
|
|
int typeSize = 1;
|
|
switch (type)
|
|
{
|
|
vtkTemplateMacro(typeSize = sizeof(VTK_TT));
|
|
}
|
|
// Send to everywhere except myself.
|
|
for (int i = 0; i < this->NumberOfProcesses; i++)
|
|
{
|
|
if (this->LocalProcessId != i)
|
|
{
|
|
result &= this->SendVoidArray(src + offsets[i]*typeSize,
|
|
sendLengths[i],
|
|
type, i, SCATTERV_TAG);
|
|
}
|
|
}
|
|
// Send to myself last in case send and receive buffers are the same.
|
|
memmove(recvBuffer, src + offsets[this->LocalProcessId]*typeSize,
|
|
recvLength*typeSize);
|
|
return result;
|
|
}
|
|
else
|
|
{
|
|
return this->ReceiveVoidArray(recvBuffer, recvLength, type,
|
|
srcProcessId, SCATTERV_TAG);
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
int vtkCommunicator::AllGatherVoidArray(const void *sendBuffer,
|
|
void *recvBuffer,
|
|
vtkIdType length, int type)
|
|
{
|
|
int result = 1;
|
|
result &= this->GatherVoidArray(sendBuffer, recvBuffer, length, type, 0);
|
|
result &= this->BroadcastVoidArray(recvBuffer, length*this->NumberOfProcesses,
|
|
type, 0);
|
|
return result;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
int vtkCommunicator::AllGather(vtkDataArray *sendBuffer,
|
|
vtkDataArray *recvBuffer)
|
|
{
|
|
int type = sendBuffer->GetDataType();
|
|
if (type != recvBuffer->GetDataType())
|
|
{
|
|
vtkErrorMacro(<< "Send and receive types do not match.");
|
|
return 0;
|
|
}
|
|
int numComponents = sendBuffer->GetNumberOfComponents();
|
|
vtkIdType numTuples = sendBuffer->GetNumberOfTuples();
|
|
recvBuffer->SetNumberOfComponents(numComponents);
|
|
recvBuffer->SetNumberOfTuples(numTuples*this->NumberOfProcesses);
|
|
return this->AllGatherVoidArray(sendBuffer->GetVoidPointer(0),
|
|
recvBuffer->GetVoidPointer(0),
|
|
numComponents*numTuples, type);
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
int vtkCommunicator::AllGatherVVoidArray(const void *sendBuffer,
|
|
void *recvBuffer,
|
|
vtkIdType sendLength,
|
|
vtkIdType *recvLengths,
|
|
vtkIdType *offsets, int type)
|
|
{
|
|
int result = 1;
|
|
result &= this->GatherVVoidArray(sendBuffer, recvBuffer, sendLength,
|
|
recvLengths, offsets, type, 0);
|
|
// Find the maximum place in the array that contains data.
|
|
vtkIdType maxIndex = 0;
|
|
for (int i = 0; i < this->NumberOfProcesses; i++)
|
|
{
|
|
vtkIdType index = recvLengths[i]+offsets[i];
|
|
maxIndex = (maxIndex < index) ? index : maxIndex;
|
|
}
|
|
result &= this->BroadcastVoidArray(recvBuffer, maxIndex, type, 0);
|
|
return result;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
int vtkCommunicator::AllGatherV(vtkDataArray *sendBuffer,
|
|
vtkDataArray *recvBuffer,
|
|
vtkIdType *recvLengths,
|
|
vtkIdType *offsets)
|
|
{
|
|
int type = sendBuffer->GetDataType();
|
|
if (type != recvBuffer->GetDataType())
|
|
{
|
|
vtkErrorMacro("Send/receive buffers do not match!");
|
|
return 0;
|
|
}
|
|
return this->AllGatherVVoidArray(sendBuffer->GetVoidPointer(0),
|
|
recvBuffer->GetVoidPointer(0),
|
|
( sendBuffer->GetNumberOfComponents()
|
|
* sendBuffer->GetNumberOfTuples() ),
|
|
recvLengths, offsets, type);
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
int vtkCommunicator::AllGatherV(vtkDataArray *sendBuffer,
|
|
vtkDataArray *recvBuffer)
|
|
{
|
|
std::vector<vtkIdType> recvLengths(this->NumberOfProcesses);
|
|
std::vector<vtkIdType> offsets(this->NumberOfProcesses + 1);
|
|
int numComponents = sendBuffer->GetNumberOfComponents();
|
|
vtkIdType numTuples = sendBuffer->GetNumberOfTuples();
|
|
vtkIdType sendLength = numComponents*numTuples;
|
|
if (!this->AllGather(&sendLength, &recvLengths.at(0), 1))
|
|
{
|
|
return 0;
|
|
}
|
|
offsets[0] = 0;
|
|
for (int i = 0; i < this->NumberOfProcesses; i++)
|
|
{
|
|
if ((recvLengths[i] % numComponents) != 0)
|
|
{
|
|
vtkWarningMacro(<< "Not all send buffers have same tuple size.");
|
|
}
|
|
offsets[i+1] = offsets[i] + recvLengths[i];
|
|
}
|
|
recvBuffer->SetNumberOfComponents(numComponents);
|
|
recvBuffer->SetNumberOfTuples(offsets[this->NumberOfProcesses]/numComponents);
|
|
return this->AllGatherV(sendBuffer, recvBuffer,
|
|
&recvLengths.at(0), &offsets.at(0));
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
int vtkCommunicator::ReduceVoidArray(const void *sendBuffer,
|
|
void *recvBuffer,
|
|
vtkIdType length, int type,
|
|
int operation, int destProcessId)
|
|
{
|
|
#define OP_CASE(id, opclass) \
|
|
case id: opClass = new vtkCommunicator##opclass##Class; break;
|
|
|
|
vtkCommunicator::Operation *opClass = 0;
|
|
|
|
switch (operation)
|
|
{
|
|
OP_CASE(MAX_OP, Max);
|
|
OP_CASE(MIN_OP, Min);
|
|
OP_CASE(SUM_OP, Sum);
|
|
OP_CASE(PRODUCT_OP, Product);
|
|
OP_CASE(LOGICAL_AND_OP, LogicalAnd);
|
|
OP_CASE(BITWISE_AND_OP, BitwiseAnd);
|
|
OP_CASE(LOGICAL_OR_OP, LogicalOr);
|
|
OP_CASE(BITWISE_OR_OP, BitwiseOr);
|
|
OP_CASE(LOGICAL_XOR_OP, LogicalXor);
|
|
OP_CASE(BITWISE_XOR_OP, BitwiseXor);
|
|
default:
|
|
vtkWarningMacro(<< "Operation number " << operation << " not supported.");
|
|
return 0;
|
|
}
|
|
|
|
int retVal = this->ReduceVoidArray(sendBuffer, recvBuffer, length, type,
|
|
opClass, destProcessId);
|
|
delete opClass;
|
|
|
|
return retVal;
|
|
|
|
#undef OP_CASE
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
int vtkCommunicator::ReduceVoidArray(const void *sendBuffer,
|
|
void *recvBuffer,
|
|
vtkIdType length, int type,
|
|
Operation *operation,
|
|
int destProcessId)
|
|
{
|
|
if (this->LocalProcessId < this->NumberOfProcesses-1)
|
|
{
|
|
this->ReceiveVoidArray(recvBuffer, length, type,
|
|
this->LocalProcessId+1, REDUCE_TAG);
|
|
operation->Function(sendBuffer, recvBuffer, length, type);
|
|
sendBuffer = recvBuffer;
|
|
}
|
|
|
|
if (this->LocalProcessId > 0)
|
|
{
|
|
this->SendVoidArray(sendBuffer, length, type,
|
|
this->LocalProcessId-1, REDUCE_TAG);
|
|
if (this->LocalProcessId == destProcessId)
|
|
{
|
|
this->ReceiveVoidArray(recvBuffer, length, type, 0, REDUCE_TAG);
|
|
}
|
|
}
|
|
else // this->LocalProcessId == 0
|
|
{
|
|
if (destProcessId != 0)
|
|
{
|
|
this->SendVoidArray(sendBuffer, length, type,
|
|
destProcessId, REDUCE_TAG);
|
|
}
|
|
else if (this->NumberOfProcesses == 1)
|
|
{
|
|
// Special case: just one process. Copy src to destination.
|
|
switch (type)
|
|
{
|
|
vtkTemplateMacro
|
|
(std::copy(reinterpret_cast<const VTK_TT*>(sendBuffer),
|
|
reinterpret_cast<const VTK_TT*>(sendBuffer) + length,
|
|
reinterpret_cast<VTK_TT*>(recvBuffer)));
|
|
}
|
|
}
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
int vtkCommunicator::Reduce(vtkDataArray *sendBuffer,
|
|
vtkDataArray *recvBuffer,
|
|
int operation, int destProcessId)
|
|
{
|
|
int type = sendBuffer->GetDataType();
|
|
int components = sendBuffer->GetNumberOfComponents();
|
|
vtkIdType tuples = sendBuffer->GetNumberOfTuples();
|
|
|
|
if (type != recvBuffer->GetDataType())
|
|
{
|
|
vtkErrorMacro(<< "Send and receive types do not match.");
|
|
return 0;
|
|
}
|
|
recvBuffer->SetNumberOfComponents(components);
|
|
recvBuffer->SetNumberOfTuples(tuples);
|
|
|
|
return this->ReduceVoidArray(sendBuffer->GetVoidPointer(0),
|
|
recvBuffer->GetVoidPointer(0),
|
|
components*tuples, type,
|
|
operation, destProcessId);
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
int vtkCommunicator::Reduce(vtkDataArray *sendBuffer,
|
|
vtkDataArray *recvBuffer,
|
|
Operation *operation, int destProcessId)
|
|
{
|
|
int type = sendBuffer->GetDataType();
|
|
int components = sendBuffer->GetNumberOfComponents();
|
|
vtkIdType tuples = sendBuffer->GetNumberOfTuples();
|
|
|
|
if (type != recvBuffer->GetDataType())
|
|
{
|
|
vtkErrorMacro(<< "Send and receive types do not match.");
|
|
return 0;
|
|
}
|
|
recvBuffer->SetNumberOfComponents(components);
|
|
recvBuffer->SetNumberOfTuples(tuples);
|
|
|
|
return this->ReduceVoidArray(sendBuffer->GetVoidPointer(0),
|
|
recvBuffer->GetVoidPointer(0),
|
|
components*tuples, type,
|
|
operation, destProcessId);
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
int vtkCommunicator::AllReduceVoidArray(const void *sendBuffer,
|
|
void *recvBuffer,
|
|
vtkIdType length, int type,
|
|
int operation)
|
|
{
|
|
if (this->ReduceVoidArray(sendBuffer, recvBuffer, length, type, operation, 0))
|
|
{
|
|
return this->BroadcastVoidArray(recvBuffer, length, type, 0);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
int vtkCommunicator::AllReduceVoidArray(const void *sendBuffer,
|
|
void *recvBuffer,
|
|
vtkIdType length, int type,
|
|
Operation *operation)
|
|
{
|
|
if (this->ReduceVoidArray(sendBuffer, recvBuffer, length, type, operation, 0))
|
|
{
|
|
return this->BroadcastVoidArray(recvBuffer, length, type, 0);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
int vtkCommunicator::AllReduce(vtkDataArray *sendBuffer,
|
|
vtkDataArray *recvBuffer,
|
|
int operation)
|
|
{
|
|
int type = sendBuffer->GetDataType();
|
|
int components = sendBuffer->GetNumberOfComponents();
|
|
vtkIdType tuples = sendBuffer->GetNumberOfTuples();
|
|
|
|
if (type != recvBuffer->GetDataType())
|
|
{
|
|
vtkErrorMacro(<< "Send and receive types do not match.");
|
|
return 0;
|
|
}
|
|
recvBuffer->SetNumberOfComponents(components);
|
|
recvBuffer->SetNumberOfTuples(tuples);
|
|
|
|
return this->AllReduceVoidArray(sendBuffer->GetVoidPointer(0),
|
|
recvBuffer->GetVoidPointer(0),
|
|
components*tuples, type, operation);
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
int vtkCommunicator::AllReduce(vtkDataArray *sendBuffer,
|
|
vtkDataArray *recvBuffer,
|
|
Operation *operation)
|
|
{
|
|
int type = sendBuffer->GetDataType();
|
|
int components = sendBuffer->GetNumberOfComponents();
|
|
vtkIdType tuples = sendBuffer->GetNumberOfTuples();
|
|
|
|
if (type != recvBuffer->GetDataType())
|
|
{
|
|
vtkErrorMacro(<< "Send and receive types do not match.");
|
|
return 0;
|
|
}
|
|
recvBuffer->SetNumberOfComponents(components);
|
|
recvBuffer->SetNumberOfTuples(tuples);
|
|
|
|
return this->AllReduceVoidArray(sendBuffer->GetVoidPointer(0),
|
|
recvBuffer->GetVoidPointer(0),
|
|
components*tuples, type, operation);
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
int vtkCommunicator::Broadcast(vtkMultiProcessStream& stream, int srcProcessId)
|
|
{
|
|
if (this->GetLocalProcessId() == srcProcessId)
|
|
{
|
|
std::vector<unsigned char> data;
|
|
stream.GetRawData(data);
|
|
unsigned int length = static_cast<unsigned int>(data.size());
|
|
if (!this->Broadcast(reinterpret_cast<int*>(&length), 1, srcProcessId))
|
|
{
|
|
return 0;
|
|
}
|
|
if (length > 0)
|
|
{
|
|
return this->Broadcast(&data[0], length, srcProcessId);
|
|
}
|
|
return 1;
|
|
}
|
|
else
|
|
{
|
|
stream.Reset();
|
|
unsigned int length = 0;
|
|
if (!this->Broadcast(reinterpret_cast<int*>(&length), 1, srcProcessId))
|
|
{
|
|
return 0;
|
|
}
|
|
if (length > 0)
|
|
{
|
|
std::vector<unsigned char> data;
|
|
data.resize(length);
|
|
if (!this->Broadcast(&data[0], length, srcProcessId))
|
|
{
|
|
return 0;
|
|
}
|
|
stream.SetRawData(data);
|
|
}
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
int vtkCommunicator::Send(const vtkMultiProcessStream& stream, int remoteId, int tag)
|
|
{
|
|
std::vector<unsigned char> data;
|
|
stream.GetRawData(data);
|
|
unsigned int length = static_cast<unsigned int>(data.size());
|
|
if (!this->Send(&length, 1, remoteId, tag))
|
|
{
|
|
return 0;
|
|
}
|
|
if (length > 0)
|
|
{
|
|
return this->Send(&data[0], length, remoteId, tag);
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
int vtkCommunicator::Receive(vtkMultiProcessStream& stream, int remoteId, int tag)
|
|
{
|
|
stream.Reset();
|
|
|
|
unsigned int length;
|
|
if (!this->Receive(&length, 1, remoteId, tag))
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
if (length > 0)
|
|
{
|
|
std::vector<unsigned char> data;
|
|
data.resize(length);
|
|
if (!this->Receive(&data[0], length, remoteId, tag))
|
|
{
|
|
return 0;
|
|
}
|
|
stream.SetRawData(data);
|
|
}
|
|
return 1;
|
|
}
|