vtkCommunicator.cxx 53.6 KB
Newer Older
Ken Martin's avatar
Ken Martin committed
1
/*=========================================================================
2

Ken Martin's avatar
Ken Martin committed
3 4 5
  Program:   Visualization Toolkit
  Module:    vtkCommunicator.cxx

6
  Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
7 8
  All rights reserved.
  See Copyright.txt or http://www.kitware.com/Copyright.htm for details.
Ken Martin's avatar
Ken Martin committed
9

10 11
     This software is distributed WITHOUT ANY WARRANTY; without even
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
12
     PURPOSE.  See the above copyright notice for more information.
Ken Martin's avatar
Ken Martin committed
13 14 15

=========================================================================*/
#include "vtkCommunicator.h"
16

17
#include "vtkBoundingBox.h"
18
#include "vtkCharArray.h"
19 20
#include "vtkCompositeDataSet.h"
#include "vtkDataObjectTypes.h"
21
#include "vtkDataSetAttributes.h"
22 23
#include "vtkDataSetReader.h"
#include "vtkDataSetWriter.h"
24 25
#include "vtkDoubleArray.h"
#include "vtkFloatArray.h"
26 27
#include "vtkGenericDataObjectReader.h"
#include "vtkGenericDataObjectWriter.h"
28
#include "vtkIdTypeArray.h"
29
#include "vtkImageData.h"
30
#include "vtkIntArray.h"
31
#include "vtkMultiProcessController.h"
32
#include "vtkMultiProcessStream.h"
33
#include "vtkNew.h"
34
#include "vtkRectilinearGrid.h"
35
#include "vtkSmartPointer.h"
36
#include "vtkStructuredGrid.h"
37
#include "vtkStructuredPoints.h"
38
#include "vtkTypeTraits.h"
39
#include "vtkTable.h"
40 41 42
#include "vtkUnsignedCharArray.h"
#include "vtkUnsignedLongArray.h"

43 44
#define VTK_CREATE(type, name) \
  vtkSmartPointer<type> name = vtkSmartPointer<type>::New()
Brad King's avatar
Brad King committed
45

46 47
#include <algorithm>
#include <vector>
48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63


#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: \
64
  void Function(const void *A, void *B, vtkIdType length, int datatype) override { \
65
    switch (datatype) \
66
    { \
67 68 69 70
      vtkTemplateMacro(vtkCommunicator##name##Func \
                                         (reinterpret_cast<const VTK_TT *>(A), \
                                          reinterpret_cast<VTK_TT *>(B), \
                                          length)); \
71
    } \
72
  } \
73
  int Commutative() override { return 1; } \
74 75 76
};

#define STANDARD_OPERATION_FLOAT_OVERRIDE(name) \
77
static void vtkCommunicator##name##Func(const double *, double *, vtkIdType)\
78 79 80 81
{ \
  vtkGenericWarningMacro(<< #name \
                         << " not supported for floating point numbers"); \
} \
82
static void vtkCommunicator##name##Func(const float *, float *, vtkIdType) \
83 84 85 86
{ \
  vtkGenericWarningMacro(<< #name \
                         << " not supported for floating point numbers"); \
}
Ken Martin's avatar
Ken Martin committed
87

88 89
STANDARD_OPERATION_DEFINITION(Max, (A[i] < B[i] ? B[i] : A[i]));
STANDARD_OPERATION_DEFINITION(Min, (A[i] < B[i] ? A[i] : B[i]));
90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105
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]);

//=============================================================================
Ken Martin's avatar
Ken Martin committed
106 107
vtkCommunicator::vtkCommunicator()
{
108 109
  this->LocalProcessId = 0;
  this->NumberOfProcesses = 1;
110
  this->MaximumNumberOfProcesses = vtkTypeTraits<int>::Max();
111
  this->Count = 0;
Ken Martin's avatar
Ken Martin committed
112 113
}

114
//----------------------------------------------------------------------------
115
vtkCommunicator::~vtkCommunicator() = default;
Ken Martin's avatar
Ken Martin committed
116

117
//----------------------------------------------------------------------------
118 119 120 121 122 123
int vtkCommunicator::UseCopy = 0;
void vtkCommunicator::SetUseCopy(int useCopy)
{
  vtkCommunicator::UseCopy = useCopy;
}

