]> https://gitweb.dealii.org/ - dealii.git/commitdiff
Introduce a function Utilities::MPI::partial_and_total_sum().
authorWolfgang Bangerth <bangerth@colostate.edu>
Wed, 20 Dec 2023 04:11:22 +0000 (21:11 -0700)
committerWolfgang Bangerth <bangerth@colostate.edu>
Wed, 20 Dec 2023 04:11:22 +0000 (21:11 -0700)
include/deal.II/base/mpi.h

index 491a7a78853225c9338159f688fd17f7373b05af..1bc1efea8a9aae74f648821a8ad87950a1753158 100644 (file)
@@ -1416,6 +1416,23 @@ namespace Utilities
            const std::function<T(const T &, const T &)> &combiner,
            const unsigned int                            root_process = 0);
 
+
+    /**
+     * For each process $p$ on a communicator with $P$ processes, compute both
+     * the (exclusive) partial sum $\sum_{i=0}^{p-1} v_i$ and the total
+     * sum $\sum_{i=0}^{P-1} v_i$, and return these two values as a pair.
+     * The former is computed via the `MPI_Exscan` function where the partial
+     * sum is typically called "(exclusive) scan" of the values $v_p$ provided
+     * by the individual processes. The term "prefix sum" is also used.
+     *
+     * This function is only available if `T` is a type natively supported
+     * by MPI.
+     */
+    template <typename T, typename = std::enable_if_t<is_mpi_type<T> == true>>
+    std::pair<T, T>
+    partial_and_total_sum(const T &value, const MPI_Comm comm);
+
+
     /**
      * A function that combines values @p local_value from all processes
      * via a user-specified binary operation @p combiner and distributes the
@@ -1971,6 +1988,44 @@ namespace Utilities
 
 
 
+    template <typename T, typename>
+    std::pair<T, T>
+    partial_and_total_sum(const T &value, const MPI_Comm comm)
+    {
+#  ifndef DEAL_II_WITH_MPI
+      (void)comm;
+      return {0, value};
+#  else
+      if (Utilities::MPI::n_mpi_processes(comm) == 1)
+        return {0, value};
+      else
+        {
+          T prefix = {};
+
+          // First obtain every process's prefix sum:
+          int ierr =
+            MPI_Exscan(&value,
+                       &prefix,
+                       1,
+                       Utilities::MPI::mpi_type_id_for_type<decltype(value)>,
+                       MPI_SUM,
+                       comm);
+          AssertThrowMPI(ierr);
+
+          // Then we also need the total sum. We could obtain it by
+          // calling Utilities::MPI::sum(), but it is cheaper if we
+          // broadcast it from the last process, which can compute it
+          // from its own prefix sum plus its own value.
+          const T sum = Utilities::MPI::broadcast(
+            comm, prefix + value, Utilities::MPI::n_mpi_processes(comm) - 1);
+
+          return {prefix, sum};
+        }
+#  endif
+    }
+
+
+
     template <typename T>
     std::vector<T>
     all_gather(const MPI_Comm comm, const T &object)

In the beginning the Universe was created. This has made a lot of people very angry and has been widely regarded as a bad move.

Douglas Adams


Typeset in Trocchi and Trocchi Bold Sans Serif.