Chi-Tech
SPDS_AdamsAdamsHawkins.cc
Go to the documentation of this file.
2
4
5#include "chi_runtime.h"
6#include "chi_log.h"
7
9#include "utils/chi_timer.h"
10
11#include <algorithm>
12
14{
15
17 const chi_mesh::Vector3& omega,
18 const chi_mesh::MeshContinuum& grid,
19 bool cycle_allowance_flag,
20 bool verbose)
21 : SPDS(omega, grid, verbose)
22{
24 << " Building sweep ordering for Omega = "
25 << omega.PrintS();
26
27 size_t num_loc_cells = grid.local_cells.size();
28
29 //============================================= Populate Cell Relationships
30 Chi::log.Log0Verbose1() << "Populating cell relationships";
31 std::vector<std::set<std::pair<int, double>>> cell_successors(num_loc_cells);
32 std::set<int> location_successors;
33 std::set<int> location_dependencies;
34
36 location_dependencies,
37 location_successors,
38 cell_successors);
39
40 location_successors_.reserve(location_successors.size());
41 location_dependencies_.reserve(location_dependencies.size());
42
43 for (auto v : location_successors)
44 location_successors_.push_back(v);
45
46 for (auto v : location_dependencies)
47 location_dependencies_.push_back(v);
48
49 //============================================= Build graph
50 chi::DirectedGraph local_DG;
51
52 // Add vertex for each local cell
53 for (int c = 0; c < num_loc_cells; ++c)
54 local_DG.AddVertex();
55
56 // Create graph edges
57 for (int c = 0; c < num_loc_cells; c++)
58 for (auto& successor : cell_successors[c])
59 local_DG.AddEdge(c, successor.first, successor.second);
60
61 //============================================= Remove local cycles if allowed
62 if (verbose_)
64
65 if (cycle_allowance_flag)
66 {
68 << Chi::program_timer.GetTimeString() << " Removing inter-cell cycles.";
69
70 auto edges_to_remove = local_DG.RemoveCyclicDependencies();
71
72 for (auto& edge_to_remove : edges_to_remove)
73 {
74 local_cyclic_dependencies_.emplace_back(edge_to_remove.first,
75 edge_to_remove.second);
76 }
77 }
78
79 //============================================= Generate topological sorting
82 << " Generating topological sorting for local sweep ordering";
83 auto so_temp = local_DG.GenerateTopologicalSort();
84 spls_.item_id.clear();
85 for (auto v : so_temp)
86 spls_.item_id.emplace_back(v);
87
88 if (spls_.item_id.empty())
89 {
91 << "Topological sorting for local sweep-ordering failed. "
92 << "Cyclic dependencies detected. Cycles need to be allowed"
93 << " by calling application.";
94 Chi::Exit(EXIT_FAILURE);
95 }
96
97 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% Create Task
98 // Dependency Graphs
99 // All locations will gather other locations' dependencies
100 // so that each location has the ability to build
101 // the global task graph.
102
104 << " Communicating sweep dependencies.";
105
106 // auto& global_dependencies = sweep_order->global_dependencies;
107 std::vector<std::vector<int>> global_dependencies;
108 global_dependencies.resize(Chi::mpi.process_count);
109
111
112 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% Build task
113 // dependency graph
114 BuildTaskDependencyGraph(global_dependencies, cycle_allowance_flag);
115
117
119 << " Done computing sweep ordering.\n\n";
120}
121
122// ###################################################################
123/**Builds the task dependency graph.*/
126 const std::vector<std::vector<int>>& global_dependencies,
127 bool cycle_allowance_flag)
128{
129
130 std::vector<std::pair<int, int>> edges_to_remove;
131 std::vector<int> raw_edges_to_remove;
133
134 //============================================= Build graph on home location
135 if (Chi::mpi.location_id == 0)
136 {
138 << " Building Task Dependency Graphs.";
139
140 //====================================== Add vertices to the graph
141 for (int loc = 0; loc < Chi::mpi.process_count; loc++)
142 TDG.AddVertex();
143
144 //====================================== Add dependencies
145 for (int loc = 0; loc < Chi::mpi.process_count; loc++)
146 for (int dep = 0; dep < global_dependencies[loc].size(); dep++)
147 TDG.AddEdge(global_dependencies[loc][dep], loc);
148
149 //====================================== Remove cyclic dependencies
150 if (cycle_allowance_flag)
151 {
153 << " Removing intra-cellset cycles.";
154 auto edges_to_remove_temp = TDG.RemoveCyclicDependencies();
155 for (const auto& [v0, v1] : edges_to_remove_temp)
156 edges_to_remove.emplace_back(v0, v1);
157 }
158
159 //====================================== Serialize edges to be removed
160 raw_edges_to_remove.resize(edges_to_remove.size() * 2, 0);
161 int i = 0;
162 for (const auto& edge : edges_to_remove)
163 {
164 raw_edges_to_remove[i++] = edge.first;
165 raw_edges_to_remove[i++] = edge.second;
166 }
167 } // if home
168
169 //============================================= Broadcast edge buffer size
170 int edge_buffer_size = 0;
171
172 if (Chi::mpi.location_id == 0)
173 edge_buffer_size = static_cast<int>(raw_edges_to_remove.size());
174
175 MPI_Bcast(&edge_buffer_size, // Buffer
176 1,
177 MPI_INT, // Count and datatype
178 0, // Root location
179 Chi::mpi.comm); // Communicator
180
181 //============================================= Broadcast edges
182 if (Chi::mpi.location_id != 0)
183 raw_edges_to_remove.resize(edge_buffer_size, -1);
184
185 MPI_Bcast(raw_edges_to_remove.data(), // Buffer
186 edge_buffer_size,
187 MPI_INT, // Count and datatype
188 0, // Root location
189 Chi::mpi.comm); // Communicator
190
191 //============================================= De-serialize edges
192 if (Chi::mpi.location_id != 0)
193 {
194 edges_to_remove.resize(edge_buffer_size / 2, std::pair<int, int>(0, 0));
195 int i = 0;
196 for (auto& edge : edges_to_remove)
197 {
198 edge.first = raw_edges_to_remove[i++];
199 edge.second = raw_edges_to_remove[i++];
200 }
201 }
202
203 //============================================= Remove edges
204 for (auto& edge_to_remove : edges_to_remove)
205 {
206 int rlocI = edge_to_remove.first;
207 int locI = edge_to_remove.second;
208
209 if (Chi::mpi.location_id == 0) TDG.RemoveEdge(rlocI, locI);
210
211 if (locI == Chi::mpi.location_id)
212 {
213 auto dependent_location = std::find(
214 location_dependencies_.begin(), location_dependencies_.end(), rlocI);
215 location_dependencies_.erase(dependent_location);
216 delayed_location_dependencies_.push_back(rlocI);
217 }
218
219 if (rlocI == Chi::mpi.location_id)
220 delayed_location_successors_.push_back(locI);
221 }
222
223 //============================================= Generate topological sort
224 std::vector<int> glob_linear_sweep_order;
225 if (Chi::mpi.location_id == 0)
226 {
228 << " - Generating topological sort.";
229 auto so_temp = TDG.GenerateTopologicalSort();
230 for (auto v : so_temp)
231 glob_linear_sweep_order.emplace_back(v);
232
233 if (glob_linear_sweep_order.empty())
234 {
236 << "Topological sorting for global sweep-ordering failed. "
237 << "Cyclic dependencies detected. Cycles need to be allowed"
238 << " by calling application.";
239 Chi::Exit(EXIT_FAILURE);
240 }
241 }
242
243 //============================================= Broadcasting topsort size
244 int topsort_buffer_size = 0;
245
246 if (Chi::mpi.location_id == 0)
247 topsort_buffer_size = glob_linear_sweep_order.size();
248
249 MPI_Bcast(&topsort_buffer_size, // Buffer
250 1,
251 MPI_INT, // Count and datatype
252 0, // Root location
253 Chi::mpi.comm); // Communicator
254
255 //============================================= Broadcast topological sort
256 if (Chi::mpi.location_id != 0)
257 glob_linear_sweep_order.resize(topsort_buffer_size, -1);
258
259 MPI_Bcast(glob_linear_sweep_order.data(), // Buffer
260 topsort_buffer_size,
261 MPI_INT, // Count and datatype
262 0, // Root location
263 Chi::mpi.comm); // Communicator
264
265 //============================================= Compute reorder mapping
266 // This mapping allows us to punch in
267 // the location id and find what its
268 // id is in the TDG
269 std::vector<int> glob_order_mapping(Chi::mpi.process_count, -1);
270
271 for (int k = 0; k < Chi::mpi.process_count; k++)
272 {
273 int loc = glob_linear_sweep_order[k];
274 glob_order_mapping[loc] = k;
275 }
276
277 //============================================= Determine sweep order ranks
279 << " Determining sweep order ranks.";
280
281 std::vector<int> glob_sweep_order_rank(Chi::mpi.process_count, -1);
282
283 int abs_max_rank = 0;
284 for (int k = 0; k < Chi::mpi.process_count; k++)
285 {
286 int loc = glob_linear_sweep_order[k];
287 if (global_dependencies[loc].empty()) glob_sweep_order_rank[k] = 0;
288 else
289 {
290 int max_rank = -1;
291 for (auto dep_loc : global_dependencies[loc])
292 {
293 if (dep_loc < 0) continue;
294 int dep_mapped_index = glob_order_mapping[dep_loc];
295
296 if (glob_sweep_order_rank[dep_mapped_index] > max_rank)
297 max_rank = glob_sweep_order_rank[dep_mapped_index];
298 }
299 glob_sweep_order_rank[k] = max_rank + 1;
300 if ((max_rank + 1) > abs_max_rank) abs_max_rank = max_rank + 1;
301 }
302 }
303
304 //============================================= Generate TDG structure
306 << " Generating TDG structure.";
307 for (int r = 0; r <= abs_max_rank; r++)
308 {
310
311 for (int k = 0; k < Chi::mpi.process_count; k++)
312 {
313 if (glob_sweep_order_rank[k] == r)
314 new_stdg.item_id.push_back(glob_linear_sweep_order[k]);
315 }
316 global_sweep_planes_.push_back(new_stdg);
317 }
318}
319
320} // namespace chi_mesh::sweep_management
static chi::Timer program_timer
Definition: chi_runtime.h:79
static void Exit(int error_code)
Definition: chi_runtime.cc:342
static chi::ChiLog & log
Definition: chi_runtime.h:81
static chi::MPI_Info & mpi
Definition: chi_runtime.h:78
LogStream LogAllError()
Definition: chi_log.h:239
LogStream LogAllVerbose2()
Definition: chi_log.h:242
LogStream Log0Verbose1()
Definition: chi_log.h:234
std::vector< size_t > GenerateTopologicalSort()
std::vector< std::pair< size_t, size_t > > RemoveCyclicDependencies()
void AddVertex(size_t id, void *context=nullptr)
void RemoveEdge(size_t from, size_t to)
bool AddEdge(size_t from, size_t to, double weight=1.0)
const MPI_Comm & comm
MPI communicator.
Definition: mpi_info.h:28
void Barrier() const
Definition: mpi_info.cc:38
const int & process_count
Total number of processes.
Definition: mpi_info.h:27
std::string GetTimeString() const
Definition: chi_timer.cc:38
LocalCellHandler local_cells
void BuildTaskDependencyGraph(const std::vector< std::vector< int > > &global_dependencies, bool cycle_allowance_flag)
SPDS_AdamsAdamsHawkins(const chi_mesh::Vector3 &omega, const chi_mesh::MeshContinuum &grid, bool cycle_allowance_flag, bool verbose)
std::vector< int > location_dependencies_
Definition: SPDS.h:63
std::vector< int > location_successors_
Definition: SPDS.h:64
std::vector< std::pair< int, int > > local_cyclic_dependencies_
Definition: SPDS.h:68
void PrintedGhostedGraph() const
Definition: SPDS.cc:179
void PopulateCellRelationships(const chi_mesh::Vector3 &omega, std::set< int > &location_dependencies, std::set< int > &location_successors, std::vector< std::set< std::pair< int, double > > > &cell_successors)
Definition: SPDS.cc:51
void CommunicateLocationDependencies(const std::vector< int > &location_dependencies, std::vector< std::vector< int > > &global_dependencies)
std::string PrintS() const
std::vector< int > item_id
Definition: SPLS.h:13
std::vector< int > item_id
Definition: SPLS.h:21