124
//----------------------------------------------------------------------------
Ken Martin's avatar
Ken Martin committed
125 126
void vtkCommunicator::PrintSelf(ostream& os, vtkIndent indent)
{
127
  this->Superclass::PrintSelf(os, indent);
128

129
  os << indent << "MaximumNumberOfProcesses: "
130 131 132
     << this->MaximumNumberOfProcesses << endl;
  os << indent << "NumberOfProcesses: " << this->NumberOfProcesses << endl;
  os << indent << "LocalProcessId: " << this->LocalProcessId << endl;
133
  os << indent << "Count: " << this->Count << endl;
134 135 136 137 138 139
}

//----------------------------------------------------------------------------
void vtkCommunicator::SetNumberOfProcesses(int num)
{
  if (num == this->NumberOfProcesses)
140
  {
141
    return;
142
  }
143

144
  if (num < 1 || num > this->MaximumNumberOfProcesses)
145
  {
146 147
    vtkErrorMacro( << num
          << " is an invalid number of processes try a number from 1 to "
148 149
          << this->NumberOfProcesses );
    return;
150
  }
151

152 153
  this->NumberOfProcesses = num;
  this->Modified();
Ken Martin's avatar
Ken Martin committed
154 155 156 157
}

//----------------------------------------------------------------------------
// Need to add better error checking
158
int vtkCommunicator::Send(vtkDataObject* data, int remoteHandle,
159
                          int tag)
160
{
161 162 163 164 165 166 167 168 169 170 171 172 173
  // 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;

174
  int data_type = data? data->GetDataObjectType() : -1;
175
  this->Send(&data_type, 1, remoteHandle, tag);
176

177
  switch(data_type)
178
  {
179
  case -1:
180
    // nullptr data.
181 182
    return 1;

183 184 185 186 187 188 189 190 191
    //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:
192 193 194
    case VTK_HIERARCHICAL_BOX_DATA_SET: // since we cannot send vtkUniformGrid anyways.
    case VTK_MULTIGROUP_DATA_SET: // obsolete
    case VTK_HIERARCHICAL_DATA_SET: //obsolete
195 196 197
    default:
      vtkWarningMacro(<< "Cannot send " << data->GetClassName());
      return 0;
198

199
    //send elemental data objects
200 201
    case VTK_DIRECTED_GRAPH:
    case VTK_UNDIRECTED_GRAPH:
202
    case VTK_IMAGE_DATA:
203 204 205 206 207 208 209 210
    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:
211
    case VTK_UNIFORM_GRID_AMR:
212
    case VTK_OVERLAPPING_AMR:
213
      return this->SendElementalDataObject(data, remoteHandle, tag);
214
  }
215 216
}

217 218
//----------------------------------------------------------------------------
int vtkCommunicator::SendElementalDataObject(
219
  vtkDataObject* data, int remoteHandle,
220
  int tag)
Ken Martin's avatar
Ken Martin committed
221
{
222 223
  VTK_CREATE(vtkCharArray, buffer);
  if (vtkCommunicator::MarshalDataObject(data, buffer))
224
  {
225
    return this->Send(buffer, remoteHandle, tag);
226
  }
227

Ken Martin's avatar
Ken Martin committed
228 229 230
  // could not marshal data
  return 0;
}
231 232

//----------------------------------------------------------------------------
233 234
int vtkCommunicator::Send(vtkDataArray* data, int remoteHandle, int tag)
{
235 236 237 238 239 240
  // 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.
Burlen Loring's avatar
 
Burlen Loring committed
241 242
  static int tagMangler = 1000;
  int mangledTag = tag + tagMangler++;
243 244 245 246
  int header[2];
  header[0] = this->LocalProcessId;  header[1] = mangledTag;
  this->Send(header, 2, remoteHandle, tag);
  tag = mangledTag;
247

248
  int type = -1;
249
  if (data == nullptr)
250
  {
251 252
      this->Send( &type, 1, remoteHandle, tag);
      return 1;
253
  }
254

255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271
  // 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)
272
  {
273
    len = static_cast<int>(strlen(name)) + 1;
274
  }
275

276 277 278 279
  // send length of name
  this->Send( &len, 1, remoteHandle, tag);

  if (len > 0)
280
  {
281 282
    // send name
    this->Send( const_cast<char*>(name), len, remoteHandle, tag);
283
  }
284

285 286
  // do nothing if size is zero.
  if (size == 0)
287
  {
288
    return 1;
289
  }
290

291 292
  // now send the raw array
  this->SendVoidArray(data->GetVoidPointer(0), size, type, remoteHandle, tag);
293
  return 1;
294 295
}

