oomph::LinearAlgebraDistributionHelpers Namespace Reference

Namespace for helper functions for LinearAlgebraDistributions. More...

Functions

void concatenate (const Vector< LinearAlgebraDistribution * > &in_distribution_pt, LinearAlgebraDistribution &out_distribution)
 

Detailed Description

Namespace for helper functions for LinearAlgebraDistributions.

Function Documentation

◆ concatenate()

void oomph::LinearAlgebraDistributionHelpers::concatenate ( const Vector< LinearAlgebraDistribution * > &  in_distribution_pt,
LinearAlgebraDistribution out_distribution 
)

Takes a vector of LinearAlgebraDistribution objects and concatenates them such that the nrow_local of the out_distribution is the sum of the nrow_local of all the in_distributions and the number of global rows of the out_distribution is the sum of the number of global rows of all the in_distributions. This results in a permutation of the rows in the out_distribution. Think of this in terms of DoubleVectors, if we have DoubleVectors with distributions A and B, distributed across two processors (p0 and p1), A: [a0] (on p0) B: [b0] (on p0) [a1] (on p1) [b1] (on P1),

then the out_distribution is [a0 (on p0) b0] (on p0) [a1 (on p1) b1] (on p1),

as opposed to [a0 (on p0) a1] (on p0) [b0 (on p1) b1] (on p1).

Note (1): The out_distribution may not be uniformly distributed even if the in_distributions are uniform distributions. Try this out with two distributions of global rows 3 and 5, uniformly distributed across two processors. Compare this against a distribution of global row 8 distributed across two processors.

Note (2): There is no equivalent function which takes a Vector of LinearAlgebraDistribution objects (as opposed to pointers), there should not be one since we do not want to invoke the assignment operator when creating the Vector of LinearAlgebraDistribution objects.

