YAC 3.18.0
Yet Another Coupler
Loading...
Searching...
No Matches
proc_sphere_part.c
Go to the documentation of this file.
1// Copyright (c) 2024 The YAC Authors
2//
3// SPDX-License-Identifier: BSD-3-Clause
4
5#include <limits.h>
6#include <string.h>
7
8#include <mpi.h>
9
10#include "proc_sphere_part.h"
11#include "remote_point.h"
12#include "ensure_array_size.h"
13#include "yac_mpi_internal.h"
14#ifdef SCOREP_USER_ENABLE
15#include "scorep/SCOREP_User.h"
16#endif // SCOREP_USER_ENABLE
17
22
23// WARNING: before changing this datatype ensure that the MPI datatype created
24// for this still matches its data layout
26 double coord[3];
30 size_t owner_offset; // hint: this variable is always generated before it
31 // being used and only contains information relevant for
32 // the local process, hence it is not communicated
33};
34
38 int * sdispls;
39 int * rdispls;
40};
41
42// forward declaration of the struct proc_sphere_part_node
44
50 union {
56 int rank;
58 int is_leaf;
59};
60
71
77
82
84 struct proc_sphere_part_node_data node_data, MPI_Comm comm);
85
87 struct proc_sphere_part_node node, MPI_Comm comm) {
88
89 int vec_pack_size;
91 MPI_Pack_size(3, MPI_DOUBLE, comm, &vec_pack_size), comm);
92
93 return vec_pack_size +
96}
97
99 struct proc_sphere_part_node_data node_data, MPI_Comm comm) {
100
101 int int_pack_size;
102 yac_mpi_call(MPI_Pack_size(1, MPI_INT, comm, &int_pack_size), comm);
103
104 int data_size = int_pack_size;
105 if (node_data.is_leaf)
106 data_size += int_pack_size;
107 else
108 data_size +=
110
111 return data_size;
112}
113
115 struct proc_sphere_part_node_data node_data, void * pack_buffer,
116 int pack_buffer_size, int * position, MPI_Comm comm);
117
119 struct proc_sphere_part_node * node, void * pack_buffer,
120 int pack_buffer_size, int * position, MPI_Comm comm) {
121
122 yac_mpi_call(MPI_Pack(&(node->gc_norm_vector[0]), 3, MPI_DOUBLE, pack_buffer,
123 pack_buffer_size, position, comm), comm);
125 node->U, pack_buffer, pack_buffer_size, position, comm);
127 node->T, pack_buffer, pack_buffer_size, position, comm);
128}
129
131 struct proc_sphere_part_node_data node_data, void * pack_buffer,
132 int pack_buffer_size, int * position, MPI_Comm comm) {
133
134 yac_mpi_call(MPI_Pack(&(node_data.is_leaf), 1, MPI_INT, pack_buffer,
135 pack_buffer_size, position, comm), comm);
136
137 if (node_data.is_leaf)
138 yac_mpi_call(MPI_Pack(&(node_data.data.rank), 1, MPI_INT, pack_buffer,
139 pack_buffer_size, position, comm), comm);
140 else
141 pack_proc_sphere_part_node(node_data.data.node, pack_buffer,
142 pack_buffer_size, position, comm);
143}
144
146 void * pack_buffer, int pack_buffer_size, int * position,
147 MPI_Comm comm);
148
150 void * pack_buffer, int pack_buffer_size, int * position,
151 MPI_Comm comm) {
152
153 struct proc_sphere_part_node * node = xmalloc(1 * sizeof(*node));
154
156 MPI_Unpack(pack_buffer, pack_buffer_size, position,
157 &(node->gc_norm_vector[0]), 3, MPI_DOUBLE, comm), comm);
158
159 node->U = unpack_proc_sphere_part_node_data(pack_buffer, pack_buffer_size,
160 position, comm);
161 node->T = unpack_proc_sphere_part_node_data(pack_buffer, pack_buffer_size,
162 position, comm);
163
164 return node;
165}
166
168 void * pack_buffer, int pack_buffer_size, int * position,
169 MPI_Comm comm) {
170
171 struct proc_sphere_part_node_data node_data;
172
174 MPI_Unpack(pack_buffer, pack_buffer_size, position,
175 &(node_data.is_leaf), 1, MPI_INT, comm), comm);
176
177 if (node_data.is_leaf)
179 MPI_Unpack(pack_buffer, pack_buffer_size, position,
180 &(node_data.data.rank), 1, MPI_INT, comm), comm);
181 else
182 node_data.data.node =
184 pack_buffer, pack_buffer_size, position, comm);
185
186 return node_data;
187}
188
190 struct proc_sphere_part_node_data local_data,
191 struct yac_group_comm local_group_comm,
192 struct yac_group_comm remote_group_comm) {
193
194 int comm_rank;
195 MPI_Comm comm = local_group_comm.comm;
196 yac_mpi_call(MPI_Comm_rank(comm, &comm_rank), comm);
197
198 int data_size;
199 void * recv_buffer = NULL;
200
201 int order = local_group_comm.start < remote_group_comm.start;
202
203 for (int i = 0; i < 2; ++i) {
204
205 if (order == i) {
206
208 &data_size, 1, MPI_INT, remote_group_comm.start, local_group_comm);
209 recv_buffer = xmalloc((size_t)data_size);
210 yac_bcast_group(recv_buffer, data_size, MPI_PACKED,
211 remote_group_comm.start, local_group_comm);
212
213 } else {
214 if (comm_rank == local_group_comm.start) {
215
216 // pack local_data
217 int pack_buffer_size =
219 void * pack_buffer = xmalloc((size_t)pack_buffer_size);
220 int position = 0;
222 local_data, pack_buffer, pack_buffer_size, &position, comm);
223
224 // broadcast data size to other group
226 &position, 1, MPI_INT, local_group_comm.start, remote_group_comm);
227
228 // broadcast remote_data to other root
229 yac_bcast_group(pack_buffer, position, MPI_PACKED,
230 local_group_comm.start, remote_group_comm);
231 free(pack_buffer);
232 }
233 }
234 }
235
236 // unpack node data
237 int position = 0;
238 struct proc_sphere_part_node_data other_data =
240 recv_buffer, data_size, &position, comm);
241 free(recv_buffer);
242
243 return other_data;
244}
245
247 int comm_rank, int split_rank, int comm_size,
248 size_t global_sizes[2], size_t (*all_bucket_sizes)[2],
249 int * counts, int * displs, size_t * recv_count) {
250
251 int color = comm_rank >= split_rank;
252
253 int split_comm_size = split_rank;
254 int split_comm_rank = comm_rank;
255 if (color) {
257 split_comm_size = comm_size - split_comm_size;
258 }
259
260 size_t global_size = global_sizes[color];
261 size_t local_interval_start =
262 (size_t)
263 (((long long)global_size * (long long)split_comm_rank +
264 (long long)(split_comm_size - 1)) /
265 (long long)split_comm_size);
266 size_t local_interval_end =
267 (size_t)
268 (((long long)global_size * (long long)(split_comm_rank+1) +
269 (long long)(split_comm_size - 1)) /
270 (long long)split_comm_size);
271
272 *recv_count = (size_t)(local_interval_end - local_interval_start);
273
274 size_t start_idx = 0;
275 for (int i = 0; i < comm_size; ++i) {
276
277 size_t next_start_idx = start_idx + all_bucket_sizes[i][color];
278 size_t interval_start = MAX(start_idx, local_interval_start);
279 size_t interval_end = MIN(next_start_idx, local_interval_end);
280
281 if (interval_start < interval_end) {
282
283 size_t count = interval_end - interval_start;
284 size_t disp = interval_start - local_interval_start;
285
287 (count <= INT_MAX) && (disp <= INT_MAX),
288 "ERROR(compute_redist_recvcounts_rdispls): invalid interval")
289
290 counts[i] = (int)count;
291 displs[i] = (int)disp;
292 } else {
293 counts[i] = 0;
294 displs[i] = 0;
295 }
296
297 start_idx = next_start_idx;
298 }
299}
300
302 int comm_rank, int split_rank, int comm_size,
303 size_t global_sizes[2], size_t (*all_bucket_sizes)[2],
304 int * counts, int * displs) {
305
306 size_t U_size = all_bucket_sizes[comm_rank][0];
307
308 size_t local_interval_start[2] = {0, 0};
309 size_t local_interval_end[2];
310 for (int i = 0; i < comm_rank; ++i)
311 for (int j = 0; j < 2; ++j)
312 local_interval_start[j] += all_bucket_sizes[i][j];
313 for (int j = 0; j < 2; ++j)
314 local_interval_end[j] =
315 local_interval_start[j] + all_bucket_sizes[comm_rank][j];
316
317 int comm_sizes[2] = {split_rank, comm_size - split_rank};
318
319 size_t start_idx[2] = {0,0};
320 for (int i = 0; i < comm_size; ++i) {
321
322 int color = i >= split_rank;
323 size_t global_size = global_sizes[color];
324 int split_comm_rank = i - (color?(split_rank):0);
325 int split_comm_size = comm_sizes[color];
326 size_t next_start_idx =
327 (size_t)(
328 ((long long)global_size * (long long)(split_comm_rank + 1) +
329 (long long)(split_comm_size - 1)) /
330 (long long)split_comm_size);
331 size_t interval_start = MAX(start_idx[color], local_interval_start[color]);
332 size_t interval_end = MIN(next_start_idx, local_interval_end[color]);
333
334 if (interval_start < interval_end) {
335
336 size_t count = interval_end - interval_start;
337 size_t disp = interval_start - local_interval_start[color] +
338 ((color)?(U_size):(0));
339
341 (count <= INT_MAX) && (disp <= INT_MAX),
342 "ERROR(compute_redist_sendcounts_sdispls): invalid interval")
343
344 counts[i] = (int)count;
345 displs[i] = (int)disp;
346 } else {
347 counts[i] = 0;
348 displs[i] = 0;
349 }
350
351 start_idx[color] = next_start_idx;
352 }
353}
354
356 size_t * reorder_idx, size_t count, struct remote_point_info * data) {
357
358 // this routine assumes that all entries in reorder_idx are unique and in the
359 // range [0;count[
360
361 // for all elements
362 for (size_t i = 0; i < count; ++i) {
363
364 if (reorder_idx[i] != i) {
365
366 size_t j = i;
367 struct remote_point_info temp = data[i];
368
369 while(1) {
370 { // swap(j, reorder_idx[j]}
371 size_t swap = reorder_idx[j];
372 reorder_idx[j] = j;
373 j = swap;
374 }
375 if (j == i) break;
376 { // swap(temp, data[j]
377 struct remote_point_info swap = data[j];
378 data[j] = temp;
379 temp = swap;
380 }
381 };
382
383 data[i] = temp;
384 }
385 }
386}
387
388static int compare_dist_vertices(const void * a, const void * b) {
389
390 int ret;
391
392 if ((ret = ((const struct dist_vertex *)a)->grid_idx -
393 ((const struct dist_vertex *)b)->grid_idx)) return ret;
394 if (((const struct dist_vertex *)a)->global_id != YAC_INT_MAX)
395 return
396 (((const struct dist_vertex *)a)->global_id >
397 ((const struct dist_vertex *)b)->global_id) -
398 (((const struct dist_vertex *)a)->global_id <
399 ((const struct dist_vertex *)b)->global_id);
400 else
401 return
403 ((const struct dist_vertex *)a)->coord,
404 ((const struct dist_vertex *)b)->coord);
405}
406
408 struct dist_vertex * vertices, size_t * num_vertices,
409 struct remote_point_info * owners, size_t num_owners,
410 size_t ** owners_reorder_idx, size_t * owners_reorder_idx_array_size) {
411
412 if (*num_vertices == 0) return;
413
415 *owners_reorder_idx, *owners_reorder_idx_array_size, num_owners);
416
417 // initialise owner offset
418 {
419 size_t owner_offset = 0;
420 for (size_t i = 0; i < *num_vertices; ++i) {
421 vertices[i].owner_offset = owner_offset;
422 owner_offset += (size_t)(vertices[i].num_owners);
423 }
426 "ERROR(remove_duplicated_vertices): internal error "
427 "(owner_offset != num_owners)");
428 }
429
430 // sort vertices by grid id and global id, if available otherwise compare
431 // coordinates
432 qsort(vertices, *num_vertices, sizeof(*vertices), compare_dist_vertices);
433 // on GPU/NEC VE do separate sorts for each criteria using radix sort
434
435 size_t old_num_vertices = *num_vertices;
436 size_t new_num_vertices = 0;
437 struct dist_vertex dummy_vertex = {.grid_idx = INT_MAX};
438 struct dist_vertex * prev_vertex = &dummy_vertex;
439 struct dist_vertex * curr_vertex = vertices;
440 size_t * owners_reorder_idx_ = *owners_reorder_idx;
441 for (size_t i = 0, reorder_idx = 0; i < old_num_vertices;
442 ++i, ++curr_vertex) {
443 size_t owner_offset = curr_vertex->owner_offset;
444 for (int j = 0; j < curr_vertex->num_owners;
445 ++j, ++owner_offset, ++reorder_idx)
446 owners_reorder_idx_[owner_offset] = reorder_idx;
447 if (compare_dist_vertices(prev_vertex, curr_vertex)) {
448 prev_vertex = vertices + new_num_vertices;
449 ++new_num_vertices;
450 if (prev_vertex != curr_vertex) *prev_vertex = *curr_vertex;
451 } else {
452 prev_vertex->num_owners += curr_vertex->num_owners;
453 }
454 }
455 *num_vertices = new_num_vertices;
456
457 // reorder owners according to new vertex order
458 reorder_data_remote_point_info(owners_reorder_idx_, num_owners, owners);
459}
460
462 struct dist_vertex ** vertices, size_t * num_vertices,
463 struct remote_point_info ** owners, size_t * num_owners,
464 size_t global_bucket_sizes[2], size_t (*all_bucket_sizes)[2],
465 int split_rank, struct comm_buffers comm_buffers,
466 size_t ** owners_reorder_idx, size_t * owners_reorder_idx_array_size,
467 MPI_Datatype dist_vertex_dt, MPI_Datatype remote_point_info_dt,
468 struct yac_group_comm group_comm) {
469
470#ifdef SCOREP_USER_ENABLE
471SCOREP_USER_REGION_DEFINE( redist_data_region )
472SCOREP_USER_REGION_BEGIN(
473 redist_data_region, "data redistribution", SCOREP_USER_REGION_TYPE_COMMON )
474#endif
475
476 int group_rank = yac_group_comm_get_rank(group_comm);
477 int group_size = yac_group_comm_get_size(group_comm);
478
479 // compute send and receive counts and respective ranks for data
480 // redistribution
482 group_rank, split_rank, group_size, global_bucket_sizes, all_bucket_sizes,
484 size_t new_num_vertices;
486 group_rank, split_rank, group_size, global_bucket_sizes, all_bucket_sizes,
487 comm_buffers.recvcounts, comm_buffers.rdispls, &new_num_vertices);
488
489 // redistribute vertices
490 struct dist_vertex * new_vertices =
491 xmalloc(new_num_vertices * sizeof(*new_vertices));
495 sizeof(**vertices), dist_vertex_dt, group_comm);
496
497 // adjust comm_buffers for redistribution of owner data
498 size_t new_num_owners;
499 {
500 size_t saccu = 0, raccu = 0, send_vertex_idx = 0, recv_vertex_idx = 0;
501 for (int i = 0; i < group_size; ++i) {
502 size_t send_count = 0, recv_count = 0;
503 for (int j = 0; j < comm_buffers.sendcounts[i]; ++j, ++send_vertex_idx)
504 send_count += (size_t)((*vertices)[send_vertex_idx].num_owners);
505 for (int j = 0; j < comm_buffers.recvcounts[i]; ++j, ++recv_vertex_idx)
506 recv_count += (size_t)(new_vertices[recv_vertex_idx].num_owners);
508 (saccu <= INT_MAX) && (raccu <= INT_MAX),
509 "ERROR(redistribute_dist_vertices): displacement exceeds INT_MAX");
511 (send_count <= INT_MAX) && (recv_count <= INT_MAX),
512 "ERROR(redistribute_dist_vertices): counts exceeds INT_MAX");
513 comm_buffers.sendcounts[i] = (int)send_count;
514 comm_buffers.recvcounts[i] = (int)recv_count;
515 comm_buffers.sdispls[i] = (int)saccu;
516 comm_buffers.rdispls[i] = (int)raccu;
517 saccu += send_count;
518 raccu += recv_count;
519 }
521 saccu == *num_owners,
522 "ERROR(redistribute_dist_vertices): inconsistent owner count");
523 new_num_owners = raccu;
524 }
525
526 // redistribute owner data
527 struct remote_point_info * new_owners =
528 xmalloc(new_num_owners * sizeof(*new_owners));
532 sizeof(**owners), remote_point_info_dt, group_comm);
533
534 free(*vertices);
535 free(*owners);
536 *vertices = new_vertices;
537 *num_vertices = new_num_vertices;
538 *owners = new_owners;
539 *num_owners = new_num_owners;
540
541 // check for duplicated vertices
542 // (identified either by global id (if available) or coordinates)
544 *vertices, num_vertices, *owners, *num_owners,
545 owners_reorder_idx, owners_reorder_idx_array_size);
546
547#ifdef SCOREP_USER_ENABLE
548SCOREP_USER_REGION_END( redist_data_region )
549#endif
550}
551
572 double const * restrict gc_norm_vector,
573 double const * restrict vertex_coord) {
574
575 return
576 (dotproduct_eft(gc_norm_vector, vertex_coord) <= 0.0)?
577 U_LIST : T_LIST;
578}
579
581 struct dist_vertex ** vertices, size_t * num_vertices,
582 struct remote_point_info ** owners, size_t * num_owners,
583 size_t (*all_bucket_sizes)[2], struct comm_buffers comm_buffers,
584 size_t ** reorder_idx, size_t * reorder_idx_array_size,
585 int ** list_flag_, size_t * list_flag_array_size,
586 MPI_Datatype dist_vertex_dt, MPI_Datatype remote_point_info_dt,
587 struct yac_group_comm group_comm, double prev_gc_norm_vector[3]) {
588
589#ifdef SCOREP_USER_ENABLE
590SCOREP_USER_REGION_DEFINE( local_balance_point_region )
591SCOREP_USER_REGION_DEFINE( global_balance_point_region )
592SCOREP_USER_REGION_DEFINE( splitting_region )
593SCOREP_USER_REGION_DEFINE( comm_split_region )
594#endif
595
596 int group_rank = yac_group_comm_get_rank(group_comm);
597 int group_size = yac_group_comm_get_size(group_comm);
598
599 //--------------------
600 // compute split plane
601 //--------------------
602
603#ifdef SCOREP_USER_ENABLE
604SCOREP_USER_REGION_BEGIN(
605 local_balance_point_region, "local balance point",
606 SCOREP_USER_REGION_TYPE_COMMON )
607#endif
608 // compute local balance point
609 double balance_point[3] = {0.0, 0.0, 0.0};
610 for (size_t i = 0; i < *num_vertices; ++i) {
611 double * vertex_coord = (*vertices)[i].coord;
612 for (int j = 0; j < 3; ++j) balance_point[j] += vertex_coord[j];
613 }
614#ifdef SCOREP_USER_ENABLE
615SCOREP_USER_REGION_END( local_balance_point_region )
616SCOREP_USER_REGION_BEGIN(
617 global_balance_point_region, "global balance point",
618 SCOREP_USER_REGION_TYPE_COMMON )
619#endif
620
621 // compute global balance point (make sure that the allreduce operation
622 // generates bit-identical results on all processes)
623 yac_allreduce_sum_dble(&(balance_point[0]), 3, group_comm);
624
625 // check whether the computed balance_point is unambiguous, otherwise use
626 // a point which is perpendicularly to the previous split plane
627 if ((fabs(balance_point[0]) > 1e-9) ||
628 (fabs(balance_point[1]) > 1e-9) ||
629 (fabs(balance_point[2]) > 1e-9)) {
630 normalise_vector(balance_point);
631 } else {
632 balance_point[0] = prev_gc_norm_vector[2];
633 balance_point[1] = prev_gc_norm_vector[0];
634 balance_point[2] = prev_gc_norm_vector[1];
635 }
636
637 // compute norm vector of new split plane
638 double gc_norm_vector[3];
639 crossproduct_kahan(balance_point, prev_gc_norm_vector, gc_norm_vector);
640
641 // check whether the computed norm vector is unambiguous, otherwise use
642 // a norm vector which is perpendicularly to the previous split plane
643 if ((fabs(gc_norm_vector[0]) > 1e-9) ||
644 (fabs(gc_norm_vector[1]) > 1e-9) ||
645 (fabs(gc_norm_vector[2]) > 1e-9)) {
647 } else {
648 gc_norm_vector[0] = prev_gc_norm_vector[2];
649 gc_norm_vector[1] = prev_gc_norm_vector[0];
650 gc_norm_vector[2] = prev_gc_norm_vector[1];
651 }
652
653#ifdef SCOREP_USER_ENABLE
654SCOREP_USER_REGION_END( global_balance_point_region )
655#endif
656
657 //-----------------
658 // split local data
659 //-----------------
660
661#ifdef SCOREP_USER_ENABLE
662SCOREP_USER_REGION_BEGIN( splitting_region, "splitting data", SCOREP_USER_REGION_TYPE_COMMON )
663#endif
664
665 ENSURE_ARRAY_SIZE(*list_flag_, *list_flag_array_size, *num_vertices);
666 int * list_flag = *list_flag_;
667
668 // compute for each vertex the list it belongs to
669 struct dist_vertex * vertices_ = *vertices;
670 size_t num_vertices_ = *num_vertices;
672 {
674 for (size_t i = 0; i < num_vertices_; ++i) {
675 list_flag[i] =
676 determine_list_type(gc_norm_vector, vertices_[i].coord) == U_LIST;
677 }
678 }
679 size_t U_size = 0, T_size = 0;
680 for (size_t i = 0; i < num_vertices_; ++i) {
681 if (list_flag[i]) ++U_size;
682 else ++T_size;
683 }
684
685 // initialise owner offset
686 for (size_t i = 0, owner_offset = 0; i < num_vertices_; ++i) {
687 vertices_[i].owner_offset = owner_offset;
688 owner_offset += (size_t)(vertices_[i].num_owners);
689 }
690
691 // The number of T-vertices among the first U-size number of vertices in the
692 // array is equal to the number of U-vertices in the remaining array. These
693 // have to be exchanged in order to get a sorted vertex array
694
695 // search for all T-vertices in the U-part of the array and swap them with a
696 // U-vertex in the T-part
697 for (size_t i = 0, j = U_size; i < U_size; ++i) {
698 // if the current vertex belongs to the T-list
699 if (!list_flag[i]) {
700 // search for a matching U-vertex
701 for (;!list_flag[j];++j);
702 struct dist_vertex temp_vertex = vertices_[i];
703 vertices_[i] = vertices_[j];
704 vertices_[j] = temp_vertex;
705 ++j;
706 }
707 }
708
709 // reorder owners according to new vertex order
710 ENSURE_ARRAY_SIZE(*reorder_idx, *reorder_idx_array_size, *num_owners);
711 size_t * reorder_idx_ = *reorder_idx;
712 for (size_t i = 0, k = 0; i < num_vertices_; ++i) {
713 size_t offset = vertices_[i].owner_offset;
714 int num_owners = vertices_[i].num_owners;
715 for (int j = 0; j < num_owners; ++j, ++k, ++offset) {
716 reorder_idx_[offset] = k;
717 }
718 }
719 reorder_data_remote_point_info(reorder_idx_, *num_owners, *owners);
720
721#ifdef SCOREP_USER_ENABLE
722SCOREP_USER_REGION_END( splitting_region )
723#endif
724
725 size_t bucket_sizes[2] = {U_size, T_size};
726
727 // exchange local U/T sizes between all processes
729 &(bucket_sizes[0]), &(all_bucket_sizes[0][0]), 2, group_comm);
730
731 // determine global U/T sizes
732 size_t global_bucket_sizes[2] = {0, 0};
733 for (int i = 0; i < group_size; ++i)
734 for (int j = 0; j < 2; ++j)
735 global_bucket_sizes[j] += all_bucket_sizes[i][j];
736 size_t global_num_vertices =
737 global_bucket_sizes[0] + global_bucket_sizes[1];
738
739 //----------------------
740 // split into two groups
741 //----------------------
742#ifdef SCOREP_USER_ENABLE
743SCOREP_USER_REGION_BEGIN(
744 comm_split_region, "creating splitcomm", SCOREP_USER_REGION_TYPE_COMMON )
745#endif
746 // determine processor groups
747 int split_rank =
748 MIN(
749 (int)MAX(
750 (((unsigned long long)global_bucket_sizes[0] *
751 (unsigned long long)group_size +
752 (unsigned long long)(global_num_vertices / 2)) /
753 (unsigned long long)global_num_vertices), 1),
754 group_size - 1);
755
756 // generate processor groups
757 struct yac_group_comm local_group_comm, remote_group_comm;
759 group_comm, split_rank, &local_group_comm, &remote_group_comm);
760
761#ifdef SCOREP_USER_ENABLE
762SCOREP_USER_REGION_END( comm_split_region )
763#endif
764
765 //------------------
766 // redistribute data
767 //------------------
768
770 vertices, num_vertices, owners, num_owners,
771 global_bucket_sizes, all_bucket_sizes, split_rank, comm_buffers,
772 reorder_idx, reorder_idx_array_size, dist_vertex_dt, remote_point_info_dt,
773 group_comm);
774
775 //----------
776 // recursion
777 //----------
778
779 // generate proc_sphere_part node for remaining data
780 struct proc_sphere_part_node_data local_data;
781
782 if (yac_group_comm_get_size(local_group_comm) > 1) {
783 local_data.data.node =
785 vertices, num_vertices, owners, num_owners,
786 all_bucket_sizes, comm_buffers, reorder_idx, reorder_idx_array_size,
787 list_flag_, list_flag_array_size, dist_vertex_dt, remote_point_info_dt,
788 local_group_comm, gc_norm_vector);
789 local_data.is_leaf = 0;
790 } else {
791
792 local_data.data.rank = yac_group_comm_get_global_rank(group_comm);
793 local_data.is_leaf = 1;
794 }
795
796 // get proc_sphere_part_node_data from remote group
797 struct proc_sphere_part_node_data remote_data =
798 get_remote_data(local_data, local_group_comm, remote_group_comm);
799
800 // generate node
801 struct proc_sphere_part_node * node = xmalloc(1 * sizeof(*node));
802 if (group_rank < split_rank) {
803 node->U = local_data;
804 node->T = remote_data;
805 } else {
806 node->U = remote_data;
807 node->T = local_data;
808 }
809 memcpy(node->gc_norm_vector, gc_norm_vector, sizeof(gc_norm_vector));
810
811 return node;
812}
813
814static MPI_Datatype yac_get_dist_vertex_mpi_datatype(MPI_Comm comm) {
815
816 struct dist_vertex dummy;
817 MPI_Datatype dist_vertex_dt;
818 enum {NUM_MEMBERS = 4};
819 int array_of_blocklengths[NUM_MEMBERS] = {3, 1, 1, 1};
820 const MPI_Aint array_of_displacements[NUM_MEMBERS] =
821 {(MPI_Aint)(intptr_t)(const void *)&(dummy.coord[0]) -
822 (MPI_Aint)(intptr_t)(const void *)&dummy,
823 (MPI_Aint)(intptr_t)(const void *)&(dummy.grid_idx) -
824 (MPI_Aint)(intptr_t)(const void *)&dummy,
825 (MPI_Aint)(intptr_t)(const void *)&(dummy.global_id) -
826 (MPI_Aint)(intptr_t)(const void *)&dummy,
827 (MPI_Aint)(intptr_t)(const void *)&(dummy.num_owners) -
828 (MPI_Aint)(intptr_t)(const void *)&dummy};
829 const MPI_Datatype array_of_types[NUM_MEMBERS] =
830 {MPI_DOUBLE, MPI_INT, yac_int_dt, MPI_INT};
832 MPI_Type_create_struct(NUM_MEMBERS, array_of_blocklengths,
833 array_of_displacements, array_of_types,
834 &dist_vertex_dt), comm);
835 return yac_create_resized(dist_vertex_dt, sizeof(dummy), comm);
836}
837
839 struct dist_vertex * dist_vertices, size_t num_dist_vertices,
840 struct remote_point_info * dist_owners,
841 size_t ** reorder_idx, size_t * reorder_idx_array_size,
842 yac_int **global_vertex_ids[2], int * global_ids_missing,
843 int **vertex_ranks[2], size_t * num_vertices, MPI_Comm comm) {
844
845 // Here we assume that the vertices are sorted first by their grid index and
846 // second by global id/coordinate (depending on availability).
847 // Additionally, the vertices should contain no duplications.
848
849 int comm_rank, comm_size;
850 yac_mpi_call(MPI_Comm_rank(comm, &comm_rank), comm);
851 yac_mpi_call(MPI_Comm_size(comm, &comm_size), comm);
852
853 // count the number of vertices per grid
854 size_t num_vertices_per_grid[2] = {0, 0};
855 size_t num_owners_per_grid[2] = {0, 0};
856 for (size_t i = 0; i < num_dist_vertices; ++i) {
857 num_vertices_per_grid[dist_vertices[i].grid_idx]++;
858 num_owners_per_grid[dist_vertices[i].grid_idx] +=
859 (size_t)(dist_vertices[i].num_owners);
860 }
861
862 size_t * sendcounts, * recvcounts, * sdispls, * rdispls;
864 1, &sendcounts, &recvcounts, &sdispls, &rdispls, comm);
865
867 *reorder_idx, *reorder_idx_array_size,
868 MAX((num_owners_per_grid[0] + num_vertices[0]),
869 (num_owners_per_grid[1] + num_vertices[1])));
870 yac_int * global_vertex_ids_buffer =
871 xmalloc(
872 MAX(
873 (global_ids_missing[0]?(num_owners_per_grid[0] + num_vertices[0]):0),
874 (global_ids_missing[1]?(num_owners_per_grid[1] + num_vertices[1]):0)) *
875 sizeof(*global_vertex_ids_buffer));
876
877 // for both grids
878 for (int grid_idx = 0; grid_idx < 2; ++grid_idx) {
879
880 struct dist_vertex * dist_grid_vertices =
881 dist_vertices + ((grid_idx == 0)?0:num_vertices_per_grid[0]);
882 struct remote_point_info * dist_grid_owners =
883 dist_owners + ((grid_idx == 0)?0:num_owners_per_grid[0]);
884
885 // if the user did not provide global vertex ids for the current grid
886 yac_int id_offset = 0;
887 if (global_ids_missing[grid_idx]) {
888
890 num_vertices_per_grid[grid_idx] <= (size_t)YAC_INT_MAX,
891 "ERROR(inform_dist_vertex_owners): global_id out of bounds");
892
893 // determine exclusive scan of sum of numbers of unique
894 // coordinates on all ranks
895 yac_int yac_int_num_vertices = (yac_int)num_vertices_per_grid[grid_idx];
896 yac_mpi_call(MPI_Exscan(&yac_int_num_vertices, &id_offset, 1, yac_int_dt,
897 MPI_SUM, comm), comm);
898 if (comm_rank == 0) id_offset = 0;
899
901 ((size_t)id_offset + num_vertices_per_grid[grid_idx]) <=
902 (size_t)YAC_INT_MAX,
903 "ERROR(inform_dist_vertex_owners): global_id out of bounds")
904 }
905
906 memset(sendcounts, 0, (size_t)(comm_size + 1) * sizeof(*sendcounts));
907
908 // determine send counts for vertex information
909 for (size_t i = 0; i < num_owners_per_grid[grid_idx]; ++i)
910 sendcounts[dist_grid_owners[i].rank]++;
912 1, sendcounts, recvcounts, sdispls, rdispls, comm);
913
914 size_t * send_reorder_idx = *reorder_idx;
915 size_t * recv_reorder_idx = *reorder_idx + num_owners_per_grid[grid_idx];
916 yac_int * send_global_vertex_ids = global_vertex_ids_buffer;
917 yac_int * recv_global_vertex_ids = global_vertex_ids_buffer +
918 num_owners_per_grid[grid_idx];
919
920 for (size_t i = 0, k = 0; i < num_vertices_per_grid[grid_idx]; ++i) {
921
922 int num_vertex_owners = dist_grid_vertices[i].num_owners;
923
924 for (int j = 0; j < num_vertex_owners; ++j, ++k) {
925
926 size_t pos = sdispls[dist_grid_owners[k].rank + 1]++;
927 send_reorder_idx[pos] = dist_grid_owners[k].orig_pos;
928 if (global_ids_missing[grid_idx])
929 send_global_vertex_ids[pos] = id_offset + (yac_int)i;
930 }
931 }
932
933 // exchange reorder idx
935 send_reorder_idx, sendcounts, sdispls,
936 recv_reorder_idx, recvcounts, rdispls,
937 sizeof(*send_reorder_idx), YAC_MPI_SIZE_T, comm,
938 "inform_dist_vertex_owners", __LINE__);
939
940 // generate vertex ranks
941 {
942 int * curr_vertex_ranks =
943 xmalloc(num_vertices[grid_idx] * sizeof(*curr_vertex_ranks));
944 size_t j = 0;
945 for (int rank = 0; rank < comm_size; ++rank)
946 for (size_t i = 0; i < recvcounts[rank]; ++i, ++j)
947 curr_vertex_ranks[recv_reorder_idx[j]] = rank;
948 *(vertex_ranks[grid_idx]) = curr_vertex_ranks;
949 }
950
951 // exchange and set global ids (if not provided by the user)
952 if (global_ids_missing[grid_idx]) {
953
955 send_global_vertex_ids, sendcounts, sdispls,
956 recv_global_vertex_ids, recvcounts, rdispls,
957 sizeof(*send_global_vertex_ids), yac_int_dt, comm,
958 "inform_dist_vertex_owners", __LINE__);
959
960 yac_int * curr_global_vertex_ids =
961 xmalloc(num_vertices[grid_idx] * sizeof(*curr_global_vertex_ids));
962
963 for (size_t i = 0; i < num_vertices[grid_idx]; ++i)
964 curr_global_vertex_ids[recv_reorder_idx[i]] = recv_global_vertex_ids[i];
965
966 *(global_vertex_ids[grid_idx]) = curr_global_vertex_ids;
967 }
968 }
969
970 free(global_vertex_ids_buffer);
971
972 yac_free_comm_buffers(sendcounts, recvcounts, sdispls, rdispls);
973}
974
976 yac_coordinate_pointer vertex_coordinates[2], size_t * num_vertices,
977 struct proc_sphere_part_node ** proc_sphere_part,
978 yac_int **global_vertex_ids_[2], int **vertex_ranks[2], MPI_Comm comm) {
979
980 // check whether there are user-provided global vertex ids
981 yac_int *global_vertex_ids[2] =
982 {*(global_vertex_ids_[0]), *(global_vertex_ids_[1])};
983 int global_ids_missing[2] =
984 {(num_vertices[0] > 0) && (global_vertex_ids[0] == NULL),
985 (num_vertices[1] > 0) && (global_vertex_ids[1] == NULL)};
987 MPI_Allreduce(MPI_IN_PLACE, global_ids_missing, 2, MPI_INT, MPI_MAX, comm),
988 comm);
989
990 size_t total_num_vertices = num_vertices[0] + num_vertices[1];
991
992 int comm_rank, comm_size;
993 yac_mpi_call(MPI_Comm_rank(comm, &comm_rank), comm);
994 yac_mpi_call(MPI_Comm_size(comm, &comm_size), comm);
995
996 double base_gc_norm_vector[3] = {0.0,0.0,1.0};
997
998 int vertices_available = total_num_vertices > 0;
1000 MPI_Allreduce(
1001 MPI_IN_PLACE, &vertices_available, 1, MPI_INT, MPI_MAX, comm), comm);
1002
1003 if ((comm_size > 1) && vertices_available) {
1004
1005 // generate basic owner information for all vertices
1006 struct remote_point_info * dist_owners =
1007 xmalloc(total_num_vertices * sizeof(*dist_owners));
1008 for (size_t i = 0; i < num_vertices[0]; ++i)
1009 dist_owners[i] =
1010 (struct remote_point_info){.rank = comm_rank, .orig_pos = i};
1011 for (size_t i = 0, j = num_vertices[0]; i < num_vertices[1]; ++i, ++j)
1012 dist_owners[j] =
1013 (struct remote_point_info){.rank = comm_rank, .orig_pos = i};
1014
1015 // generate vertex information for all vertices
1016 struct dist_vertex * dist_vertices =
1017 xmalloc(total_num_vertices * sizeof(*dist_vertices));
1018 {
1019 size_t k = 0;
1020 // for both grids
1021 for (int i = 0; i < 2; ++i) {
1022 // for all vertices of the grid
1023 for (size_t j = 0; j < num_vertices[i]; ++j, ++k) {
1024 memcpy(
1025 dist_vertices[k].coord, vertex_coordinates[i][j],
1026 3 * sizeof(vertex_coordinates[i][j][0]));
1027 dist_vertices[k].grid_idx = i;
1028 dist_vertices[k].global_id =
1029 (global_ids_missing[i])?YAC_INT_MAX:global_vertex_ids[i][j];
1030 dist_vertices[k].num_owners = 1;
1031 }
1032 }
1033 }
1034
1035 // set up buffers for generation of proc_sphere_part
1036 size_t num_dist_vertices = total_num_vertices;
1037 size_t num_dist_owners = total_num_vertices;
1038 size_t (*all_bucket_sizes)[2] =
1039 xmalloc((size_t)comm_size * sizeof(*(all_bucket_sizes)));
1042 xmalloc(4 * (size_t)comm_size * sizeof(*(comm_buffers.sendcounts)));
1044 comm_buffers.sdispls = comm_buffers.sendcounts + 2 * comm_size;
1045 comm_buffers.rdispls = comm_buffers.sendcounts + 3 * comm_size;
1046 size_t * reorder_idx = NULL, reorder_idx_array_size = 0;
1047 int * list_flag = NULL;
1048 size_t list_flag_array_size = 0;
1049 MPI_Datatype dist_vertex_dt = yac_get_dist_vertex_mpi_datatype(comm);
1050 MPI_Datatype remote_point_info_dt =
1052 struct yac_group_comm group_comm = yac_group_comm_new(comm);
1053
1054 // initial redistribute of all vertices
1055 // (in case one of the two grids has significantly more vertices per process
1056 // than the other, this improves the load balance in the initial step)
1058 (size_t[2]){total_num_vertices,0}, &(all_bucket_sizes[0][0]), 2,
1059 group_comm);
1060 size_t global_num_vertices = 0;
1061 for (int i = 0; i < comm_size; ++i)
1062 global_num_vertices += all_bucket_sizes[i][0];
1064 &dist_vertices, &num_dist_vertices, &dist_owners, &num_dist_owners,
1065 (size_t[2]){global_num_vertices, 0}, all_bucket_sizes, comm_size,
1066 comm_buffers, &reorder_idx, &reorder_idx_array_size,
1067 dist_vertex_dt, remote_point_info_dt, group_comm);
1068
1069 // generate proc_sphere_part
1070 *proc_sphere_part =
1072 &dist_vertices, &num_dist_vertices, &dist_owners, &num_dist_owners,
1073 all_bucket_sizes, comm_buffers, &reorder_idx, &reorder_idx_array_size,
1074 &list_flag, &list_flag_array_size, dist_vertex_dt, remote_point_info_dt,
1075 group_comm, base_gc_norm_vector);
1076
1077 // cleanup
1078 yac_group_comm_delete(group_comm);
1079 yac_mpi_call(MPI_Type_free(&remote_point_info_dt), comm);
1080 yac_mpi_call(MPI_Type_free(&dist_vertex_dt), comm);
1081 free(list_flag);
1083 free(all_bucket_sizes);
1084
1085 // return information about distributed vertices to original owners
1087 dist_vertices, num_dist_vertices, dist_owners,
1088 &reorder_idx, &reorder_idx_array_size, global_vertex_ids_,
1089 global_ids_missing, vertex_ranks, num_vertices, comm);
1090
1091 // cleanup
1092 free(reorder_idx);
1093 free(dist_owners);
1094 free(dist_vertices);
1095
1096 } else {
1097 *proc_sphere_part = xmalloc(1 * sizeof(**proc_sphere_part));
1098 (*proc_sphere_part)->U.data.rank = 0;
1099 (*proc_sphere_part)->U.is_leaf = 1;
1100 (*proc_sphere_part)->T.data.rank = 0;
1101 (*proc_sphere_part)->T.is_leaf = 1;
1102 (*proc_sphere_part)->gc_norm_vector[0] = base_gc_norm_vector[0];
1103 (*proc_sphere_part)->gc_norm_vector[1] = base_gc_norm_vector[1];
1104 (*proc_sphere_part)->gc_norm_vector[2] = base_gc_norm_vector[2];
1105
1106 // generate global ids and vertex ranks
1107 for (int grid_idx = 0; grid_idx < 2; ++grid_idx) {
1108 *(vertex_ranks[grid_idx]) =
1109 xmalloc(num_vertices[grid_idx] * sizeof(**(vertex_ranks[grid_idx])));
1110 for (size_t i = 0; i < num_vertices[grid_idx]; ++i)
1111 (*(vertex_ranks[grid_idx]))[i] = 0;
1112 if (global_ids_missing[grid_idx]) {
1113 *(global_vertex_ids_[grid_idx]) =
1114 xmalloc(
1115 num_vertices[grid_idx] * sizeof(**(global_vertex_ids_[grid_idx])));
1116 for (size_t i = 0; i < num_vertices[grid_idx]; ++i)
1117 (*(global_vertex_ids_[grid_idx]))[i] = (yac_int)i;
1118 }
1119 }
1120 }
1121}
1122
1123static int is_serial_node(struct proc_sphere_part_node * node) {
1124 return (node->U.is_leaf) && (node->T.is_leaf) &&
1125 (node->U.data.rank == 0) && (node->T.data.rank == 0);
1126}
1127
1128// #define YAC_NEC_EXPERIMENTAL
1129#ifdef YAC_NEC_EXPERIMENTAL
1130// the following code may be better for a vector machine
1131static void yac_proc_sphere_part_do_point_search_recursive(
1132 struct proc_sphere_part_node * node, yac_coordinate_pointer search_coords,
1133 size_t * search_idx, size_t * temp_search_idx, int * flag,
1134 size_t count, int * ranks) {
1135
1136 // Determine for each search point whether it belongs to the U or T list of
1137 // the current node.
1138 for (size_t i = 0; i < count; ++i) {
1139 flag[i] =
1141 node->gc_norm_vector, search_coords[search_idx[i]]) == U_LIST;
1142 }
1143
1144 size_t u_size = 0, t_size = 0;
1145 for (size_t i = 0; i < count; ++i) {
1146 if (flag[i]) search_idx[u_size++] = search_idx[i];
1147 else temp_search_idx[t_size++] = search_idx[i];
1148 }
1149
1150 if (node->U.is_leaf) {
1151 size_t rank = node->U.data.rank;
1152 for (size_t i = 0; i < u_size; ++i) ranks[search_idx[i]] = rank;
1153 } else {
1154 yac_proc_sphere_part_do_point_search_recursive(
1155 node->U.data.node, search_coords, search_idx, temp_search_idx + t_size,
1156 flag, u_size, ranks);
1157 }
1158
1159 if (node->T.is_leaf) {
1160 size_t rank = node->T.data.rank;
1161 for (size_t i = 0; i < t_size; ++i) ranks[temp_search_idx[i]] = rank;
1162 } else {
1163 yac_proc_sphere_part_do_point_search_recursive(
1164 node->T.data.node, search_coords, temp_search_idx, search_idx + u_size,
1165 flag, t_size, ranks);
1166 }
1167}
1168#endif // YAC_NEC_EXPERIMENTAL
1169
1171 struct proc_sphere_part_node * node, yac_coordinate_pointer search_coords,
1172 size_t count, int * ranks) {
1173
1174 if (is_serial_node(node)) {
1175 for (size_t i = 0; i < count; ++i) ranks[i] = 0;
1176 return;
1177 }
1178
1179#ifdef YAC_NEC_EXPERIMENTAL
1180
1181 size_t * search_idx = xmalloc(2 * count * sizeof(*search_idx));
1182 for (size_t i = 0; i < count; ++i) search_idx[i] = i;
1183 int * flag = xmalloc(count * sizeof(*flag));
1184 yac_proc_sphere_part_do_point_search_recursive(
1185 node, search_coords, search_idx, search_idx + count, flag, count, ranks);
1186 free(flag);
1187 free(search_idx);
1188
1189#else
1190
1192 {
1194 for (size_t i = 0; i < count; ++i) {
1195
1196 double * curr_coord = search_coords[i];
1197
1198 struct proc_sphere_part_node * curr_node = node;
1199
1200 while (1) {
1201
1203 curr_node->gc_norm_vector, curr_coord) == U_LIST) {
1204 if (curr_node->U.is_leaf) {
1205 ranks[i] = curr_node->U.data.rank;
1206 break;
1207 } else {
1208 curr_node = curr_node->U.data.node;
1209 continue;
1210 }
1211 } else {
1212 if (curr_node->T.is_leaf) {
1213 ranks[i] = curr_node->T.data.rank;
1214 break;
1215 } else {
1216 curr_node = curr_node->T.data.node;
1217 continue;
1218 }
1219 }
1220 }
1221 }
1222 }
1223#endif // YAC_NEC_EXPERIMENTAL
1224}
1225
1227 struct proc_sphere_part_node * node, struct bounding_circle bnd_circle,
1228 int * ranks, int * rank_count) {
1229
1230 double dot = dotproduct_eft(bnd_circle.base_vector, node->gc_norm_vector);
1231
1232 // angle < M_PI_2 + bnd_circle.inc_angle
1233 if (dot > - bnd_circle.inc_angle.sin) {
1234
1235 if (node->T.is_leaf) {
1236
1237 ranks[*rank_count] = node->T.data.rank;
1238 ++*rank_count;
1239
1240 } else {
1241 bnd_circle_search(node->T.data.node, bnd_circle, ranks, rank_count);
1242 }
1243 }
1244
1245 // angle > M_PI_2 - bnd_circle.inc_angle
1246 if (dot < bnd_circle.inc_angle.sin) {
1247
1248 if (node->U.is_leaf) {
1249
1250 ranks[*rank_count] = node->U.data.rank;
1251 ++*rank_count;
1252
1253 } else {
1254 bnd_circle_search(node->U.data.node, bnd_circle, ranks, rank_count);
1255 }
1256 }
1257}
1258
1260 struct proc_sphere_part_node * node, struct bounding_circle bnd_circle,
1261 int * ranks, int * rank_count) {
1262
1263 if (node->T.is_leaf) {
1264
1265 ranks[*rank_count] = node->T.data.rank;
1266 ++*rank_count;
1267
1268 } else {
1270 node->T.data.node, bnd_circle, ranks, rank_count);
1271 }
1272
1273 if (node->U.is_leaf) {
1274
1275 ranks[*rank_count] = node->U.data.rank;
1276 ++*rank_count;
1277
1278 } else {
1280 node->U.data.node, bnd_circle, ranks, rank_count);
1281 }
1282}
1283
1285 struct proc_sphere_part_node * node, struct bounding_circle bnd_circle,
1286 int * ranks, int * rank_count) {
1287
1288 YAC_ASSERT(
1289 compare_angles(bnd_circle.inc_angle, SIN_COS_M_PI) == -1,
1290 "ERROR(yac_proc_sphere_part_do_bnd_circle_search): angle is >= PI")
1291
1292 // special case in which the proc_sphere_part_node only contains a single
1293 // rank
1294 if (is_serial_node(node)) {
1295 ranks[0] = 0;
1296 *rank_count = 1;
1297 } else if (bnd_circle.inc_angle.cos <= 0.0) {
1298 *rank_count = 0;
1299 bnd_circle_search_big_angle(node, bnd_circle, ranks, rank_count);
1300 } else {
1301 *rank_count = 0;
1302 bnd_circle_search(node, bnd_circle, ranks, rank_count);
1303 }
1304}
1305
1306static int get_leaf_ranks(struct proc_sphere_part_node * node, int * ranks) {
1307
1308 int curr_size;
1309
1310 if (node->U.is_leaf) {
1311 *ranks = node->U.data.rank;
1312 curr_size = 1;
1313 } else {
1314 curr_size = get_leaf_ranks(node->U.data.node, ranks);
1315 }
1316 if (node->T.is_leaf) {
1317 ranks[curr_size++] = node->T.data.rank;
1318 } else {
1319 curr_size += get_leaf_ranks(node->T.data.node, ranks + curr_size);
1320 }
1321
1322 return curr_size;
1323}
1324
1326 struct proc_sphere_part_node * node, uint64_t * leaf_sizes, uint64_t min_size,
1327 uint64_t ** inner_node_sizes, int * send_flags, int * recv_flags,
1328 int comm_rank, struct neigh_search_data * last_valid_node) {
1329
1330 int curr_node_is_valid = (**inner_node_sizes >= min_size);
1331
1332 struct neigh_search_data * curr_valid_node;
1333 struct neigh_search_data temp_valid_node;
1334
1335 int * ranks = last_valid_node->ranks;
1336
1337 if (curr_node_is_valid) {
1338 temp_valid_node.ranks = ranks;
1339 temp_valid_node.num_ranks = 0;
1340 temp_valid_node.node = node;
1341 curr_valid_node = &temp_valid_node;
1342 last_valid_node->num_ranks = 0;
1343 } else {
1344 curr_valid_node = last_valid_node;
1345 }
1346
1347 for (int j = 0; j < 2; ++j) {
1348
1349 struct proc_sphere_part_node_data node_data = (j == 0)?(node->U):(node->T);
1350
1351 if (node_data.is_leaf) {
1352
1353 int rank = node_data.data.rank;
1354
1355 if (leaf_sizes[rank] < min_size) {
1356
1357 if (curr_valid_node->num_ranks == 0)
1358 curr_valid_node->num_ranks =
1359 get_leaf_ranks(curr_valid_node->node, ranks);
1360
1361 // if the current leaf is the local process
1362 if (rank == comm_rank)
1363 for (int i = 0; i < curr_valid_node->num_ranks; ++i)
1364 recv_flags[ranks[i]] = 1;
1365
1366 // if the process of the current leaf required data from the
1367 // local process
1368 for (int i = 0; i < curr_valid_node->num_ranks; ++i) {
1369 if (ranks[i] == comm_rank) {
1370 send_flags[rank] = 1;
1371 break;
1372 }
1373 }
1374 }
1375
1376 } else {
1377 ++*inner_node_sizes;
1379 node_data.data.node, leaf_sizes, min_size, inner_node_sizes,
1380 send_flags, recv_flags, comm_rank, curr_valid_node);
1381 }
1382 }
1383}
1384
1385static uint64_t determine_node_sizes(
1386 struct proc_sphere_part_node * node, uint64_t * leaf_sizes,
1387 uint64_t ** inner_node_sizes) {
1388
1389 uint64_t * curr_inner_node_size = *inner_node_sizes;
1390 uint64_t node_size;
1391 if (node->U.is_leaf) {
1392 node_size = leaf_sizes[node->U.data.rank];
1393 } else {
1394 ++*inner_node_sizes;
1395 node_size =
1396 determine_node_sizes(node->U.data.node, leaf_sizes, inner_node_sizes);
1397 }
1398 if (node->T.is_leaf) {
1399 node_size += leaf_sizes[node->T.data.rank];
1400 } else {
1401 ++*inner_node_sizes;
1402 node_size +=
1403 determine_node_sizes(node->T.data.node, leaf_sizes, inner_node_sizes);
1404 }
1405 return (*curr_inner_node_size = node_size);
1406}
1407
1409 struct proc_sphere_part_node * node, uint64_t * leaf_sizes,
1410 uint64_t min_size, int * send_flags, int * recv_flags,
1411 int comm_rank, int comm_size) {
1412
1413 // For each node (not leaf) in the tree, determine the sum of the sizes of
1414 // the leaves in its subtree.
1415 // (number of nodes cannot exceed number of leaves/processes)
1416 uint64_t * inner_node_sizes =
1417 xcalloc((size_t)comm_size, sizeof(*inner_node_sizes));
1418 uint64_t * temp_inner_node_sizes = inner_node_sizes;
1419 determine_node_sizes(node, leaf_sizes, &temp_inner_node_sizes);
1420
1421 YAC_ASSERT(
1422 *inner_node_sizes >= min_size,
1423 "ERROR(yac_proc_sphere_part_get_neigh_ranks): sum of global leaf sizes "
1424 "is < min_size")
1425
1426 struct neigh_search_data search_data = {
1427 .ranks = xmalloc((size_t)comm_size * sizeof(int)),
1428 .num_ranks = 0,
1429 .node = node
1430 };
1431
1432 temp_inner_node_sizes = inner_node_sizes;
1433 get_neigh_ranks(node, leaf_sizes, min_size, &temp_inner_node_sizes,
1434 send_flags, recv_flags, comm_rank, &search_data);
1435
1436 send_flags[comm_rank] = 0;
1437 recv_flags[comm_rank] = 0;
1438
1439 free(search_data.ranks);
1440 free(inner_node_sizes);
1441}
1442
1444
1445 if (!(node->U.is_leaf)) yac_proc_sphere_part_node_delete(node->U.data.node);
1447 free(node);
1448}
unsigned grid_idx[3]
#define YAC_ASSERT(exp, msg)
#define ENSURE_ARRAY_SIZE(arrayp, curr_array_size, req_size)
static int compare_coords(double const *a, double const *b)
Definition geometry.h:731
static double dotproduct_eft(double const a[], double const b[])
Definition geometry.h:434
static const struct sin_cos_angle SIN_COS_M_PI
Definition geometry.h:41
static void crossproduct_kahan(double const a[], double const b[], double cross[])
Definition geometry.h:405
static int compare_angles(struct sin_cos_angle a, struct sin_cos_angle b)
Definition geometry.h:497
static void normalise_vector(double v[])
Definition geometry.h:743
void yac_proc_sphere_part_get_neigh_ranks(struct proc_sphere_part_node *node, uint64_t *leaf_sizes, uint64_t min_size, int *send_flags, int *recv_flags, int comm_rank, int comm_size)
void yac_proc_sphere_part_do_bnd_circle_search(struct proc_sphere_part_node *node, struct bounding_circle bnd_circle, int *ranks, int *rank_count)
void yac_proc_sphere_part_do_point_search(struct proc_sphere_part_node *node, yac_coordinate_pointer search_coords, size_t count, int *ranks)
void yac_proc_sphere_part_node_delete(struct proc_sphere_part_node *node)
void yac_proc_sphere_part_new(yac_coordinate_pointer vertex_coordinates[2], size_t *num_vertices, struct proc_sphere_part_node **proc_sphere_part, yac_int **global_vertex_ids_[2], int **vertex_ranks[2], MPI_Comm comm)
#define xcalloc(nmemb, size)
Definition ppm_xfuncs.h:64
#define xmalloc(size)
Definition ppm_xfuncs.h:66
static int get_leaf_ranks(struct proc_sphere_part_node *node, int *ranks)
static struct proc_sphere_part_node * generate_proc_sphere_part_node_recursive(struct dist_vertex **vertices, size_t *num_vertices, struct remote_point_info **owners, size_t *num_owners, size_t(*all_bucket_sizes)[2], struct comm_buffers comm_buffers, size_t **reorder_idx, size_t *reorder_idx_array_size, int **list_flag_, size_t *list_flag_array_size, MPI_Datatype dist_vertex_dt, MPI_Datatype remote_point_info_dt, struct yac_group_comm group_comm, double prev_gc_norm_vector[3])
static uint64_t determine_node_sizes(struct proc_sphere_part_node *node, uint64_t *leaf_sizes, uint64_t **inner_node_sizes)
static void bnd_circle_search(struct proc_sphere_part_node *node, struct bounding_circle bnd_circle, int *ranks, int *rank_count)
static void reorder_data_remote_point_info(size_t *reorder_idx, size_t count, struct remote_point_info *data)
proc_sphere_part_list_type
@ T_LIST
@ U_LIST
static void compute_redist_recvcounts_rdispls(int comm_rank, int split_rank, int comm_size, size_t global_sizes[2], size_t(*all_bucket_sizes)[2], int *counts, int *displs, size_t *recv_count)
static int is_serial_node(struct proc_sphere_part_node *node)
splicomm_tags
@ DATA_SIZE_TAG
@ DATA_TAG
static struct proc_sphere_part_node_data get_remote_data(struct proc_sphere_part_node_data local_data, struct yac_group_comm local_group_comm, struct yac_group_comm remote_group_comm)
static void get_neigh_ranks(struct proc_sphere_part_node *node, uint64_t *leaf_sizes, uint64_t min_size, uint64_t **inner_node_sizes, int *send_flags, int *recv_flags, int comm_rank, struct neigh_search_data *last_valid_node)
static MPI_Datatype yac_get_dist_vertex_mpi_datatype(MPI_Comm comm)
static void pack_proc_sphere_part_node(struct proc_sphere_part_node *node, void *pack_buffer, int pack_buffer_size, int *position, MPI_Comm comm)
static int get_proc_sphere_part_node_pack_size(struct proc_sphere_part_node node, MPI_Comm comm)
static void pack_proc_sphere_part_node_data(struct proc_sphere_part_node_data node_data, void *pack_buffer, int pack_buffer_size, int *position, MPI_Comm comm)
static void remove_duplicated_vertices(struct dist_vertex *vertices, size_t *num_vertices, struct remote_point_info *owners, size_t num_owners, size_t **owners_reorder_idx, size_t *owners_reorder_idx_array_size)
static void compute_redist_sendcounts_sdispls(int comm_rank, int split_rank, int comm_size, size_t global_sizes[2], size_t(*all_bucket_sizes)[2], int *counts, int *displs)
static void inform_dist_vertex_owners(struct dist_vertex *dist_vertices, size_t num_dist_vertices, struct remote_point_info *dist_owners, size_t **reorder_idx, size_t *reorder_idx_array_size, yac_int **global_vertex_ids[2], int *global_ids_missing, int **vertex_ranks[2], size_t *num_vertices, MPI_Comm comm)
static int get_proc_sphere_part_node_data_pack_size(struct proc_sphere_part_node_data node_data, MPI_Comm comm)
static int compare_dist_vertices(const void *a, const void *b)
static struct proc_sphere_part_node * unpack_proc_sphere_part_node(void *pack_buffer, int pack_buffer_size, int *position, MPI_Comm comm)
static struct proc_sphere_part_node_data unpack_proc_sphere_part_node_data(void *pack_buffer, int pack_buffer_size, int *position, MPI_Comm comm)
static enum proc_sphere_part_list_type determine_list_type(double const *restrict gc_norm_vector, double const *restrict vertex_coord)
static void redistribute_dist_vertices(struct dist_vertex **vertices, size_t *num_vertices, struct remote_point_info **owners, size_t *num_owners, size_t global_bucket_sizes[2], size_t(*all_bucket_sizes)[2], int split_rank, struct comm_buffers comm_buffers, size_t **owners_reorder_idx, size_t *owners_reorder_idx_array_size, MPI_Datatype dist_vertex_dt, MPI_Datatype remote_point_info_dt, struct yac_group_comm group_comm)
static void bnd_circle_search_big_angle(struct proc_sphere_part_node *node, struct bounding_circle bnd_circle, int *ranks, int *rank_count)
MPI_Datatype yac_get_remote_point_info_mpi_datatype(MPI_Comm comm)
struct sin_cos_angle inc_angle
angle between the middle point and the boundary of the spherical cap
Definition geometry.h:53
double base_vector[3]
Definition geometry.h:51
double coord[3]
struct proc_sphere_part_node * node
Data structure for the process sphere partition.
struct proc_sphere_part_node * node
int is_leaf
1 if this node is a leaf, 0 for inner nodes
union proc_sphere_part_node_data::@52 data
Inner node of the process sphere partition tree.
double gc_norm_vector[3]
Normal vector of the great circle dividing the two child nodes.
struct proc_sphere_part_node_data U T
Data of the two child nodes (U and T) of this node.
single location information of a point
double sin
Definition geometry.h:33
double cos
Definition geometry.h:33
double * data
#define MIN(a, b)
Definition toy_common.h:29
double * recv_buffer
#define YAC_OMP_PARALLEL
#define YAC_OMP_FOR
#define MAX(a, b)
void yac_alltoallv_p2p_group(void const *send_buffer, int const *sendcounts, int const *sdispls, void *recv_buffer, int const *recvcounts, int const *rdispls, size_t dt_size, MPI_Datatype dt, struct yac_group_comm group_comm)
Definition yac_mpi.c:243
int yac_group_comm_get_global_rank(struct yac_group_comm group_comm)
Definition yac_mpi.c:500
void yac_generate_alltoallv_args(int count, size_t const *sendcounts, size_t *recvcounts, size_t *sdispls, size_t *rdispls, MPI_Comm comm)
Definition yac_mpi.c:578
void yac_free_comm_buffers(size_t *sendcounts, size_t *recvcounts, size_t *sdispls, size_t *rdispls)
Definition yac_mpi.c:634
int yac_group_comm_get_rank(struct yac_group_comm group_comm)
Definition yac_mpi.c:492
void yac_group_comm_split(struct yac_group_comm group_comm, int split_rank, struct yac_group_comm *local_group_comm, struct yac_group_comm *remote_group_comm)
Definition yac_mpi.c:512
struct yac_group_comm yac_group_comm_new(MPI_Comm comm)
Definition yac_mpi.c:477
void yac_allreduce_sum_dble(double *buffer, int count, struct yac_group_comm group_comm)
Definition yac_mpi.c:296
void yac_get_comm_buffers(int count, size_t **sendcounts, size_t **recvcounts, size_t **sdispls, size_t **rdispls, MPI_Comm comm)
Definition yac_mpi.c:603
int yac_group_comm_get_size(struct yac_group_comm group_comm)
Definition yac_mpi.c:496
MPI_Datatype yac_create_resized(MPI_Datatype dt, size_t new_size, MPI_Comm comm)
Definition yac_mpi.c:557
void yac_bcast_group(void *buffer, int count, MPI_Datatype datatype, int root, struct yac_group_comm group_comm)
Definition yac_mpi.c:412
void yac_allgather_size_t(const size_t *sendbuf, size_t *recvbuf, int count, struct yac_group_comm group_comm)
Definition yac_mpi.c:368
void yac_group_comm_delete(struct yac_group_comm group_comm)
Definition yac_mpi.c:487
void yac_alltoallv_p2p(void const *send_buffer, size_t const *sendcounts, size_t const *sdispls, void *recv_buffer, size_t const *recvcounts, size_t const *rdispls, size_t dt_size, MPI_Datatype dt, MPI_Comm comm, char const *caller, int line)
Definition yac_mpi.c:132
#define yac_mpi_call(call, comm)
#define YAC_MPI_SIZE_T
YAC_INT yac_int
Definition yac_types.h:15
#define yac_int_dt
Definition yac_types.h:18
double(* yac_coordinate_pointer)[3]
Definition yac_types.h:21