296
//----------------------------------------------------------------------------
297
int vtkCommunicator::Receive(vtkDataObject* data, int remoteHandle,
298
                             int tag)
299 300 301 302 303 304 305 306
{
   //fill in the data object we are given
   return this->ReceiveDataObject(data, remoteHandle, tag, -1);
}

//----------------------------------------------------------------------------
vtkDataObject *vtkCommunicator::ReceiveDataObject(int remoteHandle, int tag)
{
307 308 309 310 311 312 313 314 315 316
  // 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)
317
  {
318
    remoteHandle = header[0];
319
  }
320 321
  tag = header[1];

322
  int data_type = 0;
323
  this->Receive(&data_type, 1, remoteHandle, tag);
324
  if (data_type < 0)
325
  {
326
    // nullptr data object.
327
    return nullptr;
328
  }
329 330
  //manufacture a data object of the proper type to fill
  vtkDataObject * dObj = vtkDataObjectTypes::NewDataObject(data_type);
331
  if (dObj != nullptr)
332
  {
333
    if (this->ReceiveDataObject(dObj, remoteHandle, tag, data_type) == 1)
334
    {
335 336
      return dObj;
    }
337
  }
338
  if (dObj)
339
  {
340
    dObj->Delete();
341
  }
342
  return nullptr;
343 344 345
}

//----------------------------------------------------------------------------
346
int vtkCommunicator::ReceiveDataObject(vtkDataObject* data, int remoteHandle,
347 348
                                       int tag, int dataType)
{
349
  // If we have not yet received the data type, get the header and data type.
350 351
  int data_type = dataType;
  if (data_type == -1)
352
  {
353 354 355 356 357 358 359 360 361 362
    // 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)
363
    {
364
      remoteHandle = header[0];
365
    }
366 367
    tag = header[1];

368
    this->Receive(&data_type, 1, remoteHandle, tag);
369
    if (data->GetDataObjectType() != data_type)
370
    {
371 372 373
      vtkErrorMacro("Cannot receive object, type sent is different from destination.");
      return 0;
    }
374
  }
375

376
  switch(data_type)
377
  {
378 379 380 381 382 383 384 385 386
    //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:
387 388 389
    case VTK_HIERARCHICAL_BOX_DATA_SET: // since we cannot send vtkUniformGrid anyways.
    case VTK_MULTIGROUP_DATA_SET: //obsolete.
    case VTK_HIERARCHICAL_DATA_SET: // obsolete.
390
    default:
391
      vtkWarningMacro(
392
        << "Cannot receive "
393 394 395 396
        << vtkDataObjectTypes::GetClassNameFromTypeId(data_type));
      return 0;

    //receive elemental data objects
397 398
    case VTK_DIRECTED_GRAPH:
    case VTK_UNDIRECTED_GRAPH:
399
    case VTK_IMAGE_DATA:
400 401 402 403 404 405 406 407
    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:
408
    case VTK_UNIFORM_GRID_AMR:
409
    case VTK_OVERLAPPING_AMR:
410
      return this->ReceiveElementalDataObject(data, remoteHandle, tag);
411
  }
412 413 414
}

//----------------------------------------------------------------------------
415
int vtkCommunicator::ReceiveElementalDataObject(
416
  vtkDataObject* data, int remoteHandle,
417
  int tag)
Ken Martin's avatar
Ken Martin committed
418
{
419 420
  VTK_CREATE(vtkCharArray, buffer);
  if (!this->Receive(buffer, remoteHandle, tag))
421
  {
422
    return 0;
423
  }
424

425
  return vtkCommunicator::UnMarshalDataObject(buffer, data);
Ken Martin's avatar
Ken Martin committed
426 427
}

