/// <summary> /// Creates the catchment communicators. /// </summary> /// <param name="workAllocator">The work allocator.</param> private void CreateCommunicators(IWorkAllocator workAllocator) { // create the communicators (creating communicators is a collective operation, all processes that belong to the new communicator // must participate in the call). // It is also important that all processes create the communicators in the same order to avoid deadlock // There is one communicator per catchment Log.DebugFormat("Rank {0}: Creating communicators", WorldRank); // we need to sort the list of catchments by catchment CatchmentId. // All processes must have the same catchment order or they can deadlock when creating communicators that span processes. GlobalDefinition.SortCatchmentsById(); foreach (CatchmentDefinition catchment in GlobalDefinition) { Log.DebugFormat("Rank {0}: catchment {1} Creating communicator for {2} processes", WorldRank, catchment.Id, workAllocator.RanksByCatchment[catchment.Id].Count); IGroupProxy catchmentGroup = CreateGroup(workAllocator.RanksByCatchment[catchment.Id].ToArray()); Log.DebugFormat("Rank {0}: Catchment group created, size = {1}", WorldRank, catchmentGroup.Size); IIntracommunicatorProxy catchmentCommunicator = CreateIntracommunicatorProxy(catchmentGroup); if (catchmentCommunicator != null) { Log.DebugFormat("Rank {0}: Communicator created, rank = {1} size = {2}", WorldRank, catchmentCommunicator.GetRank(this.WorldRank), catchmentCommunicator.Size); } else { Log.DebugFormat("Rank {0}: Communicator created, I am not a member", WorldRank); } // catchmentCommunicator will be null if the current rank is not a member of the catchmentGroup. // This is OK, as each rank only requires the communicators for catchments it is involved in. if (catchmentCommunicator != null) { Debug.Assert(workAllocator.RanksByCatchment[catchment.Id].Contains(WorldRank)); communicatorsByCatchmentId.Add(catchment.Id, catchmentCommunicator); #if CELL_WEIGHTED_SUMS // If I am the catchment coordinator for at least one catchment, then I will need the dictionary of cached // catchment statistics evaluators if (catchmentCommunicator.GetRank(this.WorldRank) == 0) { Log.DebugFormat("Rank {0}: I am catchment coordinator. Creating stats evaluator cache.", WorldRank); // count how often this process acts as catchment coordinator CatchmentCoordinatorCount++; // create the statistics evaluator cache if (CatchmentStatisticsEvaluatorCache == null) { CatchmentStatisticsEvaluatorCache = new Dictionary <string, CatchmentStatisticsEvaluator <ICloneableSimulation, MpiSysConfig> >(); } } #endif } else { Debug.Assert(!workAllocator.RanksByCatchment[catchment.Id].Contains(WorldRank)); } } }
private void DebugDumpWorkAllocator(IWorkAllocator workAllocator) { #if DEBUG_MODELS Log.DebugFormat("Rank {0}: gridded result count = {1}", WorldRank, workAllocator.GriddedResultCount); for (int i = 0; i < GetWorldSize(); i++) { Log.DebugFormat("Rank {0} sees {2} catchment results for rank {1}", WorldRank, i, workAllocator.NumCatchmentResultsPerWorker[i]); Log.DebugFormat("Rank {0} sees {2} gridded results for rank {1}", WorldRank, i, workAllocator.NumGriddedResultsPerWorker[i]); } foreach (CatchmentDefinition catchment in GlobalDefinition) { HashSet <int> ranks = workAllocator.RanksByCatchment[catchment.Id]; string msg = String.Format("Rank {0}: Catchment {1} has {2} ranks: ", WorldRank, catchment.Id, ranks.Count); foreach (int rank in ranks) { msg += String.Format("{0}, ", rank); } Log.DebugFormat(msg); } #endif }
/// <summary> /// Allocates work and distributes the work packages to all workers. /// </summary> /// <param name="workAllocator">The work allocator. Different allocation strategies can be selected through this argument.</param> private void AllocateWork(IWorkAllocator workAllocator) { if (workAllocator == null) { throw new ArgumentNullException("workAllocator"); } Log.DebugFormat("Rank {0}: Allocating work", WorldRank); workAllocator.Allocate(); DebugDumpWorkAllocator(workAllocator); // create the MPI communicators used to coordinate processes involved in each catchment CreateCommunicators(workAllocator); // we only need to preserve some data from the work allocator SetWorkPackage(workAllocator.WorkPackage); NumCatchmentResultsPerWorker = workAllocator.NumCatchmentResultsPerWorker; NumGriddedResultsPerWorker = workAllocator.NumGriddedResultsPerWorker; TotalCellCount = workAllocator.GriddedResultCount; // check that we have enough work for the number of workers if (IsMaster && TotalCellCount < GetWorldSize() - 1) { throw new ConfigurationException( String.Format( "The number of worker processes cannot be greater than the number of cells. Currently: {0} workers, {1} cells", GetWorldSize() - 1, TotalCellCount)); } #if !CELL_WEIGHTED_SUMS CalculateCoordinatorCount(); #endif Log.DebugFormat("Rank {0}: AllocateWork complete", WorldRank); }