370  {
371  // How many distributions are in in_distribution?
372  unsigned ndistributions = in_distribution_pt.size();
373 
374 #ifdef PARANOID
375 
376  // Are any of the in_distribution pointers null?
377  // We do not want null pointers.
378  for (unsigned dist_i = 0; dist_i < ndistributions; dist_i++)
379  {
380  if (in_distribution_pt[dist_i] == 0)
381  {
382  std::ostringstream error_message;
383  error_message << "The pointer in_distribution_pt[" << dist_i
384  << "] is null.\n";
385  throw OomphLibError(error_message.str(),
388  }
389  }
390 
392 
393  // Check that all in distributions are built.
394  for (unsigned dist_i = 0; dist_i < ndistributions; dist_i++)
395  {
396  if (!in_distribution_pt[dist_i]->built())
397  {
398  std::ostringstream error_message;
399  error_message << "The in_distribution_pt[" << dist_i
400  << "] is not built.\n";
401  throw OomphLibError(error_message.str(),
404  }
405  }
406 
408 
409  // Check that all communicators to concatenate are the same
410  // by comparing all communicators against the first one.
411  const OomphCommunicator first_comm =
412  *(in_distribution_pt[0]->communicator_pt());
413 
414  for (unsigned dist_i = 0; dist_i < ndistributions; dist_i++)
415  {
416  // Get the Communicator for the current vector.
417  const OomphCommunicator another_comm =
418  *(in_distribution_pt[dist_i]->communicator_pt());
419 
420  if (!(first_comm == another_comm))
421  {
422  std::ostringstream error_message;
423  error_message << "The communicator in position " << dist_i << " is \n"
424  << "not the same as the first one.\n";
425  throw OomphLibError(error_message.str(),
428  }
429  }
430 
432 
433  // Ensure that all distributions are either distributed or not.
434  // This is because we use the distributed() function from the first
435  // distribution to indicate if the result distribution should be
436  // distributed or not.
437  bool first_distributed = in_distribution_pt[0]->distributed();
438  for (unsigned dist_i = 0; dist_i < ndistributions; dist_i++)
439  {
440  // Is the current distribution distributed?
441  bool another_distributed = in_distribution_pt[dist_i]->distributed();
442  if (first_distributed != another_distributed)
443  {
444  std::ostringstream error_message;
445  error_message
446  << "The distribution in position " << dist_i << " has a different\n"
447  << "different distributed boolean than the distribution.\n";
448  throw OomphLibError(error_message.str(),
451  }
452  }
453 
455 
456  // Check that the out distribution is not built.
457  if (out_distribution.built())
458  {
459  std::ostringstream error_message;
460  error_message << "The out distribution is built.\n"
461  << "Please clear it.\n";
462  throw OomphLibError(error_message.str(),
465  }
466 
467 #endif
468 
469  // Get the communicator pointer
470  const OomphCommunicator* const comm_pt =
471  in_distribution_pt[0]->communicator_pt();
472 
473  // Number of processors
474  unsigned nproc = comm_pt->nproc();
475 
476  // First determine the out_nrow_local and the out_nrow (the global nrow)
477  unsigned out_nrow_local = 0;
478  unsigned out_nrow = 0;
479  for (unsigned in_dist_i = 0; in_dist_i < ndistributions; in_dist_i++)
480  {
481  out_nrow_local += in_distribution_pt[in_dist_i]->nrow_local();
482  out_nrow += in_distribution_pt[in_dist_i]->nrow();
483  }
484 
485  // Now calculate the first row for this processor. We need to know the
486  // out_nrow_local for all the other processors, MPI_Allgather must be
487  // used.
488  unsigned out_first_row = 0;
489 
490  // Distributed case: We need to gather all the out_nrow_local from all
491  // processors, the out_first_row for this processors is the partial sum up
492  // of the out_nrow_local to my_rank.
493  bool distributed = in_distribution_pt[0]->distributed();
494  if (distributed)
495  {
496 #ifdef OOMPH_HAS_MPI
497  // My rank
498  unsigned my_rank = comm_pt->my_rank();
499 
500  unsigned* out_nrow_local_all = new unsigned[nproc];
501  MPI_Allgather(&out_nrow_local,
502  1,
503  MPI_UNSIGNED,
504  out_nrow_local_all,
505  1,
506  MPI_UNSIGNED,
507  comm_pt->mpi_comm());
508  for (unsigned proc_i = 0; proc_i < my_rank; proc_i++)
509  {
510  out_first_row += out_nrow_local_all[proc_i];
511  }
512  delete[] out_nrow_local_all;
513 #endif
514  }
515  // Non-distributed case
516  else
517  {
518  out_first_row = 0;
519  }
520 
521  // Build the distribution.
522  if (nproc == 1 || !distributed)
523  {
524  // Some ambiguity here -- on a single processor it doesn't really
525  // matter if we think of ourselves as distributed or not but this
526  // follows the pattern used elsewhere.
527  out_distribution.build(comm_pt, out_nrow, false);
528  }
529  else
530  {
531  out_distribution.build(
532  comm_pt, out_first_row, out_nrow_local, out_nrow);
533  }
534  } // function concatenate
#define OOMPH_EXCEPTION_LOCATION
Definition: oomph_definitions.h:61
#define OOMPH_CURRENT_FUNCTION
Definition: oomph_definitions.h:86

References oomph::LinearAlgebraDistribution::build(), oomph::LinearAlgebraDistribution::built(), oomph::OomphCommunicator::my_rank(), oomph::OomphCommunicator::nproc(), OOMPH_CURRENT_FUNCTION, and OOMPH_EXCEPTION_LOCATION.

Referenced by oomph::DoubleVectorHelpers::concatenate_without_communication(), oomph::CRDoubleMatrixHelpers::concatenate_without_communication(), oomph::BlockPreconditioner< MATRIX >::get_concatenated_block(), main(), oomph::BlockPreconditioner< MATRIX >::setup_matrix_vector_product(), and oomph::DoubleVectorHelpers::split_without_communication().