428
int vtkCommunicator::Receive(vtkDataArray* data, int remoteHandle, int tag)
429
{
430 431 432 433 434 435
  // 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.
436 437 438 439
  int header[2];
  this->Receive(header, 2, remoteHandle, tag);
  // Use the specific source and tag.
  if (remoteHandle == vtkMultiProcessController::ANY_SOURCE)
440
  {
441
    remoteHandle = header[0];
442
  }
443
  tag = header[1];
444

445 446 447
  // First receive the data type.
  int type;
  if (!this->Receive( &type, 1, remoteHandle, tag))
448
  {
449
    vtkErrorMacro("Could not receive data!");
450
    return 0;
451
  }
452

453
  if (type == -1)
454
  { // This indicates a nullptr object was sent. Do nothing.
455
    return 1;
456
  }
457

458
  if (type != data->GetDataType())
459
  {
460 461
    vtkErrorMacro("Send/receive data types do not match!");
    return 0;
462
  }
463

464 465 466
  // Next receive the number of tuples.
  vtkIdType numTuples;
  if (!this->Receive( &numTuples, 1, remoteHandle, tag))
467
  {
468 469
    vtkErrorMacro("Could not receive data!");
    return 0;
470
  }
471

472 473 474
  // Next receive the number of components.
  int numComponents;
  this->Receive( &numComponents, 1, remoteHandle, tag);
475

476 477 478 479 480 481 482 483 484
  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 )
485
  {
486 487
    char *str = new char[nameLength];

488 489 490
    // Receive the name
    this->Receive(str, nameLength, remoteHandle, tag);
    data->SetName(str);
491
  }
492
  else
493
  {
494
    data->SetName(nullptr);
495
  }
496

497
  if (size < 0)
498
  {
499 500
    vtkErrorMacro("Bad data length");
    return 0;
501
  }
502

503 504
  // Do nothing if size is zero.
  if (size == 0)
505
  {
506
    return 1;
507
  }
508

509 510 511
  // now receive the raw array.
  this->ReceiveVoidArray(data->GetVoidPointer(0), size, type, remoteHandle,tag);

512 513
  return 1;
}
514

515 516 517
//-----------------------------------------------------------------------------
int vtkCommunicator::MarshalDataObject(vtkDataObject *object,
                                       vtkCharArray *buffer)
Ken Martin's avatar
Ken Martin committed
518
{
519
  buffer->Initialize();
520 521
  buffer->SetNumberOfComponents(1);

522
  if (object == nullptr)
523
  {
524 525
    buffer->SetNumberOfTuples(0);
    return 1;
526
  }
Ken Martin's avatar
Ken Martin committed
527

528 529 530 531
  VTK_CREATE(vtkGenericDataObjectWriter, writer);

  vtkSmartPointer<vtkDataObject> copy;
  copy.TakeReference(object->NewInstance());
532
  copy->ShallowCopy(object);
533 534 535

  writer->SetFileTypeToBinary();
  // There is a problem with binary files with no data.
536
  if (vtkDataSet::SafeDownCast(copy) != nullptr)
537
  {
538
    vtkDataSet *ds = vtkDataSet::SafeDownCast(copy);
539
    if (ds->GetNumberOfCells() + ds->GetNumberOfPoints() == 0)
540
    {
541
      writer->SetFileTypeToASCII();
Ken Martin's avatar
Ken Martin committed
542
    }
543
  }
544
  writer->WriteToOutputStringOn();
545
  writer->SetInputData(copy);
546

547
  if (!writer->Write())
548
  {
549 550
    vtkGenericWarningMacro("Error detected while marshaling data object.");
    return 0;
551
  }
552
  const vtkIdType size = writer->GetOutputStringLength();
553
  if (object->GetExtentType() == VTK_3D_EXTENT)
554
  {
555 556 557 558 559 560 561
    // 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)
562
    {
563
      rg->GetExtent(extent);
564
    }
565
    else if (sg)
566
    {
567
      sg->GetExtent(extent);
568
    }
569
    else if (id)
570
    {
571
      id->GetExtent(extent);
572
    }
573
    char extentHeader[EXTENT_HEADER_SIZE];
574
    snprintf(extentHeader, sizeof(extentHeader), "EXTENT %d %d %d %d %d %d",
575 576 577 578 579 580
            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);
581
  }
582
  else
583
  {
584 585
    buffer->SetArray(writer->RegisterAndGetOutputString(),
                     size,
586
                     0,
Berk Geveci's avatar
Berk Geveci committed
587
                     vtkCharArray::VTK_DATA_ARRAY_DELETE);
588
    buffer->SetNumberOfTuples(size);
589
  }
590 591 592
  return 1;
}

