/// <summary>
        ///   Accumulates the catchment results from all processes involved in calculating that catchment.
        ///   The root process in each catchment communicator will contain the accumulated result for that catchment.
        /// </summary>
        /// <param name="partialCatchmentResults"> The partial catchment results from the current process. </param>
        /// <param name="sysConfig"> The sys config. </param>
        /// <returns> The array of final catchment results for the current process. There will be one element for each catchment
        ///  for which the current process is the catchment coordinator.
        /// </returns>
        private MpiObjectiveScores[] AccumulateCatchmentResultsInCatchmentCoordinator(
            Dictionary <string, List <SerializableDictionary <string, MpiTimeSeries> > > partialCatchmentResults, MpiSysConfig sysConfig)
        {
            MpiObjectiveScores[] finalCatchmentResults = new MpiObjectiveScores[CatchmentCoordinatorCount];
            int finalResultIndex = 0;

            foreach (CatchmentDefinition catchment in MyWork.Catchments)
            {
                // Note that Gather is blocking but not synchronous. This means that I can't cause deadlock by having processes
                // call Gather on the communicators in different sequences. My local call to gather will return even if the other
                // participants in the gather have not joined in yet.
                Intracommunicator catchmentComm = communicatorsByCatchmentId[catchment.Id];
                Log.DebugFormat("Rank {0}: Catchment '{1}' rank {2}: Sending {3} cell results", WorldRank, catchment.Id, catchmentComm.Rank, partialCatchmentResults[catchment.Id].Count);

                if (catchmentComm.Rank == 0)
                {
                    SerializableDictionary <string, MpiTimeSeries>[] completeCatchmentResults = catchmentComm.GatherFlattened(
                        partialCatchmentResults[catchment.Id].ToArray(),
                        CatchmentResultCountPerCatchmentCommunicator[catchment.Id],
                        0);

                    // catchmentResults contains all the gridded results for the current catchment
                    Log.DebugFormat("Rank {0}: Catchment '{1}': Accumulating {2} results from {3} cells", WorldRank, catchment.Id, completeCatchmentResults.Length, catchment.Cells.Count);
                    Debug.Assert(catchment.Cells.Count == completeCatchmentResults.Length);
                    MpiObjectiveScores finalCatchmentResult = CalculateCatchmentScores(catchment, completeCatchmentResults, sysConfig, catchment.Cells.Count);
                    finalCatchmentResults[finalResultIndex] = finalCatchmentResult;
                    finalResultIndex++;
                }
                else
                {
                    catchmentComm.GatherFlattened(partialCatchmentResults[catchment.Id].ToArray(), 0);
                }
            }

            return(finalCatchmentResults);
        }