593
//-----------------------------------------------------------------------------
594
int vtkCommunicator::UnMarshalDataObject(vtkCharArray *buffer, vtkDataObject *object)
595
{
596
  if (!object)
597
  {
598 599
    vtkGenericWarningMacro("Invalid 'object'!");
    return 0;
600
  }
601 602
  vtkSmartPointer<vtkDataObject> dobj = vtkCommunicator::UnMarshalDataObject(buffer);
  if (dobj)
603
  {
604
    if (!dobj->IsA(object->GetClassName()))
605
    {
606 607
      vtkGenericWarningMacro("Type mismatch while unmarshalling data.");
    }
608 609
    object->ShallowCopy(dobj);
  }
610
  else
611
  {
612
    object->Initialize();
613
  }
614 615 616 617 618 619 620
  return 1;
}

//-----------------------------------------------------------------------------
vtkSmartPointer<vtkDataObject> vtkCommunicator::UnMarshalDataObject(vtkCharArray* buffer)
{
  vtkIdType bufferSize = buffer ? buffer->GetNumberOfTuples() : 0;
621
  if (bufferSize <= 0)
622
  {
623
    return nullptr;
624
  }
625

626 627 628 629 630
  // 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)
631
  {
632 633 634 635
    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;
636
  }
637 638 639

  // Make a temporary array object holding the part of the buffer that can be
  // parsed by the reader.
640
  vtkNew<vtkCharArray> objectBuffer;
641 642 643
  objectBuffer->SetNumberOfComponents(1);
  objectBuffer->SetArray(bufferArray, bufferSize, 1);

644
  vtkNew<vtkGenericDataObjectReader> reader;
645
  reader->ReadFromInputStringOn();
646
  reader->SetInputArray(objectBuffer);
647
  reader->Update();
648

649 650
  vtkSmartPointer<vtkDataObject> dobj = reader->GetOutputDataObject(0);
  if (dobj->GetExtentType() == VTK_3D_EXTENT)
651
  {
652
    if (vtkRectilinearGrid* rg = vtkRectilinearGrid::SafeDownCast(dobj))
653
    {
654
      rg->SetExtent(extent);
655
    }
656
    else if (vtkStructuredGrid* sg = vtkStructuredGrid::SafeDownCast(dobj))
657
    {
658
      sg->SetExtent(extent);
659
    }
660
    else if (vtkImageData* id = vtkImageData::SafeDownCast(dobj))
661
    {
662 663 664 665 666
      // If we fix the extent, we need to fix the origin too.
      double origin[3];
      id->GetOrigin(origin);
      double spacing[3];
      id->GetSpacing(spacing);
667
      int readerExt[6];
668 669
      id->GetExtent(readerExt);
      for (int i=0; i<3; i++)
670
      {
671
        if (readerExt[2*i] != extent[2*i])
672
        {
673 674
          origin[i] = origin[i] - (extent[2*i] - readerExt[2*i])*spacing[i];
        }
675
      }
676
      id->SetExtent(extent);
677
      id->SetOrigin(origin);
678
    }
679
  }
680
  return dobj;
Ken Martin's avatar
Ken Martin committed
681
}
682 683 684 685 686 687 688 689

// 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)
690
  {
691
    result=proc>>1; // /2
692
  }
693
  else
694
  {
695
    result=(proc-1)>>1; // /2
696
  }
697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712
  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;
713
  int leftHasBounds = 0, rightHasBounds = 0;
714 715 716
  int left = this->GetLeftChildProcessor(processNumber);
  int right=left+1;
  if(processNumber>0) // not root (nothing to do if root)
717
  {
718
    parent=this->GetParentProcessor(processNumber);
719
  }
720

721 722
  double otherBounds[6];
  if(left<numProcessors)
723
  {
724 725
    this->Receive(&leftHasBounds, 1, left, hasBoundsTag);
    if (lhb)
726
    {
727
      *lhb = leftHasBounds;
728
    }
729 730

    if(leftHasBounds)
731
    {
732 733 734
      this->Receive(otherBounds, 6, left, localBoundsTag);
      bounds->AddBounds(otherBounds);
    }
735
  }
736
  if(right<numProcessors)
737
  {
738 739
    // Grab the bounds from right child
    this->Receive(&rightHasBounds, 1, right, hasBoundsTag);
740

741
    if (rhb)
742
    {
743
      *rhb = rightHasBounds;
744
    }
745 746

    if(rightHasBounds)
747
    {
748 749 750
      this->Receive(otherBounds, 6, right, localBoundsTag);
      bounds->AddBounds(otherBounds);
    }
751
  }
752

753 754 755 756 757
  // 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)
758
  {
759 760
    this->Send(&boundsHaveBeenSet, 1, parent, hasBoundsTag);
    if(boundsHaveBeenSet)
761
    {
762
      // Copy the bounds to an array so we can send them
763

764 765
      bounds->GetBounds(b);
      this->Send(b, 6, parent, localBoundsTag);
766

767 768 769
      this->Receive(b, 6, parent, globalBoundsTag);
      bounds->AddBounds(b);
    }
770
  }
771

772
  if(!boundsHaveBeenSet) // empty, no bounds, nothing to do
773
  {
774
    return 1;
775
  }
776

777 778 779
  // Send it to children.
  bounds->GetBounds(b);
  if(left<numProcessors)
780
  {
781
    if(leftHasBounds)
782
    {
783
      this->Send(b, 6, left, globalBoundsTag);
784
    }
785
    if(right<numProcessors)
786
    {
787
      if(rightHasBounds)
788
      {
789 790 791
        this->Send(b, 6, right, globalBoundsTag);
      }
    }
792
  }
793 794
  return 1;
}
795 796 797 798 799 800 801 802 803

//=============================================================================
// 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.

804 805 806 807 808
//-----------------------------------------------------------------------------
void vtkCommunicator::Barrier()
{
  int junk = 0;
  if (this->LocalProcessId == 0)
809
  {
810
    for (int i = 1; i < this->NumberOfProcesses; i++)
811
    {
812 813
      this->Receive(&junk, 1, i, BARRIER_TAG);
    }
814
  }
815
  else
816
  {
817
    this->Send(&junk, 1, 0, BARRIER_TAG);
818
  }
819 820 821
  this->Broadcast(&junk, 1, 0);
}

822 823 824 825 826
//-----------------------------------------------------------------------------
int vtkCommunicator::BroadcastVoidArray(void *data, vtkIdType length,
                                                  int type, int srcProcessId)
{
  if (srcProcessId == this->LocalProcessId)
827
  {
828 829
    int result = 1;
    for (int i = 0; i < this->NumberOfProcesses; i++)
830
    {
831
      if (i != this->LocalProcessId)
832
      {
833 834 835
        result &= this->SendVoidArray(data, length, type, i, BROADCAST_TAG);
      }
    }
836 837
    return result;
  }
838
  else
839
  {
840 841
    return this->ReceiveVoidArray(data, length, type,
                                  srcProcessId, BROADCAST_TAG);
842
  }
843 844 845 846 847 848 849
}

//-----------------------------------------------------------------------------
int vtkCommunicator::Broadcast(vtkDataObject *data, int srcProcessId)
{
  VTK_CREATE(vtkCharArray, buffer);
  if (this->LocalProcessId == srcProcessId)
850
  {
851
    if (vtkCommunicator::MarshalDataObject(data, buffer))
852
    {
853
      return this->Broadcast(buffer, srcProcessId);
854
    }
855
    else
856
    {
857 858 859
      // Could not marshal data.
      return 0;
    }
860
  }
861
  else
862
  {
863
    if (!this->Broadcast(buffer, srcProcessId))
864
    {
865 866
      return 0;
    }
867 868
    return vtkCommunicator::UnMarshalDataObject(buffer, data);
  }
869 870 871 872 873 874 875 876 877 878 879
}

//-----------------------------------------------------------------------------
// 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;
880
  char *name = nullptr;
881 882 883

  // On the source process, extract the metadata.
  if (this->LocalProcessId == srcProcessId)
884
  {
885 886 887 888 889 890
    type = data->GetDataType();
    numTuples = data->GetNumberOfTuples();
    numComponents = data->GetNumberOfComponents();
    nameLength = 0;
    name = data->GetName();
    if (name)
891
    {
892
      nameLength = static_cast<int>(strlen(name))+1;
893
    }