YAC 3.6.2
Yet Another Coupler
Loading...
Searching...
No Matches
dist_grid.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#ifdef HAVE_CONFIG_H
6// Get the definition of the 'restrict' keyword.
7#include "config.h"
8#endif
9
10#include <stdlib.h>
11#include <string.h>
12#include <assert.h>
13#include <float.h>
14#include <yaxt.h>
15
16#include "basic_grid.h"
17#include "dist_grid_internal.h"
18#include "geometry.h"
19#include "yac_mpi_internal.h"
20#include "utils_core.h"
21#include "sphere_part.h"
22#include "proc_sphere_part.h"
23#include "ensure_array_size.h"
24#include "interp_grid.h"
25#include "field_data_set.h"
26
27#define CHECK_LOCATION(caller) \
28 YAC_ASSERT_F( \
29 (location == YAC_LOC_CELL) || \
30 (location == YAC_LOC_CORNER) || \
31 (location == YAC_LOC_EDGE), \
32 "ERROR(%s): \"%d\" is not a invalid location", \
33 caller, (int)location)
34
39
44
45// reorder_idx has to be first
52
53// reorder_idx has to be first
61
62struct id_pos {
64 uint64_t orig_pos;
65};
66
74
80
89
90// warning: when changing this, ensure that struct yac_const_basic_grid_data is
91// changed accordingly
93 yac_coordinate_pointer vertex_coordinates; // Cartesian coordinates of all edges
94 yac_int * ids[3]; // global cell/vertex/edge ids
96 size_t * cell_to_vertex; // vertices of cell i:
97 // cell_to_vertex[cell_to_vertex_offsets[i]]@num_vertices_per_cell[i]
99 size_t * cell_to_edge; // edges of cell i:
100 // cell_to_edge[cell_to_edge_offsets[i]]@num_vertices_per_cell[i]
103 struct bounding_circle * cell_bnd_circles; // bounding circle for all cells
105 struct remote_point_infos * owners[3]; // information for cells/vertices/edges about
106 // their position in the user decomposition
107 size_t total_count[3]; // current number of cells/vertices/edges in the
108 // distributed grid (can increase over time if
109 // for example a NNN search results contains
110 // data from other processes)
111 size_t count[3]; // number of cells/vertices/edges after the initial
112 // generation of the distributed grid
113 int * owner_mask[3]; // each cell/vertex/edge is owned by exactly one
114 // process in the distributed grid
115 yac_int * sorted_ids[3]; // sorted copy of "ids" arrays
116 size_t * sorted_reorder_idx[3]; // sorted_ids[i][j] = ids[i][sorted_reorder_idx[j]]
117 // with:
118 // i in [0;2]
119 // j in [0;total_count(i)[
121 MPI_Comm comm;
122};
123
132
138
140 struct {
141 size_t local_id;
144 size_t neigh_idx;
145};
146
147// looks up positions of ids in an array of sorted ids
148static void id2idx(
149 char const * caller, yac_int * ids, size_t * idx, size_t num_ids,
150 yac_int * ref_sorted_ids, size_t * ref_sorted_reorder_idx,
151 size_t num_sorted_ids) {
152
153 size_t * reorder = xmalloc(num_ids * sizeof(*reorder));
154 for (size_t i = 0; i < num_ids; ++i) reorder[i] = i;
155
156 yac_quicksort_index_yac_int_size_t(ids, num_ids, reorder);
157
158 for (size_t i = 0, j = 0; i < num_ids; ++i) {
159
160 yac_int curr_id = ids[i];
161 while ((j < num_sorted_ids) && (ref_sorted_ids[j] < curr_id)) ++j;
163 (j < num_sorted_ids) && (ref_sorted_ids[j] == curr_id),
164 "ERROR(%s): id %" XT_INT_FMT " not found", caller, curr_id)
165 idx[reorder[i]] = ref_sorted_reorder_idx[j];
166 }
167
168 free(reorder);
169}
170
171// returns the index of the cell vertex with the lowest global id
173 struct yac_dist_grid * dist_grid, size_t cell_idx) {
174
175 int num_vertices = dist_grid->num_vertices_per_cell[cell_idx];
176 if (num_vertices == 0) return SIZE_MAX;
177 yac_int * grid_vertex_ids = dist_grid->ids[YAC_LOC_CORNER];
178 size_t * vertices =
179 dist_grid->cell_to_vertex + dist_grid->cell_to_vertex_offsets[cell_idx];
180 // get the cell corner with the smallest global id
181 size_t min_idx = vertices[0];
182 yac_int min_global_id = grid_vertex_ids[min_idx];
183 for (int j = 1; j < num_vertices; ++j) {
184 size_t curr_vertex = vertices[j];
185 yac_int curr_global_id = grid_vertex_ids[curr_vertex];
186 if (min_global_id > curr_global_id) {
187 min_global_id = curr_global_id;
188 min_idx = curr_vertex;
189 }
190 }
191 return min_idx;
192}
193
194// generate cell owner mask (true for all cells belonging to the local part of
195// the distributed directory)
197 struct yac_dist_grid * dist_grid, int is_root, int * vertex_owner_mask) {
198
199 size_t num_cells = dist_grid->count[YAC_LOC_CELL];
200 int * cell_owner_mask = xmalloc(num_cells * sizeof(*cell_owner_mask));
201
202 //--------------------------
203 // determine cell owner mask
204 //--------------------------
205 for (size_t i = 0; i < num_cells; ++i) {
206 size_t ref_vertex = get_cell_reference_vertex(dist_grid, i);
207 cell_owner_mask[i] =
208 (ref_vertex != SIZE_MAX)?(vertex_owner_mask[ref_vertex]):is_root;
209 }
210
211 return cell_owner_mask;
212}
213
214// returns the index of the edge vertex with the lowest global id
215static inline size_t get_edge_reference_vertex(
216 struct yac_dist_grid * dist_grid, size_t edge_idx) {
217
218 yac_int * vertex_ids = dist_grid->ids[YAC_LOC_CORNER];
219 size_t * edge_vertices = &(dist_grid->edge_to_vertex[edge_idx][0]);
220 // get the edge corner with the smallest global id
221 return edge_vertices[
222 (vertex_ids[edge_vertices[0]] > vertex_ids[edge_vertices[1]])?1:0];
223}
224
225// generate edge owner mask
226// (each edge is owned by exactly one process in the distributed
227// directory, but may be located on more than one)
229 struct yac_dist_grid * dist_grid, int * vertex_owner_mask) {
230
231 size_t num_edges = dist_grid->count[YAC_LOC_EDGE];
232 int * edge_owner_mask = xmalloc(num_edges * sizeof(*edge_owner_mask));
233
234 //-------------------------
235 // determine edge owner mask
236 //-------------------------
237 for (size_t i = 0; i < num_edges; ++i)
238 edge_owner_mask[i] =
239 vertex_owner_mask[get_edge_reference_vertex(dist_grid, i)];
240
241 return edge_owner_mask;
242}
243
244// mask sure that each cell/vertex/edge is owned by only one process of
245// the distributed directory
247 struct yac_dist_grid * dist_grid, int comm_rank, int * vertex_owner) {
248
249 // determine distributed owner for vertices in the local part of the
250 // distributed grid
251 int * vertex_owner_mask =
252 (dist_grid->owner_mask[YAC_LOC_CORNER] = vertex_owner);
253 for (size_t i = 0; i < dist_grid->count[YAC_LOC_CORNER]; ++i)
254 vertex_owner_mask[i] = vertex_owner_mask[i] == comm_rank;
255
256 // generate owner mask for cells based on the vertex owner mask
257 dist_grid->owner_mask[YAC_LOC_CELL] =
258 determine_cell_owner_mask(dist_grid, comm_rank == 0, vertex_owner_mask);
259
260 // generate owner mask for edges based on the vertex owner mask
261 dist_grid->owner_mask[YAC_LOC_EDGE] =
262 determine_edge_owner_mask(dist_grid, vertex_owner_mask);
263}
264
265static MPI_Datatype yac_get_id_pos_mpi_datatype(MPI_Comm comm) {
266
267 struct id_pos dummy;
268 MPI_Datatype id_pos_dt;
269 int array_of_blocklengths[] = {1,1};
270 const MPI_Aint array_of_displacements[] =
271 {(MPI_Aint)(intptr_t)(const void *)&(dummy.global_id) -
272 (MPI_Aint)(intptr_t)(const void *)&dummy,
273 (MPI_Aint)(intptr_t)(const void *)&(dummy.orig_pos) -
274 (MPI_Aint)(intptr_t)(const void *)&dummy};
275 const MPI_Datatype array_of_types[] = {yac_int_dt, MPI_UINT64_T};
277 MPI_Type_create_struct(
278 2, array_of_blocklengths, array_of_displacements,
279 array_of_types, &id_pos_dt), comm);
280 return yac_create_resized(id_pos_dt, sizeof(dummy), comm);
281}
282
283// inserts an element into an array and increases the corresponding size
284static void insert_global_id(yac_int * ids, size_t n, yac_int id) {
285
286 size_t i;
287 for (i = 0; i < n; ++i) if (ids[i] >= id) break;
288 // copy new id into array and move bigger elements one position up
289 if (n != i) memmove(ids + i + 1, ids + i, (n - i) * sizeof(*ids));
290 ids[i] = id;
291}
292
293// inserts an element into an array and increases the corresponding size
294// if the element already exists in the array nothing is done
295static void insert_rank(int * ranks, int * count, int rank) {
296
297 int i;
298 int n = *count;
299
300 for (i = 0; i < n; ++i) if (ranks[i] >= rank) break;
301
302 // if the rank is already in the array
303 if (i != n) {
304 if (ranks[i] == rank) return;
305 else memmove(ranks + i + 1, ranks + i, ((size_t)(n - i)) * sizeof(*ranks));
306 }
307 ranks[i] = rank;
308 *count = n + 1;
309}
310
312 const void * a, const void * b) {
313
314 int count_a = ((struct n_ids_reorder const *)a)->count;
315 int count_b = ((struct n_ids_reorder const *)b)->count;
316 yac_int * a_ids = ((struct n_ids_reorder const *)a)->ids;
317 yac_int * b_ids = ((struct n_ids_reorder const *)b)->ids;
318 int ret = count_a - count_b;
319 for (int i = 0; !ret && (i < count_a); ++i)
320 ret = (a_ids[i] > b_ids[i]) - (a_ids[i] < b_ids[i]);
321 return ret;
322}
323
325 const void * a, const void * b) {
326
327 return (((struct n_ids_reorder const *)a)->reorder_idx >
328 ((struct n_ids_reorder const *)b)->reorder_idx) -
329 (((struct n_ids_reorder const *)a)->reorder_idx <
330 ((struct n_ids_reorder const *)b)->reorder_idx);
331}
332
333// determines for all cells, in the grid data provided by the user, to
334// which processes they belong according to the decomposition of the
335// distributed grid
337 struct proc_sphere_part_node * proc_sphere_part,
338 struct yac_basic_grid_data * grid_data, MPI_Comm comm, int ** dist_cell_ranks,
339 int * dist_cell_rank_counts, size_t * dist_cell_rank_offsets,
340 int max_num_vertices_per_cell) {
341
342 int comm_size;
343 yac_mpi_call(MPI_Comm_size(comm, &comm_size), comm);
344
345 size_t num_cells = grid_data->num_cells;
346 int * ranks_buffer = xmalloc((size_t)comm_size * sizeof(*ranks_buffer));
347 size_t dist_cell_ranks_array_size = num_cells;
348 int * dist_cell_ranks_ = xmalloc(num_cells * sizeof(*dist_cell_ranks_));
349 size_t offset = 0;
350
351 int * core_cell_mask = grid_data->core_cell_mask;
352
353 // set up a cell buffer required to compute the bounding circle of a cell
354 struct yac_grid_cell cell;
355 cell.coordinates_xyz =
356 xmalloc(
357 (size_t)max_num_vertices_per_cell * sizeof(*(cell.coordinates_xyz)));
358 cell.edge_type =
359 xmalloc((size_t)max_num_vertices_per_cell * sizeof(*(cell.edge_type)));
360
361 size_t * cell_to_vertex = grid_data->cell_to_vertex;
362 size_t * cell_to_vertex_offsets = grid_data->cell_to_vertex_offsets;
363 size_t * cell_to_edge = grid_data->cell_to_edge;
364 size_t * cell_to_edge_offsets = grid_data->cell_to_edge_offsets;
365 yac_coordinate_pointer vertex_coordinates = grid_data->vertex_coordinates;
366 enum yac_edge_type * edge_type = grid_data->edge_type;
367 int * num_vertices_per_cell = grid_data->num_vertices_per_cell;
368
369 // generate a bounding circle for each cell and use it to determine
370 // ranks of the processes that require this cell
371 for (size_t i = 0; i < num_cells; ++i) {
372
373 int rank_count;
374
375 // we only have to consider valid cells
376 if ((core_cell_mask == NULL) || core_cell_mask[i]) {
377
378 cell.num_corners = num_vertices_per_cell[i];
379
380 // if the cell actually has corners
381 if (cell.num_corners > 0) {
382
383 // extract single cell from the grid_data data
384 size_t * curr_cell_to_vertex =
385 cell_to_vertex + cell_to_vertex_offsets[i];
386 size_t * curr_cell_to_edge =
387 cell_to_edge + cell_to_edge_offsets[i];
388 for (int j = 0; j < num_vertices_per_cell[i]; ++j) {
389 yac_coordinate_pointer curr_vertex_coords =
390 vertex_coordinates + curr_cell_to_vertex[j];
391 for (int k = 0; k < 3; ++k)
392 cell.coordinates_xyz[j][k] = (*curr_vertex_coords)[k];
393 cell.edge_type[j] = edge_type[curr_cell_to_edge[j]];
394 }
395
396 // generate bounding circle for the current cell
397 struct bounding_circle bnd_circle;
398 yac_get_cell_bounding_circle(cell, &bnd_circle);
399
400 // determine all processes whose part of the YAC internal
401 // decomposition overlaps with the bounding circle of the
402 // current cell
404 proc_sphere_part, bnd_circle, ranks_buffer, &rank_count);
405
406 } else { // cells without corners are all assigned to process 0
407
408 ranks_buffer[0] = 0;
409 rank_count = 1;
410 }
411
412 } else { // invalid cells are not distributed
413 rank_count = 0;
414 }
415
416 ENSURE_ARRAY_SIZE(dist_cell_ranks_, dist_cell_ranks_array_size,
417 offset + (size_t)rank_count);
418 memcpy(dist_cell_ranks_ + offset, ranks_buffer,
419 (size_t)rank_count * sizeof(*ranks_buffer));
420
421 dist_cell_rank_counts[i] = rank_count;
422 dist_cell_rank_offsets[i] = offset;
423 offset += (size_t)rank_count;
424 }
425
426 // the (n+1)'th entry contains the total number ranks (SUM(dist_cell_rank_counts))
427 dist_cell_rank_offsets[num_cells] = offset;
428
429 free(cell.edge_type);
430 free(cell.coordinates_xyz);
431 free(ranks_buffer);
432
433 *dist_cell_ranks = dist_cell_ranks_;
434}
435
436static MPI_Datatype yac_get_id_reorder_coord_coord_mpi_datatype(MPI_Comm comm) {
437
438 struct id_reorder_coord dummy;
439 MPI_Datatype coord_dt;
440 int array_of_blocklengths[] = {3};
441 const MPI_Aint array_of_displacements[] =
442 {(MPI_Aint)(intptr_t)(const void *)&(dummy.coord) -
443 (MPI_Aint)(intptr_t)(const void *)&dummy};
444 const MPI_Datatype array_of_types[] = {MPI_DOUBLE};
446 MPI_Type_create_struct(1, array_of_blocklengths, array_of_displacements,
447 array_of_types, &coord_dt), comm);
448 return yac_create_resized(coord_dt, sizeof(dummy), comm);
449}
450
451static MPI_Datatype yac_get_id_reorder_coord_id_mpi_datatype(MPI_Comm comm) {
452
453 struct id_reorder_coord dummy;
454 MPI_Datatype global_id_dt;
455 int array_of_blocklengths[] = {1};
456 const MPI_Aint array_of_displacements[] =
457 {(MPI_Aint)(intptr_t)(const void *)&(dummy.global_id) -
458 (MPI_Aint)(intptr_t)(const void *)&dummy};
459 const MPI_Datatype array_of_types[] = {yac_int_dt};
461 MPI_Type_create_struct(1, array_of_blocklengths, array_of_displacements,
462 array_of_types, &global_id_dt), comm);
463 return yac_create_resized(global_id_dt, sizeof(dummy), comm);
464}
465
467 const void * a, const void * b) {
468
469 return compare_coords(((const struct id_reorder_coord *)a)->coord,
470 ((const struct id_reorder_coord *)b)->coord);
471}
472
474 const void * a, const void * b) {
475
476 return (((const struct id_reorder_coord *)a)->reorder_idx >
477 ((const struct id_reorder_coord *)b)->reorder_idx) -
478 (((const struct id_reorder_coord *)a)->reorder_idx <
479 ((const struct id_reorder_coord *)b)->reorder_idx);
480}
481
482// generates global vertex ids (if they are not provied by the user)
483// and returns the distributed owners for each vertex in the provided
484// grid data
486 struct proc_sphere_part_node * proc_sphere_part,
487 struct yac_basic_grid_data * grid, MPI_Comm comm) {
488
489 char const * routine = "generate_vertex_ids";
490
491 int * vertex_ranks = xmalloc(grid->num_vertices * sizeof(*vertex_ranks));
492
493 // determine the dist grid ranks for all vertices
495 proc_sphere_part, grid->vertex_coordinates, grid->num_vertices,
496 vertex_ranks);
497
498 // check whether only of subset of the processes have defined
499 // their global ids, which is not supported
500 int ids_available_local =
501 (grid->num_vertices > 0) && (grid->vertex_ids != NULL);
502 int ids_available_global;
503 yac_mpi_call(MPI_Allreduce(
504 &ids_available_local, &ids_available_global, 1,
505 MPI_INT, MPI_MAX, comm), comm);
506
507 // if there are vertices defined locally for the current grid
508 if (grid->num_vertices != 0) {
510 ids_available_local || !ids_available_global,
511 "ERROR(%s): inconsistent global ids", routine)
512 }
513
514 // if we do not need to generate the global ids
515 if (ids_available_global) return vertex_ranks;
516
517 int comm_size;
518 yac_mpi_call(MPI_Comm_size(comm, &comm_size), comm);
519
520 size_t * sendcounts, * recvcounts, * sdispls, * rdispls;
522 1, &sendcounts, &recvcounts, &sdispls, &rdispls, comm);
523
524 for (size_t i = 0; i < grid->num_vertices; ++i)
525 sendcounts[vertex_ranks[i]]++;
526
528 1, sendcounts, recvcounts, sdispls, rdispls, comm);
529
530 size_t orig_vertex_count = grid->num_vertices;
531 size_t dist_vertex_count =
532 recvcounts[comm_size - 1] + rdispls[comm_size - 1];
533
534 struct id_reorder_coord * id_reorder_coord_buffer =
535 xmalloc((orig_vertex_count + dist_vertex_count) *
536 sizeof(*id_reorder_coord_buffer));
537 struct id_reorder_coord *
538 id_reorder_coord_send_buffer = id_reorder_coord_buffer;
539 struct id_reorder_coord *
540 id_reorder_coord_recv_buffer =
541 id_reorder_coord_buffer + orig_vertex_count;
542
543 // pack send buffer
544 for (size_t i = 0; i < orig_vertex_count; ++i) {
545 size_t pos = sdispls[vertex_ranks[i] + 1]++;
546 id_reorder_coord_send_buffer[pos].reorder_idx = i;
547 for (int j = 0; j < 3; ++j)
548 id_reorder_coord_send_buffer[pos].coord[j] =
549 grid->vertex_coordinates[i][j];
550 }
551
552 MPI_Datatype id_reorder_coord_coord_dt =
554
555 // exchange data
557 id_reorder_coord_send_buffer, sendcounts, sdispls,
558 id_reorder_coord_recv_buffer, recvcounts, rdispls,
559 sizeof(*id_reorder_coord_send_buffer), id_reorder_coord_coord_dt, comm,
560 routine, __LINE__);
561
562 yac_mpi_call(MPI_Type_free(&id_reorder_coord_coord_dt), comm);
563
564 for (size_t i = 0; i < dist_vertex_count; ++i)
565 id_reorder_coord_recv_buffer[i].reorder_idx = i;
566
567 // sort received vertices based on coordinates
568 qsort(
569 id_reorder_coord_recv_buffer, dist_vertex_count,
570 sizeof(*id_reorder_coord_recv_buffer), compare_id_reorder_coord_coord);
571
572 size_t unique_count = dist_vertex_count > 0;
573 struct id_reorder_coord * prev = id_reorder_coord_recv_buffer;
574
575 // determine number of unique coordinates
576 for (size_t i = 0; i < dist_vertex_count; ++i) {
577 struct id_reorder_coord * curr = id_reorder_coord_recv_buffer + i;
578 if (compare_id_reorder_coord_coord(prev, curr)) {
579 ++unique_count;
580 prev = curr;
581 }
582 curr->global_id = (yac_int)unique_count - 1;
583 }
584
586 unique_count <= (size_t)XT_INT_MAX,
587 "ERROR(%s): global_id out of bounds", routine)
588
589 yac_int yac_int_unique_count = (yac_int)unique_count;
590 yac_int id_offset;
591
592 // determine exclusive scan of sum of numbers of unique
593 // coordinates on all ranks
594 yac_mpi_call(MPI_Exscan(&yac_int_unique_count, &id_offset, 1, yac_int_dt,
595 MPI_SUM, comm), comm);
596 int comm_rank;
597 yac_mpi_call(MPI_Comm_rank(comm, &comm_rank), comm);
598 if (comm_rank == 0) id_offset = 0;
599
601 ((size_t)id_offset + unique_count) <= (size_t)XT_INT_MAX,
602 "ERROR(%s): global_id out of bounds", routine)
603
604 // adjust global ids
605 for (size_t i = 0; i < dist_vertex_count; ++i)
606 id_reorder_coord_recv_buffer[i].global_id += id_offset;
607
608 // return received vertices into original order
609 qsort(id_reorder_coord_recv_buffer, dist_vertex_count,
610 sizeof(*id_reorder_coord_recv_buffer),
612
613 MPI_Datatype id_reorder_coord_id_dt =
615
616 // return generated global ids data
618 id_reorder_coord_recv_buffer, recvcounts, rdispls,
619 id_reorder_coord_send_buffer, sendcounts, sdispls,
620 sizeof(*id_reorder_coord_send_buffer), id_reorder_coord_id_dt, comm,
621 routine, __LINE__);
622
623 yac_mpi_call(MPI_Type_free(&id_reorder_coord_id_dt), comm);
624
625 yac_int * vertex_ids =
626 ((grid->vertex_ids =
627 (grid->num_vertices > 0)?
628 xmalloc(grid->num_vertices * sizeof(*(grid->vertex_ids))):NULL));
629
630 for (size_t i = 0; i < grid->num_vertices; ++i)
631 vertex_ids[id_reorder_coord_send_buffer[i].reorder_idx] =
632 id_reorder_coord_send_buffer[i].global_id;
633
634 free(id_reorder_coord_buffer);
635 yac_free_comm_buffers(sendcounts, recvcounts, sdispls, rdispls);
636
637 return vertex_ranks;
638}
639
640// generate global ids for all cells and edges (if non-existent)
641static void generate_ce_ids(
642 struct yac_basic_grid * grid, int * vertex_ranks,
643 int max_num_vertices_per_cell, MPI_Comm comm) {
644
645 char const * routine = "generate_ce_ids";
646
647 struct yac_basic_grid_data * grid_data = yac_basic_grid_get_data(grid);
648
649 size_t num_cells = grid_data->num_cells;
650 size_t num_edges = grid_data->num_edges;
651
652 yac_int * vertex_ids = grid_data->vertex_ids;
653
654 int comm_rank, comm_size;
655 yac_mpi_call(MPI_Comm_rank(comm, &comm_rank), comm);
656 yac_mpi_call(MPI_Comm_size(comm, &comm_size), comm);
657
658 // check whether only a subset of the processes have defined
659 // their global ids, which is not supported
660 int ids_available_local[2], ids_available_global[2];
661 ids_available_local[0] =
662 (num_cells > 0) && (grid_data->cell_ids != NULL);
663 ids_available_local[1] =
664 (num_edges > 0) && (grid_data->edge_ids != NULL);
665 yac_mpi_call(MPI_Allreduce(ids_available_local, ids_available_global, 2,
666 MPI_INT, MPI_MAX, comm), comm);
667
669 (num_cells == 0) ||
670 (ids_available_local[0] == ids_available_global[0]),
671 "ERROR(%s): inconsistent global ids", routine)
672
674 (num_edges == 0) ||
675 (ids_available_local[1] == ids_available_global[1]),
676 "ERROR(%s): inconsistent global ids", routine)
677
678 // if no ids have to be generated
679 if (ids_available_global[0] && ids_available_global[1]) return;
680
681 int * rank_buffer =
682 xmalloc(
683 (((ids_available_global[0])?0:(num_cells)) +
684 ((ids_available_global[1])?0:(num_edges))) *
685 sizeof(*rank_buffer));
686 int * cell_ranks = rank_buffer;
687 int * edge_ranks =
688 rank_buffer + ((ids_available_global[0])?0:(num_cells));
689
690 size_t * size_t_buffer =
691 xmalloc((8 * (size_t)comm_size + 1) * sizeof(*size_t_buffer));
692 size_t * sendcounts = size_t_buffer + 0 * comm_size;
693 size_t * recvcounts = size_t_buffer + 2 * comm_size;
694 size_t * total_sendcounts = size_t_buffer + 4 * comm_size;
695 size_t * total_recvcounts = size_t_buffer + 5 * comm_size;
696 size_t * total_sdispls = size_t_buffer + 6 * comm_size;
697 size_t * total_rdispls = size_t_buffer + 7 * comm_size + 1;
698 memset(sendcounts, 0, 2 * (size_t)comm_size * sizeof(*sendcounts));
699
700 yac_int * cell_to_vertex_ids = NULL;
701
702 if (!ids_available_global[0]) {
703
705 size_t * cell_to_vertex = grid_data->cell_to_vertex;
707
708 cell_to_vertex_ids =
709 xmalloc(num_cells * max_num_vertices_per_cell *
710 sizeof(*cell_to_vertex_ids));
711
712 for (size_t i = 0; i < num_cells; ++i) {
713
714 int curr_num_vertices = num_vertices_per_cell[i];
715 yac_int * curr_cell_to_vertex_ids =
716 cell_to_vertex_ids + i * max_num_vertices_per_cell;
717
718 int cell_rank;
719 if (curr_num_vertices > 0) {
720 size_t * curr_cell_vertices =
722 size_t min_vertex = curr_cell_vertices[0];
723 curr_cell_to_vertex_ids[0] = vertex_ids[min_vertex];
724 for (int j = 1; j < curr_num_vertices; ++j) {
725 size_t curr_vertex_idx = curr_cell_vertices[j];
726 yac_int curr_vertex_id = vertex_ids[curr_vertex_idx];
727 insert_global_id(curr_cell_to_vertex_ids, j, curr_vertex_id);
728 if (curr_cell_to_vertex_ids[0] == curr_vertex_id)
729 min_vertex = curr_vertex_idx;
730 }
731 cell_rank = vertex_ranks[min_vertex];
732 } else {
733 cell_rank = 0;
734 }
735 for (int j = curr_num_vertices; j < max_num_vertices_per_cell; ++j)
736 curr_cell_to_vertex_ids[j] = XT_INT_MAX;
737
738 sendcounts[2 * ((cell_ranks[i] = cell_rank)) + 0]++;
739 }
740 }
741
742 yac_int * edge_to_vertex_ids = NULL;
743
744 if (!ids_available_global[1]) {
745
746 edge_to_vertex_ids =
747 xmalloc(2 * num_edges * sizeof(*edge_to_vertex_ids));
749
750 for (size_t i = 0; i < num_edges; ++i) {
751
752 size_t * curr_edge_to_vertex = edge_to_vertex[i];
753 yac_int * curr_edge_vertex_ids = edge_to_vertex_ids + 2 * i;
754 curr_edge_vertex_ids[0] = vertex_ids[curr_edge_to_vertex[0]];
755 curr_edge_vertex_ids[1] = vertex_ids[curr_edge_to_vertex[1]];
756
757 if (curr_edge_vertex_ids[0] > curr_edge_vertex_ids[1]) {
758 yac_int temp = curr_edge_vertex_ids[0];
759 curr_edge_vertex_ids[0] = curr_edge_vertex_ids[1];
760 curr_edge_vertex_ids[1] = temp;
761 sendcounts[
762 2 * ((edge_ranks[i] = vertex_ranks[curr_edge_to_vertex[1]])) + 1]++;
763 } else {
764 sendcounts[
765 2 * ((edge_ranks[i] = vertex_ranks[curr_edge_to_vertex[0]])) + 1]++;
766 }
767 }
768 }
769
770 // exchange the number of cells and edges
771 yac_mpi_call(MPI_Alltoall(sendcounts, 2, YAC_MPI_SIZE_T,
772 recvcounts, 2, YAC_MPI_SIZE_T, comm), comm);
773
774 total_sdispls[0] = 0;
775 size_t recv_counts[2] = {0,0};
776 size_t saccu = 0, raccu = 0;
777 for (int i = 0; i < comm_size; ++i) {
778 total_sdispls[i+1] = saccu;
779 total_rdispls[i] = raccu;
780 recv_counts[0] += recvcounts[2 * i + 0];
781 recv_counts[1] += recvcounts[2 * i + 1];
782 total_sendcounts[i] = sendcounts[2 * i + 0] *
783 (size_t)max_num_vertices_per_cell +
784 sendcounts[2 * i + 1] * 2;
785 total_recvcounts[i] = recvcounts[2 * i + 0] *
786 (size_t)max_num_vertices_per_cell +
787 recvcounts[2 * i + 1] * 2;
788 saccu += total_sendcounts[i];
789 raccu += total_recvcounts[i];
790 }
791 size_t local_data_count = total_sendcounts[comm_size - 1] +
792 total_sdispls[comm_size];
793 size_t recv_count = total_recvcounts[comm_size - 1] +
794 total_rdispls[comm_size - 1];
795
796 yac_int * yac_int_buffer =
797 xcalloc((local_data_count + recv_count), sizeof(*yac_int_buffer));
798 yac_int * send_buffer = yac_int_buffer;
799 yac_int * recv_buffer = yac_int_buffer + local_data_count;
800
801 // pack send buffer
802 if (!ids_available_global[0])
803 for (size_t i = 0; i < num_cells; ++i)
804 for (int j = 0; j < max_num_vertices_per_cell; ++j)
805 send_buffer[total_sdispls[cell_ranks[i] + 1]++] =
806 cell_to_vertex_ids[i * max_num_vertices_per_cell + j];
807 if (!ids_available_global[1])
808 for (size_t i = 0; i < num_edges; ++i)
809 for (int j = 0; j < 2; ++j)
810 send_buffer[total_sdispls[edge_ranks[i] + 1]++] =
811 edge_to_vertex_ids[2 * i + j];
812
813 free(edge_to_vertex_ids);
814 free(cell_to_vertex_ids);
815
816 // exchange data
817 yac_alltoallv_yac_int_p2p(
818 send_buffer, total_sendcounts, total_sdispls,
819 recv_buffer, total_recvcounts, total_rdispls, comm, routine, __LINE__);
820
821 struct n_ids_reorder * n_ids_reorder_buffer =
822 xmalloc((recv_counts[0] + recv_counts[1]) * sizeof(*n_ids_reorder_buffer));
823 struct n_ids_reorder * n_ids_reorder[2] =
824 {n_ids_reorder_buffer, n_ids_reorder_buffer + recv_counts[0]};
825
826 size_t offset = 0;
827 int index_counts[2] = {max_num_vertices_per_cell, 2};
828 size_t reorder_idx = 0;
829 recv_counts[0] = 0;
830 recv_counts[1] = 0;
831 for (int i = 0; i < comm_size; ++i) {
832 for (int j = 0; j < 2; ++j) {
833 size_t curr_count = recvcounts[2 * i + j];
834 for (size_t k = 0; k < curr_count;
835 ++k, ++reorder_idx, ++recv_counts[j]) {
836 n_ids_reorder[j][recv_counts[j]].count = index_counts[j];
837 n_ids_reorder[j][recv_counts[j]].ids = recv_buffer + offset;
838 n_ids_reorder[j][recv_counts[j]].reorder_idx = reorder_idx;
839 offset += index_counts[j];
840 }
841 }
842 }
843
844 for (int i = 0; i < 2; ++i) {
845
846 if (ids_available_global[i]) continue;
847
848 qsort(n_ids_reorder[i], recv_counts[i], sizeof(*(n_ids_reorder[i])),
850
851 size_t unique_count = recv_counts[i] > 0;
852 struct n_ids_reorder * prev = n_ids_reorder[i];
853 struct n_ids_reorder * curr = n_ids_reorder[i];
854
855 for (size_t j = 0; j < recv_counts[i]; ++j, ++curr) {
856 if (compare_n_ids_reorder_ids(prev, curr)) {
857 ++unique_count;
858 prev = curr;
859 }
860 curr->global_id = (yac_int)(unique_count - 1);
861 }
862
864 unique_count <= (size_t)XT_INT_MAX,
865 "ERROR(%s): global_id out of bounds", routine)
866
867 yac_int yac_int_unique_count = (yac_int)unique_count;
868 yac_int id_offset;
869
870 // determine exclusive scan of sum of numbers of unique ids on all ranks
871 yac_mpi_call(MPI_Exscan(&yac_int_unique_count, &id_offset, 1, yac_int_dt,
872 MPI_SUM, comm), comm);
873 if (comm_rank == 0) id_offset = 0;
874
876 ((size_t)id_offset + unique_count) <= (size_t)XT_INT_MAX,
877 "ERROR(%s): global_id out of bounds", routine)
878
879 // adjust global ids
880 for (size_t j = 0; j < recv_counts[i]; ++j)
881 n_ids_reorder[i][j].global_id += id_offset;
882 }
883 free(yac_int_buffer);
884
885 qsort(n_ids_reorder_buffer, recv_counts[0] + recv_counts[1],
886 sizeof(*n_ids_reorder_buffer), compare_n_ids_reorder_reorder);
887
888 yac_int * global_ids_buffer =
889 xmalloc((recv_counts[0] + recv_counts[1] +
890 ((ids_available_global[0])?0:(num_cells)) +
891 ((ids_available_global[1])?0:(num_edges))) *
892 sizeof(*global_ids_buffer));
893 yac_int * send_global_ids = global_ids_buffer;
894 yac_int * recv_global_ids =
895 global_ids_buffer + recv_counts[0] + recv_counts[1];
896
897 for (size_t i = 0; i < recv_counts[0] + recv_counts[1]; ++i)
898 send_global_ids[i] = n_ids_reorder_buffer[i].global_id;
899 free(n_ids_reorder_buffer);
900
901 // generate count and displs data
902 saccu = 0, raccu = 0;
903 for (int i = 0; i < comm_size; ++i) {
904 total_sdispls[i] = saccu;
905 total_rdispls[i] = raccu;
906 saccu +=
907 ((total_sendcounts[i] = recvcounts[2 * i + 0] + recvcounts[2 * i + 1]));
908 raccu +=
909 ((total_recvcounts[i] = sendcounts[2 * i + 0] + sendcounts[2 * i + 1]));
910 }
911
912 // exchange generated global ids data
913 yac_alltoallv_yac_int_p2p(
914 send_global_ids, total_sendcounts, total_sdispls,
915 recv_global_ids, total_recvcounts, total_rdispls, comm,
916 routine, __LINE__);
917
918 if ((!ids_available_global[0]) && (num_cells > 0))
919 grid_data->cell_ids =
920 xmalloc(num_cells * sizeof(*grid_data->cell_ids));
921 if ((!ids_available_global[1]) && (num_edges > 0))
922 grid_data->edge_ids =
923 xmalloc(num_edges * sizeof(grid_data->edge_ids));
924
925 // unpack generated global ids
926 if (!ids_available_global[0])
927 for (size_t i = 0; i < num_cells; ++i)
928 grid_data->cell_ids[i] =
929 recv_global_ids[total_rdispls[cell_ranks[i]]++];
930 if (!ids_available_global[1])
931 for (size_t i = 0; i < num_edges; ++i)
932 grid_data->edge_ids[i] =
933 recv_global_ids[total_rdispls[edge_ranks[i]]++];
934
935 free(rank_buffer);
936 free(size_t_buffer);
937 free(global_ids_buffer);
938}
939
940// check core masks for consistency
941// (contains no valid cell/edge connected to an invalid edge/vertex)
942// and generate it if required
943static void check_core_masks(struct yac_basic_grid * grid) {
944
945 struct yac_basic_grid_data * grid_data = yac_basic_grid_get_data(grid);
946
947 int * core_vertex_mask = grid_data->core_vertex_mask;
948 int * core_edge_mask = grid_data->core_edge_mask;
949 int * core_cell_mask = grid_data->core_cell_mask;
950
951 size_t num_edges = grid_data->num_edges;
952 size_t num_cells = grid_data->num_cells;
953
954 //---------------------------------------------------------------
955 // the core mask for vertices is optional and does not have to be
956 // generated if it is missing
957 //---------------------------------------------------------------
958
959 //---------------------------------------------------------------
960 // a core mask for vertices is required if the grid contains
961 // edges and a core mask for vertices
962 //---------------------------------------------------------------
963
964 if (core_vertex_mask && (num_edges > 0)) {
965
967
968 // if the grid already contains a core mask for edges -->
969 // check consistency of the mask
970 // (no valid edge can be connected to a masked out vertex)
971 if (core_edge_mask) {
972
973 for (size_t j = 0; j < num_edges; ++j) {
974
975 size_t * curr_vertices = edge_to_vertex[j];
976
978 (!core_edge_mask[j]) ||
979 (core_vertex_mask[curr_vertices[0]] &&
980 core_vertex_mask[curr_vertices[1]]),
981 "ERROR: inconsistent edge core mask for grid \"%s\" "
982 "(edge %" XT_INT_FMT " is valid but one of its vertices is not)",
984 grid_data->edge_ids?grid_data->edge_ids[j]:XT_INT_MAX);
985 }
986
987 } else { // if there is no core mask for edges --> generate one
988
990 (grid_data->core_edge_mask =
991 xmalloc(num_edges * sizeof(*core_edge_mask)));
992 for (size_t j = 0; j < num_edges; ++j) {
993 size_t * curr_vertices = edge_to_vertex[j];
994 core_edge_mask[j] =
995 core_vertex_mask[curr_vertices[0]] &
996 core_vertex_mask[curr_vertices[1]];
997 }
998 }
999 }
1000
1001 //---------------------------------------------------------------
1002 // a core mask for cells is required if the grid contains
1003 // cells and a core mask for edges
1004 //---------------------------------------------------------------
1005
1006 if (core_edge_mask && (num_cells > 0)) {
1007
1008 size_t * cell_to_edge = grid_data->cell_to_edge;
1009 size_t * cell_to_edge_offsets = grid_data->cell_to_edge_offsets;
1011
1012 // if there is a core mask for cells -->
1013 // check consistency of the mask
1014 // (no valid cell can be connected to a masked out edge)
1015 if (core_cell_mask) {
1016
1017 for (size_t j = 0; j < num_cells; ++j) {
1018
1019 if (!core_cell_mask[j]) continue;
1020
1021 size_t * curr_edges = cell_to_edge + cell_to_edge_offsets[j];
1022 int curr_num_edges = num_vertices_per_cell[j];
1023
1024 for (int k = 0; k < curr_num_edges; ++k) {
1026 core_edge_mask[curr_edges[k]],
1027 "ERROR: inconsistent cell core mask for grid \"%s\" "
1028 "(cell %" XT_INT_FMT " is valid but edge %" XT_INT_FMT " is not)",
1030 grid_data->cell_ids?grid_data->cell_ids[j]:XT_INT_MAX,
1031 grid_data->edge_ids?grid_data->edge_ids[curr_edges[k]]:XT_INT_MAX);
1032 }
1033 }
1034 } else { // if there is no core mask for cells --> generate one
1035
1037 (grid_data->core_cell_mask =
1038 xmalloc(grid_data->num_cells * sizeof(*core_cell_mask)));
1039 for (size_t j = 0; j < num_cells; ++j) {
1040 int curr_num_edges = num_vertices_per_cell[j];
1041 size_t * curr_edges = cell_to_edge + cell_to_edge_offsets[j];
1042 int mask = 1;
1043 for (int k = 0; k < curr_num_edges; ++k)
1044 mask &= core_edge_mask[curr_edges[k]];
1045 core_cell_mask[j] = mask;
1046 }
1047 }
1048 }
1049}
1050
1051// generate global ids for cells/vertices/edges (if they are missing)
1053 struct proc_sphere_part_node * proc_sphere_part,
1054 struct yac_basic_grid * grid, int ** vertex_ranks_,
1055 int max_num_vertices_per_cell, MPI_Comm comm) {
1056
1057 // generate global ids for all vertices (if non-existent)
1058 int * vertex_ranks =
1060 proc_sphere_part, yac_basic_grid_get_data(grid), comm);
1061
1062 // generate global ids and core masks for all cell and edge
1063 // (if non-existent and required)
1064 generate_ce_ids(grid, vertex_ranks, max_num_vertices_per_cell, comm);
1065
1066 *vertex_ranks_ = vertex_ranks;
1067}
1068
1069// generate edge to cell mapping
1072 int * core_cell_mask, size_t num_cells, size_t num_edges) {
1073
1074 if (num_cells == 0) return NULL;
1075
1076 yac_size_t_2_pointer edge_to_cell = xmalloc(num_edges * sizeof(*edge_to_cell));
1077
1078 for (size_t i = 0; i < num_edges; ++i) {
1079 edge_to_cell[i][0] = SIZE_MAX;
1080 edge_to_cell[i][1] = SIZE_MAX;
1081 }
1082
1083 for (size_t i = 0, offset = 0; i < num_cells; ++i) {
1084
1085 size_t curr_num_edges = num_edges_per_cell[i];
1086 const_size_t_pointer curr_cell_to_edge = cell_to_edge + offset;
1087 offset += curr_num_edges;
1088
1089 if ((core_cell_mask == NULL) || core_cell_mask[i]) {
1090
1091 for (size_t j = 0; j < curr_num_edges; ++j) {
1092
1093 size_t curr_edge = curr_cell_to_edge[j];
1094 size_t * curr_edge_to_cell = edge_to_cell[curr_edge];
1095 curr_edge_to_cell += *curr_edge_to_cell != SIZE_MAX;
1097 *curr_edge_to_cell == SIZE_MAX,
1098 "ERROR(generate_edge_to_cell): "
1099 "more than two cells point to a single edge "
1100 "(does the grid contain degenrated cells (less than 3 corners) "
1101 "or duplicated cells; "
1102 "these can be masked out using the core mask)\n"
1103 "(num_cells: %zu cell_idx: %zu: num_cell_edge %zu)",
1104 num_cells, i, curr_num_edges)
1105 *curr_edge_to_cell = i;
1106 }
1107 }
1108 }
1109
1110 return edge_to_cell;
1111}
1112
1114 yac_size_t_2_pointer edge_to_vertex,
1115 const yac_coordinate_pointer vertex_coordinates, size_t edge_id) {
1116
1117 struct bounding_circle bnd_circle;
1118
1119 size_t * curr_edge_to_vertex = edge_to_vertex[edge_id];
1120 double * vertices[2] =
1121 {vertex_coordinates[curr_edge_to_vertex[0]],
1122 vertex_coordinates[curr_edge_to_vertex[1]]};
1123
1124 bnd_circle.base_vector[0] = vertices[0][0] + vertices[1][0];
1125 bnd_circle.base_vector[1] = vertices[0][1] + vertices[1][1];
1126 bnd_circle.base_vector[2] = vertices[0][2] + vertices[1][2];
1127 normalise_vector(bnd_circle.base_vector);
1128 bnd_circle.inc_angle =
1129 half_angle(get_vector_angle_2(vertices[0], vertices[1]));
1130 bnd_circle.sq_crd = DBL_MAX;
1131
1132 return bnd_circle;
1133}
1134
1136 struct proc_sphere_part_node * proc_sphere_part,
1137 struct yac_basic_grid * grid, MPI_Comm comm,
1138 size_t * dist_cell_rank_offsets, size_t * dist_edge_rank_offsets,
1139 int * num_cell_ranks, int * num_edge_ranks,
1140 int ** rank_buffer, size_t * rank_buffer_array_size) {
1141
1142 struct yac_basic_grid_data * grid_data =
1144
1145 int comm_size;
1146 yac_mpi_call(MPI_Comm_size(comm, &comm_size), comm);
1147
1148 size_t num_cells = grid_data->num_cells;
1149 size_t num_edges = grid_data->num_edges;
1150 size_t dist_edge_rank_offset = dist_cell_rank_offsets[num_cells];
1151 int * core_edge_mask = grid_data->core_edge_mask;
1152
1153 // compute mapping from edge to cell
1154 yac_size_t_2_pointer edge_to_cell =
1156 grid_data->cell_to_edge, grid_data->num_vertices_per_cell,
1157 grid_data->core_cell_mask, num_cells, num_edges);
1158
1159 // for all edges
1160 for (size_t i = 0; i < num_edges; ++i) {
1161
1162 int edge_rank_count = 0;
1163
1164 // only distribute valid edges
1165 if ((core_edge_mask == NULL) || grid_data->core_edge_mask[i]) {
1166
1167 int cell_rank_counts[2] = {0, 0};
1168 size_t * curr_edge_cells = edge_to_cell[i];
1169
1170 for (int j = 0; j < 2; ++j)
1171 if (curr_edge_cells[j] != SIZE_MAX)
1172 edge_rank_count +=
1173 ((cell_rank_counts[j] = num_cell_ranks[curr_edge_cells[j]]));
1174
1175 // if the edge is connected to at least one cell
1176 if (edge_rank_count > 0) {
1177
1179 *rank_buffer, *rank_buffer_array_size,
1180 dist_edge_rank_offset + edge_rank_count);
1181
1182 int * curr_edge_ranks = *rank_buffer + dist_edge_rank_offset;
1183
1184 // get ranks of connected cells
1185 edge_rank_count = 0;
1186 for (int j = 0; j < 2; ++j) {
1187 if (cell_rank_counts[j] > 0) {
1188 int * cell_ranks =
1189 *rank_buffer + dist_cell_rank_offsets[curr_edge_cells[j]];
1190 for (int k = 0; k < cell_rank_counts[j]; ++k)
1192 curr_edge_ranks, &edge_rank_count, cell_ranks[k]);
1193 }
1194 }
1195
1196 } else { // if this is a "hanging edge" (not connected to any cell)
1197
1199 *rank_buffer, *rank_buffer_array_size,
1200 dist_edge_rank_offset + comm_size);
1201
1202 int * curr_edge_ranks = *rank_buffer + dist_edge_rank_offset;
1203
1204 // set up a bounding circle around the edge and search for all matching
1205 // ranks based on the YAC internal decomposition
1207 proc_sphere_part,
1209 grid_data->edge_to_vertex, grid_data->vertex_coordinates, i),
1210 curr_edge_ranks, &edge_rank_count);
1211 }
1212 }
1213
1214 dist_edge_rank_offset += (size_t)edge_rank_count;
1215 num_edge_ranks[i] = edge_rank_count;
1216
1217 dist_edge_rank_offsets[i+1] = dist_edge_rank_offset;
1218 }
1219
1220 free(edge_to_cell);
1221}
1222
1225 size_t * vertex_to_edge, int * num_edges_per_vertex) {
1226
1227 memset(
1228 num_edges_per_vertex, 0, num_vertices * sizeof(*num_edges_per_vertex));
1229
1230 for (size_t i = 0; i < num_edges; ++i) {
1231 num_edges_per_vertex[edge_to_vertex[i][0]]++;
1232 num_edges_per_vertex[edge_to_vertex[i][1]]++;
1233 }
1234
1235 size_t * vertex_edges_offsets =
1236 xmalloc((num_vertices + 1) * sizeof(*vertex_edges_offsets));
1237
1238 vertex_edges_offsets[0] = 0;
1239 for (size_t i = 0, offset = 0; i < num_vertices; ++i) {
1240 vertex_edges_offsets[i + 1] = offset;
1241 offset += (size_t)(num_edges_per_vertex[i]);
1242 }
1243
1244 for (size_t i = 0; i < num_edges; ++i) {
1245 for (int j = 0; j < 2; ++j) {
1246 size_t curr_vertex = edge_to_vertex[i][j];
1247 vertex_to_edge[vertex_edges_offsets[curr_vertex+1]] = i;
1248 vertex_edges_offsets[curr_vertex+1]++;
1249 }
1250 }
1251
1252 free(vertex_edges_offsets);
1253}
1254
1256 int * vertex_ranks, struct yac_basic_grid * grid, MPI_Comm comm,
1257 size_t * dist_edge_rank_offsets, int * num_edge_ranks, int * num_vertex_ranks,
1258 int ** rank_buffer, size_t * rank_buffer_array_size) {
1259
1260 struct yac_basic_grid_data * grid_data = yac_basic_grid_get_data(grid);
1261
1262 int comm_size;
1263 yac_mpi_call(MPI_Comm_size(comm, &comm_size), comm);
1264
1265 size_t num_edges = grid_data->num_edges;
1266 size_t num_vertices = grid_data->num_vertices;
1267 size_t vertex_rank_offset = dist_edge_rank_offsets[num_edges];
1268 int * core_vertex_mask = grid_data->core_vertex_mask;
1269
1270 // compute mapping from vertex to edge
1271 size_t * vertex_to_edge = xmalloc(2 * num_edges * sizeof(*vertex_to_edge));
1272 int * num_edges_per_vertex =
1273 xmalloc(num_vertices * sizeof(*num_edges_per_vertex));
1276 vertex_to_edge, num_edges_per_vertex);
1277 size_t * curr_edges = vertex_to_edge;
1278
1279 // for all vertices
1280 for (size_t i = 0; i < num_vertices; ++i) {
1281
1282 int vertex_rank_count = 0;
1283 int curr_num_edges = num_edges_per_vertex[i];
1284
1285 // if this is a valid vertex (not masked out by the core mask)
1286 if ((core_vertex_mask == NULL) || core_vertex_mask[i]) {
1287
1288 for (int j = 0; j < curr_num_edges; ++j)
1289 vertex_rank_count += num_edge_ranks[curr_edges[j]];
1290
1291 // if the vertex is connected to at least one edge
1292 if (vertex_rank_count > 0) {
1293
1295 *rank_buffer, *rank_buffer_array_size,
1296 vertex_rank_offset + vertex_rank_count);
1297
1298 int * curr_vertex_ranks = *rank_buffer + vertex_rank_offset;
1299
1300 // get ranks of connected edges
1301 vertex_rank_count = 0;
1302 for (int j = 0; j < curr_num_edges; ++j) {
1303 size_t curr_edge = curr_edges[j];
1304 int curr_num_edge_ranks = num_edge_ranks[curr_edge];
1305 int * curr_edge_ranks =
1306 *rank_buffer + dist_edge_rank_offsets[curr_edge];
1307 for (int k = 0; k < curr_num_edge_ranks; ++k)
1309 curr_vertex_ranks, &vertex_rank_count, curr_edge_ranks[k]);
1310 }
1311
1312 } else { // if this is a "hanging vertex" (not connected to any edge)
1313
1315 *rank_buffer, *rank_buffer_array_size, vertex_rank_offset + 1);
1316
1317 int * curr_vertex_ranks = *rank_buffer + vertex_rank_offset;
1318
1319 *curr_vertex_ranks = vertex_ranks[i];
1320 vertex_rank_count = 1;
1321 }
1322 }
1323
1324 vertex_rank_offset += (size_t)vertex_rank_count;
1325 num_vertex_ranks[i] = vertex_rank_count;
1326 curr_edges += curr_num_edges;
1327 }
1328
1329 free(num_edges_per_vertex);
1330 free(vertex_to_edge);
1331}
1332
1334 const void * a, const void * b) {
1335
1336 return (((const struct single_remote_point *)a)->global_id >
1337 ((const struct single_remote_point *)b)->global_id) -
1338 (((const struct single_remote_point *)a)->global_id <
1339 ((const struct single_remote_point *)b)->global_id);
1340}
1341
1342// generate owner information for all cell/vertices/edges that may be
1343// assigned to the local process in the YAC internal decomposition
1344// (dist owners are sorted by global ids)
1346 struct proc_sphere_part_node * proc_sphere_part,
1347 struct yac_basic_grid * grid, int * vertex_ranks,
1348 int max_num_vertices_per_cell, MPI_Comm comm,
1349 struct remote_point_infos ** dist_point_infos, yac_int ** dist_global_ids,
1350 size_t * dist_count) {
1351
1352 char const * routine = "generate_dist_remote_points";
1353
1354 struct yac_basic_grid_data * grid_data = yac_basic_grid_get_data(grid);
1355
1356 size_t num_cells = grid_data->num_cells;
1357 size_t num_vertices = grid_data->num_vertices;
1358 size_t num_edges = grid_data->num_edges;
1359
1360 int * rank_buffer;
1361 int * num_ranks_buffer =
1362 xmalloc(
1363 (num_cells + num_vertices + num_edges) * sizeof(*num_ranks_buffer));
1364 int * num_cell_ranks = num_ranks_buffer;
1365 int * num_vertex_ranks = num_ranks_buffer + num_cells;
1366 int * num_edge_ranks = num_ranks_buffer + num_cells + num_vertices;
1367 size_t * dist_rank_offsets =
1368 xmalloc((num_cells + num_edges + 1) * sizeof(*dist_rank_offsets));
1369 size_t * dist_cell_rank_offsets = dist_rank_offsets;
1370 size_t * dist_edge_rank_offsets = dist_rank_offsets + num_cells;
1371
1372 //-------------------------------------------------------------------
1373 // determine for all cells/vertices/edges that ranks of the processes
1374 // that require them according to the YAC internal decomposition
1375 //-------------------------------------------------------------------
1376
1377 // determine for all cells the ranks of the processes whose YAC internal
1378 // partition overlaps with the bounding circle of the respective cell
1380 proc_sphere_part, grid_data, comm,
1381 &rank_buffer, num_cell_ranks, dist_cell_rank_offsets, max_num_vertices_per_cell);
1382
1383 size_t rank_buffer_array_size = dist_cell_rank_offsets[num_cells];
1384
1385 // determine for all edges the ranks of the processes whose YAC internal
1386 // partition overlaps with the respective edge
1387 // (edges connected to a cell use the ranks of the cell;
1388 // edges not connected to any cell use a bounding circle to determine
1389 // the ranks)
1391 proc_sphere_part, grid, comm, dist_cell_rank_offsets, dist_edge_rank_offsets,
1392 num_cell_ranks, num_edge_ranks, &rank_buffer, &rank_buffer_array_size);
1393
1394 // determine for all vertices the ranks of the processes whose YAC internal
1395 // partition overlaps with the respective vertex
1396 // (vertices connected to an edge use the ranks of the edge;
1397 // vertices not connected to any edge directly determine the rank using
1398 // the YAC internal decomposition)
1400 vertex_ranks, grid, comm, dist_edge_rank_offsets,
1401 num_edge_ranks, num_vertex_ranks, &rank_buffer, &rank_buffer_array_size);
1402
1403 int * dist_cell_ranks = rank_buffer;
1404 int * dist_vertex_ranks = rank_buffer + dist_edge_rank_offsets[num_edges];
1405 int * dist_edge_ranks = rank_buffer + dist_cell_rank_offsets[num_cells];
1406
1407 free(dist_rank_offsets);
1408
1409 //-------------------------------------------------------------------
1410 // inform all processes about the cells/vertices/edges that they
1411 // require according to the YAC internal decomposition
1412 //-------------------------------------------------------------------
1413
1414 int comm_size;
1415 yac_mpi_call(MPI_Comm_size(comm, &comm_size), comm);
1416
1417 size_t * sendcounts, * recvcounts, * sdispls, * rdispls;
1419 3, &sendcounts, &recvcounts, &sdispls, &rdispls, comm);
1420 size_t * size_t_buffer =
1421 xmalloc(4 * (size_t)comm_size * sizeof(*size_t_buffer));
1422 size_t * total_sendcounts = size_t_buffer + 0 * comm_size;
1423 size_t * total_recvcounts = size_t_buffer + 1 * comm_size;
1424 size_t * total_sdispls = size_t_buffer + 2 * comm_size;
1425 size_t * total_rdispls = size_t_buffer + 3 * comm_size;
1426
1427 struct {
1428 size_t count;
1429 int * ranks;
1430 int * num_ranks;
1431 yac_int * ids;
1432 } cve_data[3] =
1433 {{.count = num_cells,
1434 .ranks = dist_cell_ranks,
1435 .num_ranks = num_cell_ranks,
1436 .ids = grid_data->cell_ids},
1437 {.count = num_vertices,
1438 .ranks = dist_vertex_ranks,
1439 .num_ranks = num_vertex_ranks,
1440 .ids = grid_data->vertex_ids},
1441 {.count = num_edges,
1442 .ranks = dist_edge_ranks,
1443 .num_ranks = num_edge_ranks,
1444 .ids = grid_data->edge_ids}};
1445
1446 // determine number of cells/vertices/edges that have to be
1447 // sent to other processes
1448 for (int location = 0; location < 3; ++location) {
1449 size_t count = cve_data[location].count;
1450 int * ranks = cve_data[location].ranks;
1451 int * num_ranks = cve_data[location].num_ranks;
1452 for (size_t i = 0, k = 0; i < count; ++i) {
1453 int curr_num_ranks = num_ranks[i];
1454 for (int j = 0; j < curr_num_ranks; ++j, ++k)
1455 sendcounts[3 * ranks[k] + location]++;
1456 }
1457 }
1458
1460 3, sendcounts, recvcounts, sdispls, rdispls, comm);
1461
1462 size_t receive_counts[3] = {0,0,0};
1463 size_t saccu = 0, raccu = 0;
1464 for (int i = 0; i < comm_size; ++i) {
1465 total_sdispls[i] = saccu;
1466 total_rdispls[i] = raccu;
1467 total_sendcounts[i] = 0;
1468 total_recvcounts[i] = 0;
1469 for (int location = 0; location < 3; ++location) {
1470 total_sendcounts[i] += sendcounts[3 * i + location];
1471 total_recvcounts[i] += recvcounts[3 * i + location];
1472 receive_counts[location] += recvcounts[3 * i + location];
1473 }
1474 saccu += total_sendcounts[i];
1475 raccu += total_recvcounts[i];
1476 }
1477 size_t local_data_count = total_sendcounts[comm_size - 1] +
1478 total_sdispls[comm_size - 1];
1479 size_t recv_count = total_recvcounts[comm_size - 1] +
1480 total_rdispls[comm_size - 1];
1481
1482 struct id_pos * id_pos_buffer =
1483 xcalloc((local_data_count + recv_count), sizeof(*id_pos_buffer));
1484 struct id_pos * id_pos_send_buffer = id_pos_buffer;
1485 struct id_pos * id_pos_recv_buffer =
1486 id_pos_buffer + local_data_count;
1487
1488 // pack cell/edge/vertex information for distributed owners
1489 for (int location = 0; location < 3; ++location) {
1490 size_t count = cve_data[location].count;
1491 int * ranks = cve_data[location].ranks;
1492 int * num_ranks = cve_data[location].num_ranks;
1493 yac_int * ids = cve_data[location].ids;
1494 for (size_t i = 0, k = 0; i < count; ++i) {
1495 int curr_num_ranks = num_ranks[i];
1496 yac_int global_id = ids[i];
1497 for (int j = 0; j < curr_num_ranks; ++j, ++k) {
1498 size_t pos = sdispls[3 * ranks[k] + location + 1]++;
1499 id_pos_send_buffer[pos].global_id = global_id;
1500 id_pos_send_buffer[pos].orig_pos = i;
1501 }
1502 }
1503 }
1504 free(num_ranks_buffer);
1505 free(rank_buffer);
1506
1507 MPI_Datatype id_pos_dt = yac_get_id_pos_mpi_datatype(comm);
1508
1509 // exchange cell/vertex/edge information for distributed owners
1511 id_pos_send_buffer, total_sendcounts, total_sdispls,
1512 id_pos_recv_buffer, total_recvcounts, total_rdispls,
1513 sizeof(*id_pos_send_buffer), id_pos_dt, comm,
1514 routine, __LINE__);
1515
1516 yac_mpi_call(MPI_Type_free(&id_pos_dt), comm);
1517
1518 size_t dist_owner_counts[3] = {0, 0, 0};
1519 for (int i = 0; i < comm_size; ++i)
1520 for (int location = 0; location < 3; ++location)
1521 dist_owner_counts[location] += recvcounts[3 * i + location];
1522 size_t max_dist_owner_count =
1523 MAX(MAX(dist_owner_counts[0], dist_owner_counts[1]), dist_owner_counts[2]);
1524 struct single_remote_point * temp_buffer =
1525 xcalloc(max_dist_owner_count, sizeof(*temp_buffer));
1526
1527 struct remote_point * unique_ids = NULL;
1528
1529 // unpack data
1530 for (int location = 0; location < 3; ++location) {
1531
1532 size_t count = 0;
1533 for (int i = 0; i < comm_size; ++i) {
1534 size_t curr_recvcount = recvcounts[3 * i + location];
1535 struct id_pos * curr_id_pos =
1536 id_pos_recv_buffer + rdispls[3 * i + location];
1537 for (size_t k = 0; k < curr_recvcount; ++k, ++count) {
1538 temp_buffer[count].global_id = curr_id_pos[k].global_id;
1539 temp_buffer[count].data.orig_pos = curr_id_pos[k].orig_pos;
1540 temp_buffer[count].data.rank = i;
1541 }
1542 }
1543
1544 // sort received global ids
1545 qsort(temp_buffer, count, sizeof(*temp_buffer),
1547
1548 unique_ids = xrealloc(unique_ids, count * sizeof(*unique_ids));
1549 size_t num_unique_ids = 0;
1550
1551 // determine unique global ids
1552 yac_int prev_id = (count > 0)?temp_buffer[0].global_id - 1:-1;
1553 for (size_t i = 0; i < count; ++i) {
1554
1555 yac_int curr_id = temp_buffer[i].global_id;
1556 if (curr_id != prev_id) {
1557 prev_id = curr_id;
1558 unique_ids[num_unique_ids].global_id = curr_id;
1559 unique_ids[num_unique_ids].data.count = 1;
1560 num_unique_ids++;
1561 } else {
1562 unique_ids[num_unique_ids-1].data.count++;
1563 }
1564 }
1565
1566 struct remote_point_infos * point_infos =
1567 ((dist_point_infos[location] =
1568 xmalloc(num_unique_ids * sizeof(*(dist_point_infos[location])))));
1569 yac_int * global_ids =
1570 ((dist_global_ids[location] =
1571 xmalloc(num_unique_ids * sizeof(*(dist_global_ids[location])))));
1572 dist_count[location] = num_unique_ids;
1573
1574 // compact received information
1575 // (each global id is only stored once and can have multiple
1576 // original owners)
1577 for (size_t i = 0, l = 0; i < num_unique_ids; ++i) {
1578 global_ids[i] = unique_ids[i].global_id;
1579 int curr_count = unique_ids[i].data.count;
1580 point_infos[i].count = curr_count;
1581 if (curr_count == 1) {
1582 point_infos[i].data.single = temp_buffer[l].data;
1583 ++l;
1584 } else {
1585 point_infos[i].data.multi =
1586 xmalloc(
1587 (size_t)curr_count *
1588 sizeof(*(point_infos[i].data.multi)));
1589 for (int k = 0; k < curr_count; ++k, ++l) {
1590 point_infos[i].data.multi[k] = temp_buffer[l].data;
1591 }
1592 }
1593 }
1594 } // location
1595
1596 free(unique_ids);
1597 free(id_pos_buffer);
1598 free(temp_buffer);
1599 free(size_t_buffer);
1600 yac_free_comm_buffers(sendcounts, recvcounts, sdispls, rdispls);
1601}
1602
1604 yac_int * global_ids, size_t count,
1605 yac_int ** sorted_global_ids, size_t ** reorder_idx) {
1606
1607 *sorted_global_ids = xmalloc(count * sizeof(**sorted_global_ids));
1608 memcpy(*sorted_global_ids, global_ids, count * sizeof(**sorted_global_ids));
1609 *reorder_idx = xmalloc(count * sizeof(**reorder_idx));
1610 for (size_t i = 0; i < count; ++i) (*reorder_idx)[i] = i;
1611}
1612
1613static Xt_xmap generate_xmap_data(
1614 struct remote_point_infos * point_infos, size_t count, MPI_Comm comm) {
1615
1616 int comm_size;
1617 yac_mpi_call(MPI_Comm_size(comm, &comm_size), comm);
1618
1619 size_t * sendcounts, * recvcounts, * sdispls, * rdispls;
1621 1, &sendcounts, &recvcounts, &sdispls, &rdispls, comm);
1622
1623 for (size_t i = 0; i < count; ++i) {
1624 struct remote_point_info * curr_info =
1625 (point_infos[i].count > 1)?
1626 (point_infos[i].data.multi):
1627 (&(point_infos[i].data.single));
1628 sendcounts[curr_info->rank]++;
1629 }
1630
1632 1, sendcounts, recvcounts, sdispls, rdispls, comm);
1633 size_t num_src_msg = 0, num_dst_msg = 0;
1634 for (int i = 0; i < comm_size; ++i) {
1635 num_src_msg += (recvcounts[i] > 0);
1636 num_dst_msg += (sendcounts[i] > 0);
1637 }
1638
1639 size_t recv_count =
1640 rdispls[comm_size-1] + recvcounts[comm_size-1];
1641
1642 int * pos_buffer =
1643 xmalloc((recv_count + 2 * count) * sizeof(*pos_buffer));
1644 int * src_pos_buffer = pos_buffer;
1645 int * dst_pos_buffer = pos_buffer + recv_count;
1646 int * send_pos_buffer = pos_buffer + recv_count + count;
1647
1648 // pack send buffer
1649 for (size_t i = 0; i < count; ++i) {
1650 struct remote_point_info * curr_info =
1651 (point_infos[i].count > 1)?
1652 (point_infos[i].data.multi):
1653 (&(point_infos[i].data.single));
1654 size_t pos = sdispls[curr_info->rank+1]++;
1655 dst_pos_buffer[pos] = i;
1656 send_pos_buffer[pos] = (int)(curr_info->orig_pos);
1657 }
1658
1659 // redistribute positions of requested data
1660 yac_alltoallv_int_p2p(
1661 send_pos_buffer, sendcounts, sdispls,
1662 src_pos_buffer, recvcounts, rdispls, comm,
1663 "generate_xmap_data", __LINE__);
1664
1665 struct Xt_com_pos * com_pos =
1666 xmalloc(((size_t)num_src_msg + (size_t)num_dst_msg) * sizeof(*com_pos));
1667 struct Xt_com_pos * src_com = com_pos;
1668 struct Xt_com_pos * dst_com = com_pos + num_src_msg;
1669
1670 // set transfer_pos pointers and transfer_pos counts in com_pos's
1671 num_src_msg = 0;
1672 num_dst_msg = 0;
1673 for (int i = 0; i < comm_size; ++i) {
1674 if (recvcounts[i] > 0) {
1675 src_com[num_src_msg].transfer_pos = src_pos_buffer;
1676 src_com[num_src_msg].num_transfer_pos = recvcounts[i];
1677 src_com[num_src_msg].rank = i;
1678 src_pos_buffer += recvcounts[i];
1679 ++num_src_msg;
1680 }
1681 if (sendcounts[i] > 0) {
1682 dst_com[num_dst_msg].transfer_pos = dst_pos_buffer;
1683 dst_com[num_dst_msg].num_transfer_pos = sendcounts[i];
1684 dst_com[num_dst_msg].rank = i;
1685 dst_pos_buffer += sendcounts[i];
1686 ++num_dst_msg;
1687 }
1688 }
1689 yac_free_comm_buffers(sendcounts, recvcounts, sdispls, rdispls);
1690
1691 Xt_xmap xmap =
1692 xt_xmap_intersection_pos_new(
1693 num_src_msg, src_com, num_dst_msg, dst_com, comm);
1694
1695 free(com_pos);
1696 free(pos_buffer);
1697
1698 return xmap;
1699}
1700
1702 const void * a, const void * b) {
1703
1704 return (((const struct single_remote_point_reorder *)a)->data.global_id >
1705 ((const struct single_remote_point_reorder *)b)->data.global_id) -
1706 (((const struct single_remote_point_reorder *)a)->data.global_id <
1707 ((const struct single_remote_point_reorder *)b)->data.global_id);
1708}
1709
1711 const void * a, const void * b) {
1712
1713 return (((const struct single_remote_point_reorder *)a)->reorder_idx >
1714 ((const struct single_remote_point_reorder *)b)->reorder_idx) -
1715 (((const struct single_remote_point_reorder *)a)->reorder_idx <
1716 ((const struct single_remote_point_reorder *)b)->reorder_idx);
1717}
1718
1719static MPI_Datatype yac_get_coordinate_mpi_datatype(MPI_Comm comm) {
1720
1721 MPI_Datatype coord_dt;
1722 yac_mpi_call(MPI_Type_contiguous(3, MPI_DOUBLE, &coord_dt), comm);
1723 yac_mpi_call(MPI_Type_commit(&coord_dt), comm);
1724 return coord_dt;
1725}
1726
1728 struct yac_field_data * orig_field_data, size_t dist_size,
1729 Xt_redist redist_mask, Xt_redist redist_coords, MPI_Comm comm) {
1730
1731 struct yac_field_data * dist_field_data = yac_field_data_empty_new();
1732
1733 uint64_t counts[2], max_counts[2];
1734 if (orig_field_data != NULL) {
1735 counts[0] = yac_field_data_get_masks_count(orig_field_data);
1736 counts[1] = yac_field_data_get_coordinates_count(orig_field_data);
1737 } else {
1738 counts[0] = 0;
1739 counts[1] = 0;
1740 }
1742 MPI_Allreduce(
1743 counts, max_counts, 2, MPI_UINT64_T, MPI_MAX, comm), comm);
1744 YAC_ASSERT(
1745 (orig_field_data == NULL) ||
1746 ((counts[0] == max_counts[0]) && (counts[1] == max_counts[1])),
1747 "ERROR(field_data_init): inconsistent number of masks or coordinates")
1748
1749 int * data_available_flag =
1750 xcalloc(2 * max_counts[0] + max_counts[1], sizeof(*data_available_flag));
1751
1752 for (size_t i = 0; i < counts[0]; ++i) {
1753 data_available_flag[i] =
1754 yac_field_data_get_mask_data(orig_field_data, i) != NULL;
1755 data_available_flag[i + counts[0]] =
1756 (yac_field_data_get_mask_name(orig_field_data, i) != NULL)?
1757 ((int)strlen(yac_field_data_get_mask_name(orig_field_data, i))+1):0;
1758 }
1759 for (size_t i = 0; i < counts[1]; ++i)
1760 data_available_flag[i + 2 * counts[0]] =
1761 yac_field_data_get_coordinates_data(orig_field_data, i) != NULL;
1762
1764 MPI_Allreduce(
1765 MPI_IN_PLACE, data_available_flag,
1766 (int)(2 * max_counts[0] + max_counts[1]), MPI_INT, MPI_MAX, comm), comm);
1767
1768 for (size_t i = 0; i < counts[0]; ++i) {
1769 YAC_ASSERT(
1770 data_available_flag[i] ==
1771 (yac_field_data_get_mask_data(orig_field_data, i) != NULL),
1772 "ERROR(field_data_init): inconsistent availability of masks")
1773 int mask_name_len =
1774 (yac_field_data_get_mask_name(orig_field_data, i) != NULL)?
1775 ((int)strlen(yac_field_data_get_mask_name(orig_field_data, i))+1):0;
1776 YAC_ASSERT(
1777 data_available_flag[i + counts[0]] ==
1778 mask_name_len,
1779 "ERROR(field_data_init): inconsistent mask names")
1780 }
1781
1782 for (size_t i = 0; i < counts[1]; ++i)
1783 YAC_ASSERT(
1784 data_available_flag[i + 2 * counts[0]] ==
1785 (yac_field_data_get_coordinates_data(orig_field_data, i) != NULL),
1786 "ERROR(field_data_init): inconsistent availability of coordinates")
1787
1788 for (uint64_t i = 0; i < max_counts[0]; ++i) {
1789 int * dist_mask = NULL;
1790 if (data_available_flag[i]) {
1791 dist_mask = xmalloc(dist_size * sizeof(*dist_mask));
1792 int const * orig_mask =
1793 (orig_field_data != NULL)?
1794 yac_field_data_get_mask_data(orig_field_data, i):NULL;
1795 xt_redist_s_exchange1(redist_mask, orig_mask, dist_mask);
1796 }
1797
1798 int mask_name_len = data_available_flag[i + max_counts[0]];
1799 char * mask_name = NULL;
1800 if (mask_name_len > 0) {
1801 mask_name = xmalloc((size_t)mask_name_len * sizeof(*mask_name));
1802 if ((orig_field_data != NULL) &&
1803 (yac_field_data_get_mask_name(orig_field_data, i) != NULL))
1804 memcpy(
1805 mask_name, yac_field_data_get_mask_name(orig_field_data, i),
1806 (size_t)mask_name_len);
1807 else
1808 memset(mask_name, 0, (size_t)mask_name_len * sizeof(*mask_name));
1810 MPI_Allreduce(
1811 MPI_IN_PLACE, mask_name, mask_name_len, MPI_CHAR, MPI_MAX, comm),
1812 comm);
1813 YAC_ASSERT(
1814 (orig_field_data == NULL) ||
1815 (yac_field_data_get_mask_name(orig_field_data, i) == NULL) ||
1816 !memcmp(
1817 yac_field_data_get_mask_name(orig_field_data, i), mask_name,
1818 (size_t)mask_name_len * sizeof(*mask_name)),
1819 "ERROR(field_data_init): inconsistent mask names")
1820 }
1821 yac_field_data_add_mask_nocpy(dist_field_data, dist_mask, mask_name);
1822 }
1823
1824 for (uint64_t i = 0; i < max_counts[1]; ++i) {
1825 yac_coordinate_pointer dist_coordinates = NULL;
1826 if (data_available_flag[i + 2 * max_counts[0]]) {
1827 dist_coordinates = xmalloc(dist_size * sizeof(*dist_coordinates));
1828 yac_const_coordinate_pointer orig_coordinates =
1829 (orig_field_data != NULL)?
1830 yac_field_data_get_coordinates_data(orig_field_data, i):NULL;
1831 xt_redist_s_exchange1(redist_coords, orig_coordinates, dist_coordinates);
1832 }
1833 yac_field_data_add_coordinates_nocpy(dist_field_data, dist_coordinates);
1834 }
1835
1836 free(data_available_flag);
1837
1838 return dist_field_data;
1839}
1840
1842 struct yac_basic_grid * grid,
1843 struct remote_point_infos * dist_vertex_infos, size_t num_vertices,
1844 MPI_Comm comm, MPI_Datatype dt_coord, int * vertex_ranks,
1845 yac_coordinate_pointer * vertex_coordinates_, int ** vertex_owner_,
1846 struct yac_field_data ** vertex_field_data_) {
1847
1848 struct yac_basic_grid_data * grid_data = yac_basic_grid_get_data(grid);
1849
1850 // generate a yaxt exchange map user -> YAC decomposition
1851 Xt_xmap xmap = generate_xmap_data(dist_vertex_infos, num_vertices, comm);
1852
1853 // generate redistributing objects for vertex data
1854 Xt_redist redist_vertex_coords = xt_redist_p2p_new(xmap, dt_coord);
1855 Xt_redist redist_vertex_int = xt_redist_p2p_new(xmap, MPI_INT);
1856 xt_xmap_delete(xmap);
1857
1858 // get vertex coordinates
1861 xt_redist_s_exchange1(
1862 redist_vertex_coords, grid_data->vertex_coordinates, vertex_coordinates);
1863
1864 // get owners of all vertices
1865 int * vertex_owner = xmalloc(num_vertices * sizeof(*vertex_owner));
1866 xt_redist_s_exchange1(redist_vertex_int, vertex_ranks, vertex_owner);
1867
1868 // get field data
1869 struct yac_field_data * vertex_field_data =
1871 yac_basic_grid_get_field_data(grid, YAC_LOC_CORNER), num_vertices,
1872 redist_vertex_int, redist_vertex_coords, comm);
1873
1874 xt_redist_delete(redist_vertex_int);
1875 xt_redist_delete(redist_vertex_coords);
1876
1877 *vertex_coordinates_ = vertex_coordinates;
1878 *vertex_owner_ = vertex_owner;
1879 *vertex_field_data_ = vertex_field_data;
1880}
1881
1883 struct yac_basic_grid * grid,
1884 struct remote_point_infos * dist_edge_infos, size_t num_edges, MPI_Comm comm,
1885 MPI_Datatype dt_coord, size_t num_vertices, yac_int * sorted_vertex_ids,
1886 size_t * sorted_vertex_reorder_idx,
1887 yac_size_t_2_pointer * edge_to_vertex_, enum yac_edge_type ** edge_type_,
1888 struct yac_field_data ** edge_field_data_) {
1889
1890 struct yac_basic_grid_data * grid_data = yac_basic_grid_get_data(grid);
1891
1892 // generate a yaxt exchange map user -> YAC decomposition
1893 Xt_xmap xmap = generate_xmap_data(dist_edge_infos, num_edges, comm);
1894
1895 // generate redistributing objects for edge data
1896 MPI_Datatype dt_2yac_int;
1897 yac_mpi_call(MPI_Type_contiguous(2, yac_int_dt, &dt_2yac_int), comm);
1898 yac_mpi_call(MPI_Type_commit(&dt_2yac_int), comm);
1899 Xt_redist redist_edge_int = xt_redist_p2p_new(xmap, MPI_INT);
1900 Xt_redist redist_edge_coords = xt_redist_p2p_new(xmap, dt_coord);
1901 Xt_redist redist_edge_2yac_int = xt_redist_p2p_new(xmap, dt_2yac_int);
1902 yac_mpi_call(MPI_Type_free(&dt_2yac_int), comm);
1903 xt_xmap_delete(xmap);
1904
1905 enum yac_edge_type * edge_type = xmalloc(num_edges * sizeof(*edge_type));
1906 { // get edge types
1907 int * temp_edge_type_src, * temp_edge_type_dst;
1908 if (sizeof(*edge_type) == sizeof(int)) {
1909 temp_edge_type_src = (int*)(grid_data->edge_type);
1910 temp_edge_type_dst = (int*)edge_type;
1911 } else {
1912 temp_edge_type_src =
1913 xmalloc(grid_data->num_edges * sizeof(*temp_edge_type_src));
1914 for (size_t i = 0; i < grid_data->num_edges; ++i)
1915 temp_edge_type_src[i] = (int)(grid_data->edge_type[i]);
1916 temp_edge_type_dst = xmalloc(num_edges * sizeof(*temp_edge_type_dst));
1917 for (size_t i = 0; i < num_edges; ++i)
1918 temp_edge_type_dst[i] = (int)(edge_type[i]);
1919 }
1920
1921 xt_redist_s_exchange1(
1922 redist_edge_int, temp_edge_type_src, temp_edge_type_dst);
1923
1924 if (sizeof(*edge_type) != sizeof(int)) {
1925
1926 for (size_t i = 0; i < num_edges; ++i)
1927 edge_type[i] = (enum yac_edge_type)(temp_edge_type_dst[i]);
1928
1929 free(temp_edge_type_src);
1930 free(temp_edge_type_dst);
1931 }
1932 }
1933
1935 xmalloc(num_edges * sizeof(*edge_to_vertex));
1936 { // get edge to vertex
1937 yac_int * vertex_id_buffer =
1938 xmalloc(
1939 2 * (grid_data->num_edges + num_edges) * sizeof(*vertex_id_buffer));
1940 yac_int * grid_edge_vertex_ids = vertex_id_buffer;
1941 yac_int * edge_vertex_ids = vertex_id_buffer + 2 * grid_data->num_edges;
1942
1943 size_t * grid_edge_to_vertex = &(grid_data->edge_to_vertex[0][0]);
1944
1945 for (size_t i = 0; i < 2 * grid_data->num_edges; ++i)
1946 grid_edge_vertex_ids[i] =
1947 grid_data->vertex_ids[grid_edge_to_vertex[i]];
1948
1949 xt_redist_s_exchange1(
1950 redist_edge_2yac_int, grid_edge_vertex_ids, edge_vertex_ids);
1951
1952 id2idx(
1953 "redistribute_edge_data", edge_vertex_ids,
1954 &(edge_to_vertex[0][0]), 2 * num_edges,
1955 sorted_vertex_ids, sorted_vertex_reorder_idx, num_vertices);
1956
1957 free(vertex_id_buffer);
1958 }
1959
1960 // get field data
1961 struct yac_field_data * edge_field_data =
1964 redist_edge_int, redist_edge_coords, comm);
1965
1966 xt_redist_delete(redist_edge_2yac_int);
1967 xt_redist_delete(redist_edge_coords);
1968 xt_redist_delete(redist_edge_int);
1969
1970 *edge_to_vertex_ = edge_to_vertex;
1971 *edge_type_ = edge_type;
1972 *edge_field_data_ = edge_field_data;
1973}
1974
1976 struct yac_basic_grid * grid,
1977 struct remote_point_infos * dist_cell_infos, size_t num_cells, MPI_Comm comm,
1978 MPI_Datatype dt_coord,
1979 size_t num_edges, yac_int * sorted_edge_ids,
1980 size_t * sorted_edge_reorder_idx,
1981 size_t num_vertices, yac_int * sorted_vertex_ids,
1982 size_t * sorted_vertex_reorder_idx, int max_num_vertices_per_cell,
1983 size_t ** cell_to_vertex_, size_t ** cell_to_edge_,
1984 int ** num_vertices_per_cell_, struct yac_field_data ** cell_field_data_) {
1985
1986 struct yac_basic_grid_data * grid_data = yac_basic_grid_get_data(grid);
1987
1988 // generate a yaxt exchange map user -> YAC decomposition
1989 Xt_xmap xmap = generate_xmap_data(dist_cell_infos, num_cells, comm);
1990
1991 // generate redistributing objects for edge data
1992 MPI_Datatype dt_yac_ints;
1994 MPI_Type_contiguous(
1995 max_num_vertices_per_cell, yac_int_dt, &dt_yac_ints), comm);
1996 yac_mpi_call(MPI_Type_commit(&dt_yac_ints), comm);
1997 Xt_redist redist_cell_int = xt_redist_p2p_new(xmap, MPI_INT);
1998 Xt_redist redist_cell_yac_ints = xt_redist_p2p_new(xmap, dt_yac_ints);
1999 Xt_redist redist_cell_coords = xt_redist_p2p_new(xmap, dt_coord);
2000 yac_mpi_call(MPI_Type_free(&dt_yac_ints), comm);
2001 xt_xmap_delete(xmap);
2002
2003 size_t * cell_to_vertex;
2004 size_t * cell_to_edge;
2005 int * num_vertices_per_cell = NULL;
2006 { // get connectivity data
2007 yac_int * id_buffer =
2008 xmalloc(
2009 (size_t)max_num_vertices_per_cell *
2010 (grid_data->num_cells + num_cells) * sizeof(*id_buffer));
2011 yac_int * grid_id_buffer =
2012 id_buffer + (size_t)max_num_vertices_per_cell * num_cells;
2013 size_t total_num_ids = 0;
2014
2015 size_t grid_num_cells = grid_data->num_cells;
2016 int * grid_num_ve_per_cell = grid_data->num_vertices_per_cell;
2017 yac_int * grid_ids = grid_data->vertex_ids;
2018 size_t * grid_cell_to_ve = grid_data->cell_to_vertex;
2019 size_t * grid_cell_to_ve_offests = grid_data->cell_to_vertex_offsets;
2020 size_t ** cell_to_ve_ = &cell_to_vertex;
2021 yac_int * sorted_ve_ids = sorted_vertex_ids;
2022 size_t * sorted_ve_reorder_idx = sorted_vertex_reorder_idx;
2023 size_t num_ve = num_vertices;
2024 int compact_flag;
2025
2026 for (int location = 0; location < 2; ++location) {
2027
2028 // prepare send buffer
2029 for (size_t i = 0, k = 0; i < grid_num_cells; ++i) {
2030 int curr_num_ve_per_cell = grid_num_ve_per_cell[i];
2031 size_t * curr_cell_to_ve = grid_cell_to_ve + grid_cell_to_ve_offests[i];
2032 for (int j = 0; j < curr_num_ve_per_cell; ++j, ++k)
2033 grid_id_buffer[k] = grid_ids[curr_cell_to_ve[j]];
2034 for (int j = curr_num_ve_per_cell; j < max_num_vertices_per_cell; ++j, ++k)
2035 grid_id_buffer[k] = XT_INT_MAX;
2036 }
2037
2038 // exchange data
2039 xt_redist_s_exchange1(
2040 redist_cell_yac_ints, grid_id_buffer, id_buffer);
2041
2042 if (num_vertices_per_cell == NULL) {
2043 total_num_ids = 0;
2044 compact_flag = 0;
2046 for (size_t i = 0; i < num_cells; ++i) {
2047 int vertex_count;
2049 id_buffer + i * (size_t)max_num_vertices_per_cell;
2050 for (vertex_count = 0; vertex_count < max_num_vertices_per_cell;
2051 ++vertex_count)
2052 if (vertex_ids[vertex_count] == XT_INT_MAX) break;
2053 compact_flag |= vertex_count != max_num_vertices_per_cell;
2054 num_vertices_per_cell[i] = vertex_count;
2055 total_num_ids += (size_t)vertex_count;
2056 }
2057 }
2058
2059 // compact data if necessary
2060 if (compact_flag) {
2061 for (size_t i = 0, j = 0; j < total_num_ids; ++i) {
2062 yac_int curr_id = id_buffer[i];
2063 if (curr_id != XT_INT_MAX) {
2064 id_buffer[j] = curr_id;
2065 ++j;
2066 }
2067 }
2068 }
2069
2070 // lookup local ids
2071 size_t * cell_to_ve =
2072 ((*cell_to_ve_ = xmalloc(total_num_ids * sizeof(*cell_to_ve))));
2073 id2idx(
2074 "redistribute_cell_data", id_buffer, cell_to_ve, total_num_ids,
2075 sorted_ve_ids, sorted_ve_reorder_idx, num_ve);
2076
2077 // switch to edge
2078 grid_ids = grid_data->edge_ids;
2079 grid_cell_to_ve = grid_data->cell_to_edge;
2080 grid_cell_to_ve_offests = grid_data->cell_to_edge_offsets;
2081 cell_to_ve_ = &cell_to_edge;
2082 sorted_ve_ids = sorted_edge_ids;
2083 sorted_ve_reorder_idx = sorted_edge_reorder_idx;
2084 num_ve = num_edges;
2085 }
2086
2087 free(id_buffer);
2088 }
2089
2090 // get field data
2091 struct yac_field_data * cell_field_data =
2094 redist_cell_int, redist_cell_coords, comm);
2095
2096 xt_redist_delete(redist_cell_coords);
2097 xt_redist_delete(redist_cell_yac_ints);
2098 xt_redist_delete(redist_cell_int);
2099
2100 *cell_to_vertex_ = cell_to_vertex;
2101 *cell_to_edge_ = cell_to_edge;
2102 *num_vertices_per_cell_ = num_vertices_per_cell;
2103 *cell_field_data_ = cell_field_data;
2104}
2105
2107 size_t num_cells, int max_num_vertices_per_cell, int * num_vertices_per_cell,
2108 size_t * cell_to_vertex, size_t * cell_to_vertex_offsets,
2109 yac_coordinate_pointer vertex_coordinates,
2110 size_t * cell_to_edge, size_t * cell_to_edge_offsets,
2111 enum yac_edge_type * edge_type) {
2112
2113 struct bounding_circle * cell_bnd_circles =
2114 xmalloc(num_cells * sizeof(*cell_bnd_circles));
2115 {
2116 struct yac_grid_cell cell;
2117 cell.coordinates_xyz = xmalloc((size_t)max_num_vertices_per_cell *
2118 sizeof(*(cell.coordinates_xyz)));
2119 cell.edge_type = xmalloc((size_t)max_num_vertices_per_cell *
2120 sizeof(*(cell.edge_type)));
2121
2122 for (size_t i = 0; i < num_cells; ++i) {
2123 size_t * curr_cell_to_vertex =
2124 cell_to_vertex + cell_to_vertex_offsets[i];
2125 size_t * curr_cell_to_edge =
2126 cell_to_edge + cell_to_edge_offsets[i];
2127 for (int j = 0; j < num_vertices_per_cell[i]; ++j) {
2128 yac_coordinate_pointer curr_vertex_coords =
2129 vertex_coordinates + curr_cell_to_vertex[j];
2130 for (int k = 0; k < 3; ++k)
2131 cell.coordinates_xyz[j][k] = (*curr_vertex_coords)[k];
2132 cell.edge_type[j] = edge_type[curr_cell_to_edge[j]];
2133 }
2134 cell.num_corners = num_vertices_per_cell[i];
2135 if (cell.num_corners > 0)
2136 yac_get_cell_bounding_circle(cell, cell_bnd_circles + i);
2137 else
2138 cell_bnd_circles[i] =
2139 (struct bounding_circle) {
2140 .base_vector = {1.0, 0.0, 0.0},
2141 .inc_angle = SIN_COS_ZERO,
2142 .sq_crd = DBL_MAX};
2143 }
2144 free(cell.edge_type);
2145 free(cell.coordinates_xyz);
2146 }
2147
2148 return cell_bnd_circles;
2149}
2150
2151// compute the global maximum number of vertices per cell
2152// (this is requied by various operations that require the exchange of
2153// cell data; using varying number of vertices per cell would make
2154// these exchanges much more complicated)
2156 struct yac_basic_grid_data * grid_data, MPI_Comm comm) {
2157
2158 size_t num_cells = grid_data->num_cells;
2159 int * num_vertices_per_cell = grid_data->num_vertices_per_cell;
2160 int * core_cell_mask = grid_data->core_cell_mask;
2161
2162 int max_num_vertices_per_cell = 0;
2163
2164 // if there is a core mask for cells
2165 if (core_cell_mask) {
2166 for (size_t i = 0; i < num_cells; ++i)
2167 if (core_cell_mask[i] &&
2168 (num_vertices_per_cell[i] > max_num_vertices_per_cell))
2169 max_num_vertices_per_cell = num_vertices_per_cell[i];
2170 } else {
2171 for (size_t i = 0; i < num_cells; ++i)
2172 if (num_vertices_per_cell[i] > max_num_vertices_per_cell)
2173 max_num_vertices_per_cell = num_vertices_per_cell[i];
2174 }
2175
2177 MPI_Allreduce(
2178 MPI_IN_PLACE, &max_num_vertices_per_cell, 1, MPI_INT, MPI_MAX, comm),
2179 comm);
2180
2181 return max_num_vertices_per_cell;
2182}
2183
2185 struct proc_sphere_part_node * proc_sphere_part,
2186 struct yac_basic_grid * grid, MPI_Comm comm) {
2187
2188 struct yac_basic_grid_data * grid_data = yac_basic_grid_get_data(grid);
2189
2190 int comm_rank;
2191 yac_mpi_call(MPI_Comm_rank(comm, &comm_rank), comm);
2192
2193 // compute the global maximum number of vertices per cell
2194 int max_num_vertices_per_cell =
2195 get_max_num_vertices_per_cell(grid_data, comm);
2196
2197 // check core masks for consistency
2198 // (should contain no valid cell/edge connected to an invalid edge/vertex)
2199 // and generate it if required
2200 check_core_masks(grid);
2201
2202 int * vertex_ranks; // for each vertex in the user-provided grid data this
2203 // array contains the owner in the YAC internal
2204 // decomposition
2205
2206 // generate global ids for cells/vertices/edges (if they are missing)
2208 proc_sphere_part, grid, &vertex_ranks, max_num_vertices_per_cell, comm);
2209
2210 // generate owner information for all cell/vertices/edges that may be
2211 // assigned to the local process in the YAC internal decomposition
2212 // (dist owners are sorted by global ids)
2213 struct remote_point_infos * dist_point_infos[3];
2214 yac_int * dist_global_ids[3];
2215 size_t dist_count[3];
2217 proc_sphere_part, grid, vertex_ranks, max_num_vertices_per_cell, comm,
2218 dist_point_infos, dist_global_ids, dist_count);
2219 size_t num_cells = dist_count[YAC_LOC_CELL];
2220 size_t num_vertices = dist_count[YAC_LOC_CORNER];
2221 size_t num_edges = dist_count[YAC_LOC_EDGE];
2222 yac_int * cell_ids = dist_global_ids[YAC_LOC_CELL];
2223 yac_int * vertex_ids = dist_global_ids[YAC_LOC_CORNER];
2224 yac_int * edge_ids = dist_global_ids[YAC_LOC_EDGE];
2225
2226 // generate sorted ids (the initial data is already sorted, which makes this
2227 // a simple copy)
2228 yac_int * sorted_cell_ids, * sorted_vertex_ids, * sorted_edge_ids;
2229 size_t * sorted_cell_reorder_idx, * sorted_vertex_reorder_idx,
2230 * sorted_edge_reorder_idx;
2232 cell_ids, num_cells, &sorted_cell_ids, &sorted_cell_reorder_idx);
2234 vertex_ids, num_vertices, &sorted_vertex_ids,
2235 &sorted_vertex_reorder_idx);
2237 edge_ids, num_edges, &sorted_edge_ids, &sorted_edge_reorder_idx);
2238
2239 MPI_Datatype dt_coord = yac_get_coordinate_mpi_datatype(comm);
2240
2241 // redistribute vertex information from user to
2242 // YAC internal decomposition
2243 yac_coordinate_pointer vertex_coordinates;
2244 int * vertex_owner;
2245 struct yac_field_data * vertex_field_data;
2247 grid, dist_point_infos[YAC_LOC_CORNER], num_vertices,
2248 comm, dt_coord, vertex_ranks,
2249 &vertex_coordinates, &vertex_owner, &vertex_field_data);
2250 free(vertex_ranks);
2251
2252 // redistribute edge information from user to
2253 // YAC internal decomposition
2254 yac_size_t_2_pointer edge_to_vertex;
2255 enum yac_edge_type * edge_type;
2256 struct yac_field_data * edge_field_data;
2258 grid, dist_point_infos[YAC_LOC_EDGE], num_edges, comm, dt_coord,
2259 num_vertices, sorted_vertex_ids, sorted_vertex_reorder_idx,
2260 &edge_to_vertex, &edge_type, &edge_field_data);
2261
2262 // redistribute cell information from user to
2263 // YAC internal decomposition
2264 size_t * cell_to_vertex;
2265 size_t * cell_to_edge;
2266 int * num_vertices_per_cell;
2267 struct yac_field_data * cell_field_data;
2269 grid, dist_point_infos[YAC_LOC_CELL], num_cells, comm, dt_coord,
2270 num_edges, sorted_edge_ids, sorted_edge_reorder_idx,
2271 num_vertices, sorted_vertex_ids, sorted_vertex_reorder_idx,
2272 max_num_vertices_per_cell, &cell_to_vertex, &cell_to_edge,
2273 &num_vertices_per_cell, &cell_field_data);
2274
2275 yac_mpi_call(MPI_Type_free(&dt_coord), comm);
2276
2277 // compute two support arrays
2278 size_t * cell_to_vertex_offsets =
2279 xmalloc(num_cells * sizeof(*cell_to_vertex_offsets));
2280 size_t * cell_to_edge_offsets = cell_to_vertex_offsets;
2281 for (size_t i = 0, accu = 0; i < num_cells; ++i) {
2282 cell_to_vertex_offsets[i] = accu;
2283 accu += (size_t)(num_vertices_per_cell[i]);
2284 }
2285
2286 struct yac_dist_grid dist_grid =
2287 {.comm = comm,
2288 .vertex_coordinates = vertex_coordinates,
2289 .ids = {cell_ids, vertex_ids, edge_ids},
2290 .total_count = {num_cells, num_vertices, num_edges},
2291 .count = {num_cells, num_vertices, num_edges},
2292 .num_vertices_per_cell = num_vertices_per_cell,
2293 .cell_to_vertex = cell_to_vertex,
2294 .cell_to_vertex_offsets = cell_to_vertex_offsets,
2295 .cell_to_edge = cell_to_edge,
2296 .cell_to_edge_offsets = cell_to_edge_offsets,
2297 .edge_to_vertex = edge_to_vertex,
2298 .cell_bnd_circles =
2300 num_cells, max_num_vertices_per_cell, num_vertices_per_cell,
2303 .edge_type = edge_type,
2304 .owner_mask = {NULL, NULL, NULL},
2305 .sorted_ids = {sorted_cell_ids, sorted_vertex_ids, sorted_edge_ids},
2306 .sorted_reorder_idx =
2307 {sorted_cell_reorder_idx, sorted_vertex_reorder_idx,
2308 sorted_edge_reorder_idx},
2309 .field_data =
2311 cell_field_data, vertex_field_data, edge_field_data),
2312 .owners =
2313 {dist_point_infos[YAC_LOC_CELL],
2314 dist_point_infos[YAC_LOC_CORNER],
2315 dist_point_infos[YAC_LOC_EDGE]}};
2316
2317 // mask sure that each cell/vertex/edge is valid only on one process
2318 generate_owner_masks(&dist_grid, comm_rank, vertex_owner);
2319
2320 return dist_grid;
2321}
2322
2323static void setup_search_data(struct yac_dist_grid_pair * dist_grid_pair) {
2324
2325 // build sphere part for vertices
2326 for (int i = 0; i < 2; ++i)
2327 dist_grid_pair->vertex_sphere_part[i] =
2329 dist_grid_pair->dist_grid[i].count[YAC_LOC_CORNER],
2331 (dist_grid_pair->dist_grid[i].vertex_coordinates),
2332 dist_grid_pair->dist_grid[i].ids[YAC_LOC_CORNER]);
2333
2334 // build sphere part for bounding circle of cells
2335 for (int i = 0; i < 2; ++i) {
2336 dist_grid_pair->cell_sphere_part[i] =
2338 dist_grid_pair->dist_grid[i].cell_bnd_circles,
2339 dist_grid_pair->dist_grid[i].count[YAC_LOC_CELL]);
2340 }
2341}
2342
2344 struct yac_basic_grid * grid_a, struct yac_basic_grid * grid_b,
2345 MPI_Comm comm) {
2346
2347 struct yac_basic_grid_data * grid_data[2] =
2349
2350 // gather cell centers from both grids into single array
2351 size_t num_vertices = grid_data[0]->num_vertices + grid_data[1]->num_vertices;
2352 struct dist_vertex * vertices = xmalloc(num_vertices * sizeof(*vertices));
2353 for (size_t i = 0, k = 0; i < 2; ++i) {
2354 yac_coordinate_pointer vertex_coordinates = grid_data[i]->vertex_coordinates;
2355 for (size_t j = 0; j < grid_data[i]->num_vertices; ++j, ++k)
2356 memcpy(
2357 vertices[k].coord, vertex_coordinates[j], sizeof(*vertex_coordinates));
2358 }
2359
2360 // redistribute all cell centers and build parallel sphere
2361 // part for vertices
2362 struct proc_sphere_part_node * proc_sphere_part =
2363 yac_redistribute_vertices(&vertices, &num_vertices, comm);
2364
2365 free(vertices);
2366
2367 return proc_sphere_part;
2368}
2369
2371 struct yac_basic_grid * grid_a, struct yac_basic_grid * grid_b,
2372 MPI_Comm comm) {
2373
2374 char const * routine = "yac_dist_grid_pair_new";
2375
2377 grid_a, "ERROR(%s): NULL is not a valid value for parameter grid_a",
2378 routine)
2380 grid_b, "ERROR(%s): NULL is not a valid value for parameter grid_b",
2381 routine)
2382
2384 strcmp(yac_basic_grid_get_name(grid_a), yac_basic_grid_get_name(grid_b)),
2385 "ERROR(%s): identical grid names", routine)
2386
2387 MPI_Comm comm_copy;
2388 yac_mpi_call(MPI_Comm_dup(comm, &comm_copy), comm);
2389 comm = comm_copy;
2390
2391 // ensure same grid ordering on all processes
2392 if (strcmp(yac_basic_grid_get_name(grid_a),
2393 yac_basic_grid_get_name(grid_b)) > 0) {
2394 struct yac_basic_grid * grid_swap = grid_a;
2395 grid_a = grid_b;
2396 grid_b = grid_swap;
2397 }
2398
2399 struct yac_dist_grid_pair * grid_pair = xmalloc(1 * sizeof(*grid_pair));
2400
2401 grid_pair->grid_names[0] = strdup(yac_basic_grid_get_name(grid_a));
2402 grid_pair->grid_names[1] = strdup(yac_basic_grid_get_name(grid_b));
2403 grid_pair->comm = comm;
2404
2405 // generate a decomposition for the distributed grid pair
2406 // with the following properties:
2407 // * each process covers a unique area on the sphere
2408 // * number of cells (from grid_a and/or grid_b) per area
2409 // is roughly the same
2410 grid_pair->proc_sphere_part =
2411 generate_dist_grid_decomposition(grid_a, grid_b, comm);
2412
2413 // redistribute grid_a and grid_b according to decomposition
2414 grid_pair->dist_grid[0] =
2415 generate_dist_grid(grid_pair->proc_sphere_part, grid_a, comm);
2416 grid_pair->dist_grid[1] =
2417 generate_dist_grid(grid_pair->proc_sphere_part, grid_b, comm);
2418
2419 // build search data structures for local cells and vertices in
2420 // distributed grid
2421 setup_search_data(grid_pair);
2422
2423 return grid_pair;
2424}
2425
2427 struct yac_basic_grid * grid_a, struct yac_basic_grid * grid_b,
2428 MPI_Fint comm) {
2429
2430 return
2431 yac_dist_grid_pair_new(grid_a, grid_b, MPI_Comm_f2c(comm));
2432}
2433
2435 struct yac_dist_grid_pair * grid_pair) {
2436 return grid_pair->comm;
2437}
2438
2440 struct yac_dist_grid_pair * grid_pair, char const * grid_name) {
2441
2442 struct yac_dist_grid * dist_grid = NULL;
2443 for (int i = 0; (i < 2) && (dist_grid == NULL); ++i)
2444 if (!strcmp(grid_name, grid_pair->grid_names[i]))
2445 dist_grid = &(grid_pair->dist_grid[i]);
2446 YAC_ASSERT(
2447 dist_grid, "ERROR(yac_dist_grid_pair_get_dist_grid): invalid grid_name")
2448 return dist_grid;
2449}
2450
2452 struct yac_dist_grid * dist_grid) {
2453
2454 return (struct yac_const_basic_grid_data *)dist_grid;
2455}
2456
2457// return the number of cells/vertex/edges in the distributed directoy that
2458// are owned by the local process
2460 struct yac_dist_grid * dist_grid, enum yac_location location) {
2461
2462 CHECK_LOCATION("yac_dist_grid_get_local_count")
2463 size_t local_count = 0;
2464 size_t count = dist_grid->count[location];
2465 int * owner_mask = dist_grid->owner_mask[location];
2466 for (size_t i = 0; i < count; ++i) if (owner_mask[i]) ++local_count;
2467 return local_count;
2468}
2469
2470// returns the current number of cells/vertices/edges in the local
2471// part of the distributed directory (may increase over time, if the local
2472// has to be extended in order to contain external search results)
2474 struct yac_dist_grid * dist_grid, enum yac_location location) {
2475
2476 CHECK_LOCATION("yac_dist_grid_get_total_count")
2477 size_t * total_count = dist_grid->total_count;
2478 return total_count[location];
2479}
2480
2481// returns the original number of cells/vertices/edges in the local
2482// part of the distributed directory
2484 struct yac_dist_grid * dist_grid, enum yac_location location) {
2485
2486 CHECK_LOCATION("yac_dist_grid_get_count")
2487 size_t * count = dist_grid->count;
2488 return count[location];
2489}
2490
2492 struct yac_dist_grid * dist_grid, enum yac_location location) {
2493
2494 CHECK_LOCATION("yac_dist_grid_get_owner_mask")
2495 int ** owner_mask = dist_grid->owner_mask;
2496 return owner_mask[location];
2497}
2498
2500 struct yac_dist_grid * dist_grid, enum yac_location location) {
2501
2502 CHECK_LOCATION("yac_dist_grid_get_global_ids")
2503 yac_int ** ids = dist_grid->ids;
2504 return ids[location];
2505}
2506
2507// returns local ids of all points in the distributed directory of the
2508// provided fields that are owned by the local process and are not masked
2509// out by the field
2511 struct yac_dist_grid * dist_grid, struct yac_interp_field field,
2512 size_t ** indices, size_t * num_indices) {
2513
2514 int const * field_mask = yac_dist_grid_get_field_mask(dist_grid, field);
2515
2516 size_t count = yac_dist_grid_get_count(dist_grid, field.location);
2517 int const * owner_mask =
2518 yac_dist_grid_get_owner_mask(dist_grid, field.location);
2519
2520 size_t * temp_indices = xmalloc(count * sizeof(*temp_indices));
2521
2522 size_t num_indices_ = 0;
2523
2524 if (field_mask != NULL) {
2525 for (size_t i = 0; i < count; ++i)
2526 if (owner_mask[i] && field_mask[i]) temp_indices[num_indices_++] = i;
2527 } else {
2528 for (size_t i = 0; i < count; ++i)
2529 if (owner_mask[i]) temp_indices[num_indices_++] = i;
2530 }
2531
2532 *indices = xrealloc(temp_indices, num_indices_ * sizeof(**indices));
2533 *num_indices = num_indices_;
2534}
2535
2537 struct yac_dist_grid * dist_grid, enum yac_location location) {
2538
2539 return
2540 yac_field_data_set_get_field_data(dist_grid->field_data, location);
2541}
2542
2544 struct yac_dist_grid * dist_grid, struct yac_interp_field field) {
2545
2546 if (field.masks_idx == SIZE_MAX) return NULL;
2547
2548 return
2549 (field.masks_idx != SIZE_MAX)?
2551 yac_dist_grid_get_field_data(dist_grid, field.location),
2552 field.masks_idx):NULL;
2553}
2554
2556 struct yac_dist_grid * dist_grid, struct yac_interp_field field) {
2557
2559 (field.coordinates_idx != SIZE_MAX)?
2561 yac_dist_grid_get_field_data(dist_grid, field.location),
2562 field.coordinates_idx):NULL;
2563
2564 // if no field coordinates are defined, but the location is at the corners of
2565 // of the grid cells, return coordinates of them
2566 return
2567 ((coords != NULL) || (field.location != YAC_LOC_CORNER))?
2568 coords:((yac_const_coordinate_pointer)(dist_grid->vertex_coordinates));
2569}
2570
2572 struct yac_dist_grid * dist_grid, struct yac_interp_field field) {
2573
2574 size_t count =
2575 yac_dist_grid_get_count(dist_grid, field.location);
2576
2577 int const * field_mask = yac_dist_grid_get_field_mask(dist_grid, field);
2578 if (field_mask == NULL)
2579 return yac_dist_grid_get_local_count(dist_grid, field.location);
2580
2581 int const * owner_mask =
2582 yac_dist_grid_get_owner_mask(dist_grid, field.location);
2583
2584 size_t unmasked_local_count = 0;
2585 for (size_t i = 0; i < count; ++i)
2586 if (owner_mask[i] && field_mask[i]) ++unmasked_local_count;
2587 return unmasked_local_count;
2588}
2589
2591 struct remote_point_infos * point_infos, size_t count) {
2592
2593 for (size_t i = 0; i < count; ++i)
2594 if (point_infos[i].count > 1) free(point_infos[i].data.multi);
2595 free(point_infos);
2596}
2597
2598static void yac_dist_grid_free(struct yac_dist_grid grid) {
2599
2600 free(grid.vertex_coordinates);
2601 free(grid.num_vertices_per_cell);
2602 free(grid.cell_to_vertex);
2603 free(grid.cell_to_vertex_offsets);
2604 free(grid.cell_to_edge);
2605 free(grid.cell_bnd_circles);
2606 free(grid.edge_type);
2607 free(grid.edge_to_vertex);
2608 for (int i = 0; i < 3; ++i) {
2609 free(grid.ids[i]);
2610 free(grid.owner_mask[i]);
2611 free(grid.sorted_ids[i]);
2612 free(grid.sorted_reorder_idx[i]);
2614 }
2616}
2617
2619
2620 if (grid_pair == NULL) return;
2621 free(grid_pair->grid_names[0]);
2622 free(grid_pair->grid_names[1]);
2623 yac_mpi_call(MPI_Comm_free(&(grid_pair->comm)), MPI_COMM_WORLD);
2625 for (int i = 0; i < 2; ++i) {
2626 yac_dist_grid_free(grid_pair->dist_grid[i]);
2629 }
2630 free(grid_pair);
2631}
2632
2633static int coord_in_cell(
2634 double coord[3], struct yac_dist_grid * dist_grid,
2635 size_t cell_idx, struct yac_grid_cell * buffer_cell) {
2636
2638 (struct yac_const_basic_grid_data *)dist_grid, cell_idx, buffer_cell);
2639
2640 return
2642 coord, *buffer_cell, dist_grid->cell_bnd_circles[cell_idx]);
2643}
2644
2646 double coord[3], struct yac_dist_grid * dist_grid,
2647 size_t cell_idx, struct yac_grid_cell * buffer_cell) {
2648
2650 (struct yac_const_basic_grid_data *)dist_grid, cell_idx, buffer_cell);
2651 for (size_t i = 0; i < buffer_cell->num_corners; ++i)
2652 buffer_cell->edge_type[i] = YAC_GREAT_CIRCLE_EDGE;
2653
2654 return
2656 coord, *buffer_cell, dist_grid->cell_bnd_circles[cell_idx]);
2657}
2658
2660 struct yac_const_basic_grid_data * grid_data, size_t cell_idx,
2661 struct yac_grid_cell * buffer_cell) {
2662
2663 size_t num_vertices = (size_t)(grid_data->num_vertices_per_cell[cell_idx]);
2664
2665 struct yac_grid_cell cell = *buffer_cell;
2666
2667 if (cell.array_size < num_vertices) {
2668 cell.coordinates_xyz =
2669 xrealloc(cell.coordinates_xyz, num_vertices *
2670 sizeof(*(cell.coordinates_xyz)));
2671 cell.edge_type = xrealloc(cell.edge_type, num_vertices *
2672 sizeof(*(cell.edge_type)));
2673 cell.array_size = num_vertices;
2674 *buffer_cell = cell;
2675 }
2676
2677 for (size_t i = 0; i < num_vertices; ++i) {
2678 size_t vertex_idx =
2679 grid_data->cell_to_vertex[
2680 grid_data->cell_to_vertex_offsets[cell_idx] + i];
2681 cell.coordinates_xyz[i][0] = grid_data->vertex_coordinates[vertex_idx][0];
2682 cell.coordinates_xyz[i][1] = grid_data->vertex_coordinates[vertex_idx][1];
2683 cell.coordinates_xyz[i][2] = grid_data->vertex_coordinates[vertex_idx][2];
2684 size_t edge_idx =
2685 grid_data->cell_to_edge[grid_data->cell_to_edge_offsets[cell_idx] + i];
2686 cell.edge_type[i] = grid_data->edge_type[edge_idx];
2687 }
2688 buffer_cell->num_corners = num_vertices;
2689}
2690
2692 struct yac_dist_grid_pair * grid_pair, char const * grid_name) {
2693
2694 struct bnd_sphere_part_search * search = NULL;
2695
2696 for (int i = 0; (i < 2) && (search == NULL); ++i)
2697 if (!strcmp(grid_name, grid_pair->grid_names[i]))
2698 search = grid_pair->cell_sphere_part[i];
2699 YAC_ASSERT(
2700 search != NULL,
2701 "ERROR(yac_dist_grid_pair_get_cell_sphere_part): invalid grid_name")
2702 return search;
2703}
2704
2706 struct yac_dist_grid_pair * grid_pair, char const * grid_name,
2707 yac_coordinate_pointer search_coords, size_t count, size_t * cells,
2708 int (*coord_in_cell)(
2709 double coord[3], struct yac_dist_grid * dist_grid, size_t cell_idx,
2710 struct yac_grid_cell * buffer_cell)) {
2711
2712 struct bnd_sphere_part_search * cell_sphere_part =
2713 dist_grid_pair_get_cell_sphere_part(grid_pair, grid_name);
2714 struct yac_dist_grid * dist_grid =
2715 yac_dist_grid_pair_get_dist_grid(grid_pair, grid_name);
2716
2717 size_t * temp_cells;
2718 size_t * num_cells_per_coord =
2719 xmalloc(count * sizeof(*num_cells_per_coord));
2720
2721 // search for all matching source cells
2723 cell_sphere_part, search_coords, count, &temp_cells,
2724 num_cells_per_coord);
2725
2726 struct yac_grid_cell buffer_cell;
2727 yac_init_grid_cell(&buffer_cell);
2728
2729 // if we have multiple source cells for a single search coordinate, get the
2730 // source cell with the lowest global id
2731 for (size_t i = 0, k = 0; i < count; ++i) {
2732 size_t curr_num_cells = num_cells_per_coord[i];
2733 if (curr_num_cells == 0) {
2734 cells[i] = SIZE_MAX;
2735 } else if (curr_num_cells == 1) {
2736 if (coord_in_cell(
2737 search_coords[i], dist_grid, temp_cells[k], &buffer_cell))
2738 cells[i] = temp_cells[k];
2739 else
2740 cells[i] = SIZE_MAX;
2741 ++k;
2742 } else {
2743 size_t cell_idx = SIZE_MAX;
2744 yac_int cell_id = XT_INT_MAX;
2745 for (size_t j = 0; j < curr_num_cells; ++j, ++k) {
2746 size_t curr_cell_idx = temp_cells[k];
2747 yac_int curr_cell_id = dist_grid->ids[YAC_LOC_CELL][curr_cell_idx];
2748 if (!coord_in_cell(
2749 search_coords[i], dist_grid, curr_cell_idx, &buffer_cell))
2750 continue;
2751 if (curr_cell_id < cell_id) {
2752 cell_idx = curr_cell_idx;
2753 cell_id = curr_cell_id;
2754 }
2755 }
2756 cells[i] = cell_idx;
2757 }
2758 }
2759
2760 yac_free_grid_cell(&buffer_cell);
2761 free(num_cells_per_coord);
2762 free(temp_cells);
2763}
2764
2766 struct yac_dist_grid * dist_grid, enum yac_location location,
2767 struct single_remote_point_reorder * ids, size_t * count, size_t * idx) {
2768
2769 CHECK_LOCATION("lookup_single_remote_point_reorder_locally")
2770
2771 yac_int * sorted_ids = dist_grid->sorted_ids[location];
2772 size_t * reorder_idx = dist_grid->sorted_reorder_idx[location];
2773 size_t num_ids = dist_grid->total_count[location];
2774
2775 size_t count_ = *count;
2776 size_t new_count = 0;
2777
2778 // sort ids by global ids
2779 qsort(ids, count_, sizeof(*ids),
2781
2782 for (size_t i = 0, j = 0; i < count_; ++i) {
2783 yac_int curr_id = ids[i].data.global_id;
2784 while ((j < num_ids) && (sorted_ids[j] < curr_id)) ++j;
2785 if ((j < num_ids) && (sorted_ids[j] == curr_id)) {
2786 idx[ids[i].reorder_idx] = reorder_idx[j];
2787 } else {
2788 if (i != new_count) ids[new_count] = ids[i];
2789 ++new_count;
2790 }
2791 }
2792
2793 *count = new_count;
2794}
2795
2797 struct yac_field_data * field_data, MPI_Comm comm) {
2798
2799 int pack_size_field_coord, pack_size_field_mask;
2800
2802 MPI_Pack_size(3, MPI_DOUBLE, comm, &pack_size_field_coord), comm);
2803 pack_size_field_coord *=
2804 (int)yac_field_data_get_coordinates_count(field_data);
2805
2807 MPI_Pack_size(1, MPI_INT, comm, &pack_size_field_mask), comm);
2808 pack_size_field_mask *=
2809 (int)yac_field_data_get_masks_count(field_data);
2810
2811 return pack_size_field_coord + pack_size_field_mask;
2812}
2813
2815 struct yac_field_data * cell_field_data,
2816 MPI_Datatype bnd_circle_dt, MPI_Comm comm) {
2817
2818 int pack_size_id,
2819 pack_size_num_vertices,
2820 pack_size_bnd_circle;
2821
2822 // id
2823 yac_mpi_call(MPI_Pack_size(1, yac_int_dt, comm, &pack_size_id), comm);
2824 // num_vertices
2825 yac_mpi_call(MPI_Pack_size(1, MPI_INT, comm, &pack_size_num_vertices), comm);
2826 // bounding circle
2828 MPI_Pack_size(1, bnd_circle_dt, comm, &pack_size_bnd_circle), comm);
2829
2830 return pack_size_id + pack_size_num_vertices + pack_size_bnd_circle +
2831 get_pack_size_field_data(cell_field_data, comm);
2832}
2833
2835 struct yac_field_data * vertex_field_data, MPI_Comm comm) {
2836
2837 int pack_size_id,
2838 pack_size_vertex_coords;
2839 // id
2840 yac_mpi_call(MPI_Pack_size(1, yac_int_dt, comm, &pack_size_id), comm);
2841 // vertex coordinates
2843 MPI_Pack_size(3, MPI_DOUBLE, comm, &pack_size_vertex_coords), comm);
2844
2845 return pack_size_id + pack_size_vertex_coords +
2846 get_pack_size_field_data(vertex_field_data, comm);
2847}
2848
2850 struct yac_field_data * edge_field_data, MPI_Comm comm) {
2851
2852 int pack_size_id,
2853 pack_size_edge_to_vertex,
2854 pack_size_edge_type;
2855 // id
2856 yac_mpi_call(MPI_Pack_size(1, yac_int_dt, comm, &pack_size_id), comm);
2857 // edge type
2858 yac_mpi_call(MPI_Pack_size(1, MPI_INT, comm, &pack_size_edge_type), comm);
2859 // edge vertex ids
2861 MPI_Pack_size(2, yac_int_dt, comm, &pack_size_edge_to_vertex), comm);
2862
2863 return pack_size_id + pack_size_edge_type + pack_size_edge_to_vertex +
2864 get_pack_size_field_data(edge_field_data, comm);
2865}
2866
2868 struct yac_dist_grid * dist_grid, uint64_t * pos, size_t count,
2869 int * pack_sizes, MPI_Datatype bnd_circle_dt, MPI_Datatype point_info_dt,
2870 MPI_Comm comm) {
2871
2872 int pack_size_base_cell =
2875 dist_grid->field_data, YAC_LOC_CELL),
2876 bnd_circle_dt, comm);
2877 int pack_size_base_vertex =
2880 dist_grid->field_data, YAC_LOC_CORNER), comm);
2881 int pack_size_base_edge =
2884 dist_grid->field_data, YAC_LOC_EDGE), comm);
2885
2886 for (size_t i = 0; i < count; ++i) {
2887 size_t idx = (size_t)(pos[i]);
2888 int num_vertices = dist_grid->num_vertices_per_cell[idx];
2889 size_t * curr_vertices =
2890 dist_grid->cell_to_vertex + dist_grid->cell_to_vertex_offsets[idx];
2891 size_t * curr_edges =
2892 dist_grid->cell_to_edge + dist_grid->cell_to_edge_offsets[idx];
2893 int pack_size =
2894 pack_size_base_cell +
2895 num_vertices * (pack_size_base_vertex + pack_size_base_edge) +
2897 dist_grid->owners[YAC_LOC_CELL] + idx, point_info_dt, comm);
2898 for (int j = 0; j < num_vertices; ++j) {
2899 pack_size +=
2901 dist_grid->owners[YAC_LOC_CORNER] + curr_vertices[j],
2902 point_info_dt, comm) +
2904 dist_grid->owners[YAC_LOC_EDGE] + curr_edges[j], point_info_dt, comm);
2905 }
2906 pack_sizes[i] = pack_size;
2907 }
2908}
2909
2911 struct yac_dist_grid * dist_grid, uint64_t * pos, size_t count,
2912 int * pack_sizes, MPI_Datatype point_info_dt, MPI_Comm comm) {
2913
2914 int pack_size_base_vertex =
2917 dist_grid->field_data, YAC_LOC_CORNER), comm);
2918 for (size_t i = 0; i < count; ++i)
2919 pack_sizes[i] =
2920 pack_size_base_vertex +
2922 dist_grid->owners[YAC_LOC_CORNER] + pos[i], point_info_dt, comm);
2923}
2924
2926 struct yac_dist_grid * dist_grid, uint64_t * pos, size_t count,
2927 int * pack_sizes, MPI_Datatype point_info_dt, MPI_Comm comm) {
2928
2929 int pack_size_base_vertex =
2932 dist_grid->field_data, YAC_LOC_CORNER), comm);
2933 int pack_size_base_edge =
2936 dist_grid->field_data, YAC_LOC_EDGE), comm);
2937 for (size_t i = 0; i < count; ++i) {
2938 size_t * curr_vertices = dist_grid->edge_to_vertex[pos[i]];
2939 pack_sizes[i] =
2940 pack_size_base_edge +
2941 2 * pack_size_base_vertex +
2943 dist_grid->owners[YAC_LOC_EDGE] + pos[i], point_info_dt, comm) +
2945 dist_grid->owners[YAC_LOC_CORNER] + curr_vertices[0],
2946 point_info_dt, comm) +
2948 dist_grid->owners[YAC_LOC_CORNER] + curr_vertices[1],
2949 point_info_dt, comm);
2950 }
2951}
2952
2953static void get_pack_sizes(
2954 struct yac_dist_grid * dist_grid, enum yac_location location, uint64_t * pos,
2955 size_t count, int * pack_sizes, MPI_Datatype bnd_circle_dt,
2956 MPI_Datatype point_info_dt, MPI_Comm comm) {
2957
2958 CHECK_LOCATION("get_pack_sizes")
2959
2960 switch(location) {
2961 default:
2962 case(YAC_LOC_CELL):
2964 dist_grid, pos, count, pack_sizes, bnd_circle_dt, point_info_dt, comm);
2965 break;
2966 case(YAC_LOC_CORNER):
2968 dist_grid, pos, count, pack_sizes, point_info_dt, comm);
2969 break;
2970 case(YAC_LOC_EDGE):
2972 dist_grid, pos, count, pack_sizes, point_info_dt, comm);
2973 break;
2974 };
2975}
2976
2978 size_t idx, void * buffer, int buffer_size, int * position,
2979 struct yac_field_data * field_data, MPI_Comm comm) {
2980
2981 size_t coordinates_count =
2983 size_t masks_count =
2985
2986 // coordinates
2987 for (size_t i = 0; i < coordinates_count; ++i)
2989 MPI_Pack(
2990 yac_field_data_get_coordinates_data(field_data, i)[idx],
2991 3, MPI_DOUBLE, buffer, buffer_size, position, comm), comm);
2992
2993 // masks
2994 for (size_t i = 0; i < masks_count; ++i)
2996 MPI_Pack(
2997 yac_field_data_get_mask_data(field_data, i) + idx, 1, MPI_INT, buffer,
2998 buffer_size, position, comm), comm);
2999}
3000
3002 struct yac_dist_grid * dist_grid, size_t idx, void * buffer, int buffer_size,
3003 int * position, MPI_Datatype bnd_circle_dt, MPI_Datatype point_info_dt,
3004 MPI_Comm comm) {
3005
3006 UNUSED(bnd_circle_dt);
3007
3008 // id
3010 MPI_Pack(dist_grid->ids[YAC_LOC_CORNER] + idx, 1, yac_int_dt, buffer, buffer_size,
3011 position, comm), comm);
3012 // vertex coordinates
3014 MPI_Pack(&(dist_grid->vertex_coordinates[idx][0]), 3, MPI_DOUBLE, buffer,
3015 buffer_size, position, comm), comm);
3016 // vertex owner
3018 dist_grid->owners[YAC_LOC_CORNER] + idx, buffer, buffer_size, position,
3019 point_info_dt, comm);
3020 // pack field data
3022 idx, buffer, buffer_size, position,
3024}
3025
3027 struct yac_dist_grid * dist_grid, size_t idx, void * buffer, int buffer_size,
3028 int * position, MPI_Datatype bnd_circle_dt, MPI_Datatype point_info_dt,
3029 MPI_Comm comm) {
3030
3031 UNUSED(bnd_circle_dt);
3032
3033 int edge_type = (int)(dist_grid->edge_type[idx]);
3034
3035 // id
3037 MPI_Pack(
3038 dist_grid->ids[YAC_LOC_EDGE] + idx, 1, yac_int_dt, buffer, buffer_size, position,
3039 comm), comm);
3040 // edge type
3042 MPI_Pack(
3043 &edge_type, 1, MPI_INT, buffer, buffer_size, position, comm), comm);
3044 // edge to vertex
3045 yac_int edge_to_vertex[2] = {
3046 dist_grid->ids[YAC_LOC_CORNER][dist_grid->edge_to_vertex[idx][0]],
3047 dist_grid->ids[YAC_LOC_CORNER][dist_grid->edge_to_vertex[idx][1]]};
3049 MPI_Pack(
3050 edge_to_vertex, 2, yac_int_dt, buffer, buffer_size, position, comm),
3051 comm);
3052 // edge owner
3054 dist_grid->owners[YAC_LOC_EDGE] + idx, buffer, buffer_size, position,
3055 point_info_dt, comm);
3056 // pack field data
3058 idx, buffer, buffer_size, position,
3060}
3061
3063 struct yac_dist_grid * dist_grid, size_t idx, void * buffer, int buffer_size,
3064 int * position, MPI_Datatype bnd_circle_dt, MPI_Datatype point_info_dt,
3065 MPI_Comm comm) {
3066
3068 dist_grid, idx, buffer, buffer_size, position,
3069 bnd_circle_dt, point_info_dt, comm);
3070
3071 // pack edge vertices
3072 for (int i = 0; i < 2; ++i)
3074 dist_grid, dist_grid->edge_to_vertex[idx][i],
3075 buffer, buffer_size, position, bnd_circle_dt, point_info_dt, comm);
3076}
3077
3079 struct yac_dist_grid * dist_grid, size_t idx, void * buffer, int buffer_size,
3080 int * position, MPI_Datatype bnd_circle_dt, MPI_Datatype point_info_dt,
3081 MPI_Comm comm) {
3082
3083 int num_vertices = dist_grid->num_vertices_per_cell[idx];
3084
3085 // id
3087 MPI_Pack(
3088 dist_grid->ids[YAC_LOC_CELL] + idx, 1, yac_int_dt, buffer, buffer_size, position,
3089 comm), comm);
3090 // pack field data
3092 idx, buffer, buffer_size, position,
3094 // num_vertices
3096 MPI_Pack(&num_vertices, 1, MPI_INT, buffer,
3097 buffer_size, position, comm), comm);
3098 // bounding_circle
3100 MPI_Pack(dist_grid->cell_bnd_circles + idx, 1, bnd_circle_dt, buffer,
3101 buffer_size, position, comm), comm);
3102 // cell owner
3104 dist_grid->owners[YAC_LOC_CELL] + idx, buffer, buffer_size, position,
3105 point_info_dt, comm);
3106
3107 for (int i = 0; i < num_vertices; ++i) {
3109 dist_grid,
3110 dist_grid->cell_to_vertex[dist_grid->cell_to_vertex_offsets[idx] + i],
3111 buffer, buffer_size, position, bnd_circle_dt, point_info_dt, comm);
3113 dist_grid,
3114 dist_grid->cell_to_edge[dist_grid->cell_to_edge_offsets[idx] + i],
3115 buffer, buffer_size, position, bnd_circle_dt, point_info_dt, comm);
3116 }
3117}
3118
3119static void pack_grid_data(
3120 struct yac_dist_grid * dist_grid, enum yac_location location, uint64_t * pos,
3121 size_t count, void ** pack_data, int * pack_sizes,
3122 MPI_Datatype bnd_circle_dt, MPI_Datatype point_info_dt, MPI_Comm comm) {
3123
3124 get_pack_sizes(dist_grid, location, pos, count, pack_sizes,
3125 bnd_circle_dt, point_info_dt, comm);
3126
3127 size_t pack_size = 0;
3128 for (size_t i = 0; i < count; ++i) pack_size += (size_t)(pack_sizes[i]);
3129
3130 void * pack_data_ = xmalloc(pack_size);
3131
3132 CHECK_LOCATION("pack_grid_data")
3133
3134 void (*func_pack[3])(
3135 struct yac_dist_grid * dist_grid, size_t idx, void * buffer,
3136 int buffer_size, int * position, MPI_Datatype bnd_circle_dt,
3137 MPI_Datatype point_info_dt, MPI_Comm comm) =
3139
3140 for (size_t i = 0, offset = 0; i < count; ++i) {
3141 int position = 0;
3142 func_pack[location](
3143 dist_grid, pos[i], (char*)pack_data_ + offset, pack_sizes[i],
3144 &position, bnd_circle_dt, point_info_dt, comm);
3145 pack_sizes[i] = position;
3146 offset += (size_t)position;
3147 }
3148
3149 *pack_data = pack_data_;
3150}
3151
3153 void * buffer, int buffer_size, int * position, size_t idx,
3154 struct temp_field_data temp_field_data, MPI_Comm comm) {
3155
3156 for (size_t i = 0; i < temp_field_data.coordinates_count; ++i)
3158 MPI_Unpack(
3159 buffer, buffer_size, position, temp_field_data.coordinates[i][idx],
3160 3, MPI_DOUBLE, comm), comm);
3161
3162 for (size_t i = 0; i < temp_field_data.masks_count; ++i)
3164 MPI_Unpack(buffer, buffer_size, position,
3165 temp_field_data.masks[i] + idx, 1, MPI_INT, comm), comm);
3166}
3167
3169 struct global_vertex_reorder * vertex, size_t idx, void * buffer,
3170 int buffer_size, int * position,
3171 struct temp_field_data temp_vertex_field_data,
3172 MPI_Datatype point_info_dt, MPI_Comm comm) {
3173
3174 // id
3176 MPI_Unpack(buffer, buffer_size, position, &(vertex[idx].global_id), 1,
3177 yac_int_dt, comm), comm);
3178 // vertex coordinates
3180 MPI_Unpack(buffer, buffer_size, position, &(vertex[idx].coord[0]), 3,
3181 MPI_DOUBLE, comm), comm);
3182 // vertex owners
3184 buffer, buffer_size, position, &(vertex[idx].owners), point_info_dt, comm);
3185 // unpack field data
3187 buffer, buffer_size, position, idx, temp_vertex_field_data, comm);
3188}
3189
3191 struct global_edge_reorder * edge, size_t idx, void * buffer,
3192 int buffer_size, int * position,
3193 struct temp_field_data temp_edge_field_data,
3194 MPI_Datatype point_info_dt, MPI_Comm comm) {
3195
3196 int edge_type;
3197
3198 // id
3200 MPI_Unpack(buffer, buffer_size, position, &(edge[idx].global_id), 1,
3201 yac_int_dt, comm), comm);
3202 // edge type
3204 MPI_Unpack(buffer, buffer_size, position, &edge_type, 1,
3205 MPI_INT, comm), comm);
3206 edge[idx].edge_type = (enum yac_edge_type)edge_type;
3207 // edge to vertex
3209 MPI_Unpack(buffer, buffer_size, position, edge[idx].edge_to_vertex, 2,
3210 yac_int_dt, comm), comm);
3211 // edge owners
3212 yac_remote_point_infos_unpack(buffer, buffer_size, position,
3213 &(edge[idx].owners), point_info_dt, comm);
3214 // unpack field data
3216 buffer, buffer_size, position, idx, temp_edge_field_data, comm);
3217}
3218
3220 const void * a, const void * b) {
3221
3222 return (((const struct global_vertex_reorder *)a)->global_id >
3223 ((const struct global_vertex_reorder *)b)->global_id) -
3224 (((const struct global_vertex_reorder *)a)->global_id <
3225 ((const struct global_vertex_reorder *)b)->global_id);
3226}
3227
3228static void add_field_data(
3229 struct yac_field_data * field_data, struct temp_field_data temp_field_data,
3230 void * reorder_idx, size_t reorder_idx_size,
3231 size_t old_count, size_t new_count) {
3232
3233 size_t add_count = new_count - old_count;
3234
3235 for (size_t i = 0; i < temp_field_data.masks_count; ++i) {
3236 int * temp_mask = temp_field_data.masks[i];
3237 int * mask =
3238 xrealloc(
3239 (void*)yac_field_data_get_mask_data(field_data, i),
3240 new_count * sizeof(*mask));
3241 yac_field_data_set_mask_data(field_data, i, mask);
3242 for (size_t i = 0, j = old_count; i < add_count; ++i, ++j) {
3243 size_t idx =
3244 *(size_t*)((unsigned char*)reorder_idx + i * reorder_idx_size);
3245 mask[j] = temp_mask[idx];
3246 }
3247 }
3248
3249 for (size_t i = 0; i < temp_field_data.coordinates_count; ++i) {
3251 yac_coordinate_pointer coordinates =
3252 xrealloc(
3253 (void*)yac_field_data_get_coordinates_data(field_data, i),
3254 new_count * sizeof(*coordinates));
3255 yac_field_data_set_coordinates_data(field_data, i, coordinates);
3256 for (size_t i = 0, j = old_count; i < add_count; ++i, ++j) {
3257 size_t idx =
3258 *(size_t*)((unsigned char*)reorder_idx + i * reorder_idx_size);
3259 coordinates[j][0] = temp_coordinates[idx][0];
3260 coordinates[j][1] = temp_coordinates[idx][1];
3261 coordinates[j][2] = temp_coordinates[idx][2];
3262 }
3263 }
3264}
3265
3267 struct remote_point_infos * point_infos) {
3268
3269 if (point_infos->count > 1) free(point_infos->data.multi);
3270}
3271
3273 struct yac_dist_grid * dist_grid, struct global_vertex_reorder * vertices,
3274 size_t count, size_t * idx,
3275 struct temp_field_data temp_vertex_field_data) {
3276
3277 if (count == 0) return;
3278
3279 // sort vertices global ids
3280 qsort(vertices, count, sizeof(*vertices),
3282
3283 yac_int * sorted_vertex_ids =
3284 dist_grid->sorted_ids[YAC_LOC_CORNER];
3285 size_t * sorted_vertex_reorder_idx =
3287
3288 yac_int prev_global_id = vertices[0].global_id - 1;
3289 size_t prev_idx = 0;
3290 size_t add_count = 0;
3291 size_t num_total_vertices = dist_grid->total_count[YAC_LOC_CORNER];
3292
3293 // determine which vertices need to be added to local data
3294 for (size_t i = 0, j = 0; i < count; ++i) {
3295
3296 yac_int curr_global_id = vertices[i].global_id;
3297 size_t curr_reorder_idx = vertices[i].reorder_idx;
3298
3299 // if the current global id is a duplicate
3300 if (prev_global_id == curr_global_id) {
3301 if (idx != NULL) idx[curr_reorder_idx] = prev_idx;
3303 continue;
3304 }
3305 prev_global_id = curr_global_id;
3306
3307 // check whether the current global id is already part of the local
3308 // grid data
3309 while ((j < num_total_vertices) && (sorted_vertex_ids[j] < curr_global_id))
3310 ++j;
3311
3312 // if we found a match in the local data
3313 if ((j < num_total_vertices) && (sorted_vertex_ids[j] == curr_global_id)) {
3314
3315 if (idx != NULL) idx[curr_reorder_idx] = sorted_vertex_reorder_idx[j];
3316 prev_idx = sorted_vertex_reorder_idx[j];
3318
3319 // if we need to add the current vertex to the local data
3320 } else {
3321
3322 if (idx != NULL) idx[curr_reorder_idx] = num_total_vertices + add_count;
3323 prev_idx = num_total_vertices + add_count;
3324 if (add_count != i) vertices[add_count] = vertices[i];
3325 ++add_count;
3326 }
3327 }
3328
3329 size_t new_num_total_vertices = num_total_vertices + add_count;
3330 yac_coordinate_pointer vertex_coordinates =
3331 xrealloc(dist_grid->vertex_coordinates, new_num_total_vertices *
3332 sizeof(*vertex_coordinates));
3333 yac_int * vertex_ids =
3334 xrealloc(dist_grid->ids[YAC_LOC_CORNER],
3335 new_num_total_vertices * sizeof(*vertex_ids));
3336 int * vertex_owner_mask =
3337 xrealloc(dist_grid->owner_mask[YAC_LOC_CORNER], new_num_total_vertices *
3338 sizeof(*vertex_owner_mask));
3339 struct remote_point_infos * vertex_owners =
3340 xrealloc(dist_grid->owners[YAC_LOC_CORNER], new_num_total_vertices *
3341 sizeof(*vertex_owners));
3342 sorted_vertex_ids =
3343 xrealloc(
3344 sorted_vertex_ids, new_num_total_vertices * sizeof(*sorted_vertex_ids));
3345 sorted_vertex_reorder_idx =
3346 xrealloc(
3347 sorted_vertex_reorder_idx, new_num_total_vertices *
3348 sizeof(*sorted_vertex_reorder_idx));
3349
3350 // add the selected vertices to the local grid data
3351 for (size_t i = 0, j = num_total_vertices; i < add_count; ++i, ++j) {
3352
3353 vertex_coordinates[j][0] = vertices[i].coord[0];
3354 vertex_coordinates[j][1] = vertices[i].coord[1];
3355 vertex_coordinates[j][2] = vertices[i].coord[2];
3356 vertex_ids[j] = vertices[i].global_id;
3357 vertex_owner_mask[j] = 0;
3358 vertex_owners[j] = vertices[i].owners;
3359 sorted_vertex_ids[j] = vertices[i].global_id;
3360 sorted_vertex_reorder_idx[j] = j;
3361 }
3362 // add field data
3365 temp_vertex_field_data, vertices, sizeof(*vertices),
3366 num_total_vertices, new_num_total_vertices);
3368 sorted_vertex_ids, new_num_total_vertices, sorted_vertex_reorder_idx);
3369
3370 dist_grid->vertex_coordinates = vertex_coordinates;
3371 dist_grid->ids[YAC_LOC_CORNER] = vertex_ids;
3372 dist_grid->owner_mask[YAC_LOC_CORNER] = vertex_owner_mask;
3373 dist_grid->owners[YAC_LOC_CORNER] = vertex_owners;
3374 dist_grid->sorted_ids[YAC_LOC_CORNER] = sorted_vertex_ids;
3375 dist_grid->sorted_reorder_idx[YAC_LOC_CORNER] = sorted_vertex_reorder_idx;
3376 dist_grid->total_count[YAC_LOC_CORNER] = new_num_total_vertices;
3377}
3378
3380 const void * a, const void * b) {
3381
3382 return (((const struct global_edge_reorder *)a)->global_id >
3383 ((const struct global_edge_reorder *)b)->global_id) -
3384 (((const struct global_edge_reorder *)a)->global_id <
3385 ((const struct global_edge_reorder *)b)->global_id);
3386}
3387
3389 struct yac_dist_grid * dist_grid, struct global_edge_reorder * edges,
3390 size_t count, size_t * idx, struct temp_field_data temp_edge_field_data) {
3391
3392 if (count == 0) return;
3393
3394 // sort edges global ids
3395 qsort(edges, count, sizeof(*edges), compare_global_edge_reorder_global_id);
3396
3397 yac_int * sorted_edge_ids = dist_grid->sorted_ids[YAC_LOC_EDGE];
3398 size_t * sorted_edge_reorder_idx = dist_grid->sorted_reorder_idx[YAC_LOC_EDGE];
3399
3400 yac_int prev_global_id = edges[0].global_id - 1;
3401 size_t prev_idx = 0;
3402 size_t add_count = 0;
3403 size_t num_total_edges = dist_grid->total_count[YAC_LOC_EDGE];
3404
3405 // determine which edges need to be added to local data
3406 for (size_t i = 0, j = 0; i < count; ++i) {
3407
3408 yac_int curr_global_id = edges[i].global_id;
3409 size_t curr_reorder_idx = edges[i].reorder_idx;
3410
3411 // if the current global id is a duplicate
3412 if (prev_global_id == curr_global_id) {
3413 if (idx != NULL) idx[curr_reorder_idx] = prev_idx;
3415 continue;
3416 }
3417 prev_global_id = curr_global_id;
3418
3419 // check whether the current global id is already part of the local
3420 // grid data
3421 while ((j < num_total_edges) && (sorted_edge_ids[j] < curr_global_id)) ++j;
3422
3423 // if we found a match in the local data
3424 if ((j < num_total_edges) && (sorted_edge_ids[j] == curr_global_id)) {
3425
3426 if (idx != NULL) idx[curr_reorder_idx] = sorted_edge_reorder_idx[j];
3427 prev_idx = sorted_edge_reorder_idx[j];
3429
3430 // if we need to add the current edge to the local data
3431 } else {
3432
3433 if (idx != NULL) idx[curr_reorder_idx] = num_total_edges + add_count;
3434 prev_idx = num_total_edges + add_count;
3435 if (add_count != i) edges[add_count] = edges[i];
3436 ++add_count;
3437 }
3438 }
3439
3440 size_t new_num_total_edges = num_total_edges + add_count;
3441 yac_int * edge_ids =
3442 xrealloc(dist_grid->ids[YAC_LOC_EDGE],
3443 new_num_total_edges * sizeof(*edge_ids));
3444 enum yac_edge_type * edge_type =
3445 xrealloc(dist_grid->edge_type,
3446 new_num_total_edges * sizeof(*edge_type));
3448 xrealloc(dist_grid->edge_to_vertex,
3449 new_num_total_edges * sizeof(*edge_to_vertex));
3450 struct remote_point_infos * edge_owners =
3451 xrealloc(dist_grid->owners[YAC_LOC_EDGE],
3452 new_num_total_edges * sizeof(*edge_owners));
3453 int * edge_owner_mask =
3454 xrealloc(dist_grid->owner_mask[YAC_LOC_EDGE], new_num_total_edges *
3455 sizeof(*edge_owner_mask));
3456 sorted_edge_ids =
3457 xrealloc(
3458 sorted_edge_ids, new_num_total_edges * sizeof(*sorted_edge_ids));
3459 sorted_edge_reorder_idx =
3460 xrealloc(
3461 sorted_edge_reorder_idx, new_num_total_edges *
3462 sizeof(*sorted_edge_reorder_idx));
3463
3464 yac_int * vertex_ids = xmalloc(2 * add_count * sizeof(*vertex_ids));
3465 size_t * reorder = xmalloc(2 * add_count * sizeof(*reorder));
3466
3467 // add the selected edges to the local grid data
3468 for (size_t i = 0, j = num_total_edges; i < add_count; ++i, ++j) {
3469
3470 edge_ids[j] = edges[i].global_id;
3471 edge_type[j] = edges[i].edge_type;
3472 edge_owner_mask[j] = 0;
3473 edge_owners[j] = edges[i].owners;
3474 sorted_edge_ids[j] = edges[i].global_id;
3475 sorted_edge_reorder_idx[j] = j;
3476
3477 vertex_ids[2 * i + 0] = edges[i].edge_to_vertex[0];
3478 vertex_ids[2 * i + 1] = edges[i].edge_to_vertex[1];
3479 reorder[2 * i + 0] = 2 * num_total_edges + 2 * i + 0;
3480 reorder[2 * i + 1] = 2 * num_total_edges + 2 * i + 1;
3481 }
3482 // add field data
3485 temp_edge_field_data, edges, sizeof(*edges),
3486 num_total_edges, new_num_total_edges);
3488 sorted_edge_ids, new_num_total_edges, sorted_edge_reorder_idx);
3489
3490 { // determine vertex indices for edge_to_vertex
3491 yac_quicksort_index_yac_int_size_t(vertex_ids, 2 * add_count, reorder);
3492 yac_int * sorted_vertex_ids = dist_grid->sorted_ids[YAC_LOC_CORNER];
3493 size_t * sorted_vertex_reorder_idx =
3495 size_t total_num_vertices = dist_grid->total_count[YAC_LOC_CORNER];
3496 size_t * edge_to_vertex_ = (size_t*)&(edge_to_vertex[0][0]);
3497 // lookup global ids
3498 for (size_t i = 0, j = 0; i < 2 * add_count; ++i) {
3499 yac_int curr_id = vertex_ids[i];
3500 while ((j < total_num_vertices) && (sorted_vertex_ids[j] < curr_id)) ++j;
3501 YAC_ASSERT(
3502 (j < total_num_vertices) && (sorted_vertex_ids[j] == curr_id),
3503 "ERROR(yac_dist_grid_add_edges): vertex id not found")
3504 edge_to_vertex_[reorder[i]] = sorted_vertex_reorder_idx[j];
3505 }
3506 }
3507
3508 free(vertex_ids);
3509 free(reorder);
3510
3511 dist_grid->ids[YAC_LOC_EDGE] = edge_ids;
3512 dist_grid->edge_type = edge_type;
3513 dist_grid->edge_to_vertex = edge_to_vertex;
3514 dist_grid->owners[YAC_LOC_EDGE] = edge_owners;
3515 dist_grid->owner_mask[YAC_LOC_EDGE] = edge_owner_mask;
3516 dist_grid->sorted_ids[YAC_LOC_EDGE] = sorted_edge_ids;
3517 dist_grid->sorted_reorder_idx[YAC_LOC_EDGE] = sorted_edge_reorder_idx;
3518 dist_grid->total_count[YAC_LOC_EDGE] = new_num_total_edges;
3519}
3520
3522 struct yac_dist_grid * dist_grid, yac_int * cell_ids,
3523 int * num_vertices_per_cell, struct bounding_circle * cell_bnd_circles,
3524 size_t count, size_t * cell_to_vertex, size_t * cell_to_edge,
3525 struct remote_point_infos * cell_owners,
3526 struct temp_field_data temp_cell_field_data) {
3527
3528 if (count == 0) return;
3529
3530 size_t * reorder_idx = xmalloc(count * sizeof(reorder_idx));
3531 for (size_t i = 0; i < count; ++i) reorder_idx[i] = i;
3532
3533 size_t * prescan = xmalloc(count * sizeof(*prescan));
3534 for (size_t i = 0, accu = 0; i < count;
3535 accu += (size_t)(num_vertices_per_cell[i++])) prescan[i] = accu;
3536
3537 // sort cells global ids
3538 yac_quicksort_index_yac_int_size_t(cell_ids, count, reorder_idx);
3539
3540 yac_int * sorted_cell_ids = dist_grid->sorted_ids[YAC_LOC_CELL];
3541 size_t * sorted_cell_reorder_idx =
3542 dist_grid->sorted_reorder_idx[YAC_LOC_CELL];
3543
3544 yac_int prev_global_id = cell_ids[0] - 1;
3545 size_t cell_add_count = 0;
3546 size_t relations_add_count = 0;
3547 size_t num_total_cells = dist_grid->total_count[YAC_LOC_CELL];
3548
3549 // determine which cells need to be added to local data
3550 for (size_t i = 0, j = 0; i < count; ++i) {
3551
3552 yac_int curr_global_id = cell_ids[i];
3553 size_t curr_reorder_idx = reorder_idx[i];
3554
3555 // if the current global id is a duplicate
3556 if (prev_global_id == curr_global_id) {
3557 yac_remote_point_infos_single_free(cell_owners + curr_reorder_idx);
3558 continue;
3559 }
3560 prev_global_id = curr_global_id;
3561
3562 // check whether the current global id is already part of the local
3563 // grid data
3564 while ((j < num_total_cells) && (sorted_cell_ids[j] < curr_global_id)) ++j;
3565
3566 // if we did not find a match in the local data
3567 if ((j >= num_total_cells) || (sorted_cell_ids[j] != curr_global_id)) {
3568
3569 if (cell_add_count != i) {
3570 cell_ids[cell_add_count] = curr_global_id;
3571 reorder_idx[cell_add_count] = curr_reorder_idx;
3572 }
3573 ++cell_add_count;
3574 relations_add_count += (size_t)(num_vertices_per_cell[curr_reorder_idx]);
3575 }
3576 }
3577
3578 size_t new_num_total_cells = num_total_cells + cell_add_count;
3579 size_t num_total_relations =
3580 (num_total_cells > 0)?
3581 (dist_grid->cell_to_vertex_offsets[num_total_cells-1] +
3582 (size_t)(dist_grid->num_vertices_per_cell[num_total_cells-1])):0;
3583 size_t new_num_total_relations = num_total_relations + relations_add_count;
3584 yac_int * new_cell_ids =
3585 xrealloc(dist_grid->ids[YAC_LOC_CELL],
3586 new_num_total_cells * sizeof(*new_cell_ids));
3587 int * new_num_vertices_per_cell =
3588 xrealloc(dist_grid->num_vertices_per_cell, new_num_total_cells *
3589 sizeof(*new_num_vertices_per_cell));
3590 size_t * new_cell_to_vertex =
3591 xrealloc(dist_grid->cell_to_vertex, new_num_total_relations *
3592 sizeof(*new_cell_to_vertex));
3593 size_t * cell_to_vertex_offsets =
3594 xrealloc(dist_grid->cell_to_vertex_offsets, new_num_total_cells *
3595 sizeof(*cell_to_vertex_offsets));
3596 size_t * new_cell_to_edge =
3597 xrealloc(dist_grid->cell_to_edge, new_num_total_relations *
3598 sizeof(*new_cell_to_edge));
3599 struct bounding_circle * new_cell_bnd_circles =
3600 xrealloc(dist_grid->cell_bnd_circles, new_num_total_cells *
3601 sizeof(*new_cell_bnd_circles));
3602 int * cell_owner_mask =
3603 xrealloc(dist_grid->owner_mask[YAC_LOC_CELL],
3604 new_num_total_cells * sizeof(*cell_owner_mask));
3605 struct remote_point_infos * new_cell_owners =
3606 xrealloc(dist_grid->owners[YAC_LOC_CELL],
3607 new_num_total_cells * sizeof(*cell_owners));
3608 sorted_cell_ids =
3609 xrealloc(
3610 sorted_cell_ids, new_num_total_cells * sizeof(*sorted_cell_ids));
3611 sorted_cell_reorder_idx =
3612 xrealloc(
3613 sorted_cell_reorder_idx, new_num_total_cells *
3614 sizeof(*sorted_cell_reorder_idx));
3615
3616 // add the selected cells to the local grid data
3617 for (size_t i = 0, j = num_total_cells; i < cell_add_count;
3618 ++i, ++j) {
3619
3620 size_t curr_reorder_idx = reorder_idx[i];
3621 int curr_num_vertices = num_vertices_per_cell[curr_reorder_idx];
3622 size_t curr_relation_idx = prescan[curr_reorder_idx];
3623
3624 new_cell_ids[j] = cell_ids[i];
3625 new_num_vertices_per_cell[j] = curr_num_vertices;
3626 cell_to_vertex_offsets[j] = num_total_relations;
3627 for (int j = 0; j < curr_num_vertices;
3628 ++j, ++num_total_relations, ++curr_relation_idx) {
3629 new_cell_to_vertex[num_total_relations] =
3630 cell_to_vertex[curr_relation_idx];
3631 new_cell_to_edge[num_total_relations] = cell_to_edge[curr_relation_idx];
3632 }
3633 cell_owner_mask[j] = 0;
3634 sorted_cell_ids[j] = cell_ids[i];
3635 sorted_cell_reorder_idx[j] = j;
3636 new_cell_bnd_circles[j] = cell_bnd_circles[curr_reorder_idx];
3637 new_cell_owners[j] = cell_owners[curr_reorder_idx];
3638 }
3639 // add field data
3642 temp_cell_field_data, reorder_idx, sizeof(*reorder_idx),
3643 num_total_cells, new_num_total_cells);
3645 sorted_cell_ids, new_num_total_cells, sorted_cell_reorder_idx);
3646
3647 dist_grid->ids[YAC_LOC_CELL] = new_cell_ids;
3648 dist_grid->num_vertices_per_cell = new_num_vertices_per_cell;
3649 dist_grid->cell_to_vertex = new_cell_to_vertex;
3650 dist_grid->cell_to_vertex_offsets = cell_to_vertex_offsets;
3651 dist_grid->cell_to_edge = new_cell_to_edge;
3652 dist_grid->cell_to_edge_offsets = cell_to_vertex_offsets;
3653 dist_grid->owner_mask[YAC_LOC_CELL] = cell_owner_mask;
3654 dist_grid->owners[YAC_LOC_CELL] = new_cell_owners;
3655 dist_grid->sorted_ids[YAC_LOC_CELL] = sorted_cell_ids;
3656 dist_grid->sorted_reorder_idx[YAC_LOC_CELL] = sorted_cell_reorder_idx;
3657 dist_grid->cell_bnd_circles = new_cell_bnd_circles;
3658 dist_grid->total_count[YAC_LOC_CELL] = new_num_total_cells;
3659
3660 free(prescan);
3661 free(reorder_idx);
3662}
3663
3665 struct temp_field_data * temp_field_data, size_t size) {
3666
3667 for (size_t i = 0; i < temp_field_data->masks_count; ++i)
3670 for (size_t i = 0; i < temp_field_data->coordinates_count; ++i)
3674}
3675
3677 struct yac_field_data * field_data, size_t count) {
3678
3680 size_t masks_count = yac_field_data_get_masks_count(field_data);
3682
3688 for (size_t i = 0; i < masks_count; ++i) {
3690 xmalloc(count * sizeof(**temp_field_data.masks));
3692 }
3693
3695 xmalloc(
3698 xmalloc(
3702 for (size_t i = 0; i < coordinates_count; ++i) {
3704 xmalloc(count * sizeof(**temp_field_data.coordinates));
3706 }
3707
3708 return temp_field_data;
3709}
3710
3712
3713 for (size_t i = 0; i < temp_field_data.masks_count; ++i)
3714 free(temp_field_data.masks[i]);
3715 free(temp_field_data.masks);
3717 for (size_t i = 0; i < temp_field_data.coordinates_count; ++i)
3721}
3722
3724 struct yac_dist_grid * dist_grid, size_t count, void * buffer,
3725 int buffer_size, MPI_Datatype bnd_circle_dt, MPI_Datatype point_info_dt,
3726 MPI_Comm comm) {
3727
3728 yac_int * cell_ids = xmalloc(count * sizeof(*cell_ids));
3729 int * num_vertices_per_cell = xmalloc(count * sizeof(*num_vertices_per_cell));
3730 struct bounding_circle * cell_bnd_circles =
3731 xmalloc(count * sizeof(*cell_bnd_circles));
3732 struct remote_point_infos * cell_owners =
3733 xmalloc(count * sizeof(*cell_owners));
3734
3735 struct global_vertex_reorder * vertices = NULL;
3736 size_t vertices_array_size = 0;
3737 size_t total_num_vertices = 0;
3738
3739 struct global_edge_reorder * edges = NULL;
3740 size_t edges_array_size = 0;
3741
3742 struct temp_field_data temp_cell_field_data =
3745 dist_grid->field_data, YAC_LOC_CELL), count);
3746 struct temp_field_data temp_vertex_field_data =
3749 dist_grid->field_data, YAC_LOC_CORNER), 3 * count);
3750 struct temp_field_data temp_edge_field_data =
3753 dist_grid->field_data, YAC_LOC_EDGE), 3 * count);
3754
3755 for (size_t i = 0, buffer_offset = 0; i < count; ++i) {
3756
3757 int position = 0;
3758 void * curr_buffer = (char*)buffer + buffer_offset;
3759 int num_vertices;
3760
3761 // cell id
3763 MPI_Unpack(curr_buffer, buffer_size, &position, cell_ids + i, 1,
3764 yac_int_dt, comm), comm);
3765 // unpack field data
3767 curr_buffer, buffer_size, &position, i, temp_cell_field_data, comm);
3768 // num vertices
3770 MPI_Unpack(curr_buffer, buffer_size, &position, &num_vertices, 1,
3771 MPI_INT, comm), comm);
3772 // bounding circle
3774 MPI_Unpack(curr_buffer, buffer_size, &position, cell_bnd_circles + i, 1,
3775 bnd_circle_dt, comm), comm);
3776 // cell owners
3778 curr_buffer, buffer_size, &position, cell_owners + i,
3779 point_info_dt, comm);
3780
3781 num_vertices_per_cell[i] = num_vertices;
3782
3784 vertices, vertices_array_size, total_num_vertices + (size_t)num_vertices);
3786 edges, edges_array_size, total_num_vertices + (size_t)num_vertices);
3788 &temp_vertex_field_data, total_num_vertices + (size_t)num_vertices);
3790 &temp_edge_field_data, total_num_vertices + (size_t)num_vertices);
3791
3792 for (int j = 0; j < num_vertices; ++j, ++total_num_vertices) {
3794 vertices, total_num_vertices, curr_buffer, buffer_size, &position,
3795 temp_vertex_field_data, point_info_dt, comm);
3797 edges, total_num_vertices, curr_buffer, buffer_size, &position,
3798 temp_edge_field_data, point_info_dt, comm);
3799 vertices[total_num_vertices].reorder_idx = total_num_vertices;
3800 edges[total_num_vertices].reorder_idx = total_num_vertices;
3801 }
3802
3803 buffer_offset += (size_t)position;
3804 buffer_size -= position;
3805 }
3806
3807 size_t * cell_to_vertex = xmalloc(total_num_vertices * sizeof(*cell_to_vertex));
3808 size_t * cell_to_edge = xmalloc(total_num_vertices * sizeof(*cell_to_edge));
3809
3811 dist_grid, vertices, total_num_vertices, cell_to_vertex,
3812 temp_vertex_field_data);
3814 dist_grid, edges, total_num_vertices, cell_to_edge,
3815 temp_edge_field_data);
3817 dist_grid, cell_ids, num_vertices_per_cell, cell_bnd_circles, count,
3818 cell_to_vertex, cell_to_edge, cell_owners, temp_cell_field_data);
3819
3820 temp_field_data_free(temp_cell_field_data);
3821 temp_field_data_free(temp_vertex_field_data);
3822 temp_field_data_free(temp_edge_field_data);
3823 free(cell_to_edge);
3824 free(cell_to_vertex);
3825 free(vertices);
3826 free(edges);
3827 free(cell_owners);
3828 free(cell_bnd_circles);
3829 free(num_vertices_per_cell);
3830 free(cell_ids);
3831}
3832
3834 struct yac_dist_grid * dist_grid, size_t count, void * buffer,
3835 int buffer_size, MPI_Datatype point_info_dt, MPI_Comm comm) {
3836
3837 struct global_vertex_reorder * vertices = xmalloc(count * sizeof(*vertices));
3838
3839 struct temp_field_data temp_vertex_field_data =
3842 count);
3843
3844 for (size_t i = 0, buffer_offset = 0; i < count; ++i) {
3845
3846 int position = 0;
3847 void * curr_buffer = (char*)buffer + buffer_offset;
3848
3850 vertices, i, curr_buffer, buffer_size, &position,
3851 temp_vertex_field_data, point_info_dt, comm);
3852 vertices[i].reorder_idx = i;
3853
3854 buffer_offset += (size_t)position;
3855 buffer_size -= position;
3856 }
3857
3859 dist_grid, vertices, count, NULL, temp_vertex_field_data);
3860
3861 temp_field_data_free(temp_vertex_field_data);
3862
3863 free(vertices);
3864}
3865
3867 struct yac_dist_grid * dist_grid, size_t count, void * buffer,
3868 int buffer_size, MPI_Datatype point_info_dt, MPI_Comm comm) {
3869
3870 struct global_edge_reorder * edges = xmalloc(count * sizeof(*edges));
3871 struct global_vertex_reorder * vertices =
3872 xmalloc(2 * count * sizeof(*vertices));
3873
3874 struct temp_field_data temp_edge_field_data =
3877 count);
3878 struct temp_field_data temp_vertex_field_data =
3881 2 * count);
3882
3883 for (size_t i = 0, buffer_offset = 0; i < count; ++i) {
3884
3885 int position = 0;
3886 void * curr_buffer = (char*)buffer + buffer_offset;
3887
3889 edges, i, curr_buffer, buffer_size, &position,
3890 temp_edge_field_data, point_info_dt, comm);
3891 edges[i].reorder_idx = i;
3892
3893 for (size_t j = 0; j < 2; ++j)
3895 vertices, 2 * i + j, curr_buffer, buffer_size, &position,
3896 temp_vertex_field_data, point_info_dt, comm);
3897
3898 buffer_offset += (size_t)position;
3899 buffer_size -= position;
3900 }
3901
3903 dist_grid, vertices, 2 * count, NULL, temp_vertex_field_data);
3905 dist_grid, edges, count, NULL, temp_edge_field_data);
3906
3907 temp_field_data_free(temp_vertex_field_data);
3908 temp_field_data_free(temp_edge_field_data);
3909
3910 free(vertices);
3911 free(edges);
3912}
3913
3915 struct yac_dist_grid * dist_grid, enum yac_location location, size_t count,
3916 void * buffer, int buffer_size, MPI_Datatype bnd_circle_dt,
3917 MPI_Datatype point_info_dt, MPI_Comm comm) {
3918
3919 CHECK_LOCATION("unpack_grid_data")
3920
3921 switch(location) {
3922 default:
3923 case(YAC_LOC_CELL):
3925 dist_grid, count, buffer, buffer_size, bnd_circle_dt,
3926 point_info_dt, comm);
3927 break;
3928 case(YAC_LOC_CORNER):
3930 dist_grid, count, buffer, buffer_size, point_info_dt, comm);
3931 break;
3932 case(YAC_LOC_EDGE):
3934 dist_grid, count, buffer, buffer_size, point_info_dt, comm);
3935 break;
3936 };
3937}
3938
3940 const void * a, const void * b) {
3941
3942 return ((const struct single_remote_point_reorder *)a)->data.data.rank -
3943 ((const struct single_remote_point_reorder *)b)->data.data.rank;
3944}
3945
3947 struct yac_dist_grid * dist_grid, struct single_remote_point * ids,
3948 size_t count, enum yac_location location, size_t * idx) {
3949
3950 MPI_Comm comm = dist_grid->comm;
3951 int comm_rank, comm_size;
3952 yac_mpi_call(MPI_Comm_rank(comm, &comm_rank), comm);
3953 yac_mpi_call(MPI_Comm_size(comm, &comm_size), comm);
3954
3955 size_t remote_count = 0;
3956
3957 for (size_t i = 0; i < count; ++i) {
3958 if (ids[i].global_id == XT_INT_MAX) idx[i] = SIZE_MAX;
3959 else if (ids[i].data.rank != comm_rank) ++remote_count;
3960 else idx[i] = ids[i].data.orig_pos;
3961 }
3962
3963 struct single_remote_point_reorder * missing_ids =
3964 xmalloc(remote_count * sizeof(*missing_ids));
3965
3966 for (size_t i = 0, j = 0; i < count; ++i) {
3967 if ((ids[i].data.rank != comm_rank) &&
3968 (ids[i].global_id != XT_INT_MAX)) {
3969 missing_ids[j].data = ids[i];
3970 missing_ids[j].reorder_idx = i;
3971 ++j;
3972 }
3973 }
3974
3975 // check whether we already have some of the missing ids locally
3977 dist_grid, location, missing_ids, &remote_count, idx);
3978
3979 // sort data by owner
3980 qsort(missing_ids, remote_count, sizeof(*missing_ids),
3982
3983 size_t * sendcounts, * recvcounts, * sdispls, * rdispls;
3985 1, &sendcounts, &recvcounts, &sdispls, &rdispls, comm);
3986
3987 for (size_t i = 0; i < remote_count; ++i)
3988 sendcounts[missing_ids[i].data.data.rank]++;
3989
3991 1, sendcounts, recvcounts, sdispls, rdispls, comm);
3992
3993 size_t recv_count = rdispls[comm_size-1] + recvcounts[comm_size-1];
3994
3995 uint64_t * uint64_t_buffer =
3996 xmalloc((remote_count + recv_count) * sizeof(*uint64_t_buffer));
3997 uint64_t * orig_pos_send_buffer = uint64_t_buffer;
3998 uint64_t * orig_pos_recv_buffer = uint64_t_buffer + remote_count;
3999
4000 // pack send buffer
4001 for (size_t i = 0; i < remote_count; ++i) {
4002 int rank = missing_ids[i].data.data.rank;
4003 if (rank != comm_rank)
4004 orig_pos_send_buffer[sdispls[rank+1]++] =
4005 (uint64_t)(missing_ids[i].data.data.orig_pos);
4006 }
4007
4008 // redistribute ids
4009 yac_alltoallv_uint64_p2p(
4010 orig_pos_send_buffer, sendcounts, sdispls,
4011 orig_pos_recv_buffer, recvcounts, rdispls, comm,
4012 "yac_dist_grid_single_remote_point_to_local", __LINE__);
4013
4014 MPI_Datatype bnd_circle_dt = yac_get_bounding_circle_mpi_datatype(comm);
4015 yac_mpi_call(MPI_Type_commit(&bnd_circle_dt), comm);
4016 MPI_Datatype point_info_dt = yac_get_remote_point_info_mpi_datatype(comm);
4017 yac_mpi_call(MPI_Type_commit(&point_info_dt), comm);
4018
4019 void * packed_send_data = NULL;
4020 int * pack_sizes = xmalloc(recv_count * sizeof(*pack_sizes));
4021
4022 // pack all requested grid data
4024 dist_grid, location, orig_pos_recv_buffer, recv_count,
4025 &packed_send_data, pack_sizes,
4026 bnd_circle_dt, point_info_dt, comm);
4027 free(uint64_t_buffer);
4028
4029 memset(sendcounts, 0, (size_t)comm_size * sizeof(*sendcounts));
4030 for (int i = 0, k = 0; i < comm_size; ++i)
4031 for (size_t j = 0; j < recvcounts[i]; ++j, ++k)
4032 sendcounts[i] += (size_t)(pack_sizes[k]);
4033
4034 free(pack_sizes);
4035
4037 1, sendcounts, recvcounts, sdispls, rdispls, comm);
4038
4039 recv_count = rdispls[comm_size-1] + recvcounts[comm_size-1];
4040
4041 void * packed_recv_data = xmalloc(recv_count);
4042
4043 // redistribute packed grid data
4044 yac_alltoallv_packed_p2p(
4045 packed_send_data, sendcounts, sdispls+1,
4046 packed_recv_data, recvcounts, rdispls, comm,
4047 "yac_dist_grid_single_remote_point_to_local", __LINE__);
4048
4049 // unpack requested grid data
4051 dist_grid, location, remote_count, packed_recv_data, (int)recv_count,
4052 bnd_circle_dt, point_info_dt, comm);
4053
4054 yac_mpi_call(MPI_Type_free(&point_info_dt), comm);
4055 yac_mpi_call(MPI_Type_free(&bnd_circle_dt), comm);
4056
4057 // get the local ids for the remaining missing ids
4059 dist_grid, location, missing_ids, &remote_count, idx);
4060
4061 free(missing_ids);
4062 free(packed_recv_data);
4063 free(packed_send_data);
4064 yac_free_comm_buffers(sendcounts, recvcounts, sdispls, rdispls);
4065}
4066
4067static MPI_Datatype yac_get_single_remote_point_mpi_datatype(MPI_Comm comm) {
4068
4069 struct single_remote_point dummy;
4070 MPI_Datatype single_id_owner_dt;
4071 int array_of_blocklengths[] = {1, 1, 1};
4072 const MPI_Aint array_of_displacements[] =
4073 {(MPI_Aint)(intptr_t)(const void *)&(dummy.global_id) -
4074 (MPI_Aint)(intptr_t)(const void *)&dummy,
4075 (MPI_Aint)(intptr_t)(const void *)&(dummy.data.rank) -
4076 (MPI_Aint)(intptr_t)(const void *)&dummy,
4077 (MPI_Aint)(intptr_t)(const void *)&(dummy.data.orig_pos) -
4078 (MPI_Aint)(intptr_t)(const void *)&dummy};
4079 const MPI_Datatype array_of_types[] =
4080 {yac_int_dt, MPI_INT, MPI_UINT64_T};
4082 MPI_Type_create_struct(3, array_of_blocklengths, array_of_displacements,
4083 array_of_types, &single_id_owner_dt), comm);
4084 return yac_create_resized(single_id_owner_dt, sizeof(dummy), comm);
4085}
4086
4087// determines for each search point the matching cell
4089 struct yac_dist_grid_pair * grid_pair, char const * grid_name,
4090 yac_coordinate_pointer search_coords, size_t count, size_t * cells,
4091 int (*coord_in_cell)(
4092 double coord[3], struct yac_dist_grid * dist_grid, size_t cell_idx,
4093 struct yac_grid_cell * buffer_cell)) {
4094
4095 char const * routine = "yac_dist_grid_pair_do_point_search_";
4096
4097 MPI_Comm comm = grid_pair->comm;
4098 int comm_rank, comm_size;
4099 yac_mpi_call(MPI_Comm_rank(comm, &comm_rank), comm);
4100 yac_mpi_call(MPI_Comm_size(comm, &comm_size), comm);
4101
4102 int * ranks = xmalloc(count * sizeof(ranks));
4103
4104 //----------------------------------------------------
4105 // match search points with YAC internal decomposition
4106 //----------------------------------------------------
4107
4108 // search for the matching process (according to the YAC
4109 // internal decomposition) for each search point
4111 grid_pair->proc_sphere_part, search_coords, count, ranks);
4112
4113 //---------------------------------------------------------------
4114 // relocate search points according to YAC internal decomposition
4115 //---------------------------------------------------------------
4116
4117 size_t * sendcounts, * recvcounts, * sdispls, * rdispls;
4119 1, &sendcounts, &recvcounts, &sdispls, &rdispls, comm);
4120 for (size_t i = 0; i < count; ++i) sendcounts[ranks[i]]++;
4121
4122 size_t local_count = sendcounts[comm_rank];
4123 sendcounts[comm_rank] = 0;
4124
4126 1, sendcounts, recvcounts, sdispls, rdispls, comm);
4127
4128 size_t remote_count = sdispls[comm_size] + sendcounts[comm_size-1];
4129 size_t request_count = rdispls[comm_size-1] + recvcounts[comm_size-1];
4130
4131 yac_coordinate_pointer coord_buffer =
4132 xmalloc((remote_count + request_count + local_count) *
4133 sizeof(*coord_buffer));
4134 yac_coordinate_pointer coord_send_buffer = coord_buffer + 0;
4135 yac_coordinate_pointer coord_recv_buffer = coord_buffer + remote_count;
4136 yac_coordinate_pointer coord_local_buffer =
4137 coord_buffer + remote_count + request_count;
4138
4139 // pack search coordinates
4140 for (size_t i = 0, k = 0; i < count; ++i) {
4141 if (ranks[i] == comm_rank) {
4142 coord_local_buffer[k][0] = search_coords[i][0];
4143 coord_local_buffer[k][1] = search_coords[i][1];
4144 coord_local_buffer[k][2] = search_coords[i][2];
4145 ++k;
4146 } else {
4147 size_t displ = sdispls[ranks[i]+1]++;
4148 coord_send_buffer[displ][0] = search_coords[i][0];
4149 coord_send_buffer[displ][1] = search_coords[i][1];
4150 coord_send_buffer[displ][2] = search_coords[i][2];
4151 }
4152 }
4153
4154 MPI_Datatype dt_coord;
4155 yac_mpi_call(MPI_Type_contiguous(3, MPI_DOUBLE, &dt_coord), comm);
4156 yac_mpi_call(MPI_Type_commit(&dt_coord), comm);
4157
4158 // redistribute search coordinates
4160 coord_send_buffer, sendcounts, sdispls,
4161 coord_recv_buffer, recvcounts, rdispls,
4162 sizeof(*coord_send_buffer), dt_coord, comm, routine, __LINE__);
4163
4164 yac_mpi_call(MPI_Type_free(&dt_coord), comm);
4165
4166 size_t * local_cells =
4167 xmalloc((request_count + local_count) * sizeof(*local_cells));
4168
4169 //-----------------------------------------------
4170 // match search points with locally stored cells,
4171 // which should contain the matching cell
4172 //-----------------------------------------------
4173
4174 // do local search
4176 grid_pair, grid_name, coord_recv_buffer, request_count + local_count,
4177 local_cells, coord_in_cell);
4178
4179 //--------------------------------------------------------------
4180 // return search results (global and local id of matching cells)
4181 // (unmatched points:
4182 // global_id = XT_INT_MAX, local_id = UINT64_MAX)
4183 //--------------------------------------------------------------
4184
4185 struct single_remote_point * single_remote_point_buffer =
4186 xmalloc((remote_count + request_count) *
4187 sizeof(*single_remote_point_buffer));
4188 struct single_remote_point * id_send_buffer = single_remote_point_buffer;
4189 struct single_remote_point * id_recv_buffer = single_remote_point_buffer +
4190 request_count;
4191
4192 struct yac_dist_grid * dist_grid =
4193 yac_dist_grid_pair_get_dist_grid(grid_pair, grid_name);
4194
4195 // pack global ids of found source cells
4196 for (size_t i = 0; i < request_count; ++i) {
4197 size_t cell_idx = local_cells[i];
4198 id_send_buffer[i].data.rank = comm_rank;
4199 if (cell_idx != SIZE_MAX) {
4200 id_send_buffer[i].global_id = dist_grid->ids[YAC_LOC_CELL][cell_idx];
4201 id_send_buffer[i].data.orig_pos = (uint64_t)cell_idx;
4202 } else {
4203 id_send_buffer[i].global_id = XT_INT_MAX;
4204 id_send_buffer[i].data.orig_pos = UINT64_MAX;
4205 }
4206 }
4207
4208 MPI_Datatype single_remote_point_dt =
4210
4211 // redistribute results (global ids of found source cells)
4213 id_send_buffer, recvcounts, rdispls, id_recv_buffer, sendcounts, sdispls,
4214 sizeof(*id_send_buffer), single_remote_point_dt, comm, routine, __LINE__);
4215
4216 yac_mpi_call(MPI_Type_free(&single_remote_point_dt), comm);
4217
4218 size_t * new_local_cells =
4219 xmalloc(remote_count * sizeof(*new_local_cells));
4220
4221 //------------------------------------------------------------------
4222 // extend local part of the distributed grid, such that it contains
4223 // all matching cells and afterwards convert all search results into
4224 // from global ids to local ones
4225 //------------------------------------------------------------------
4226
4227 // convert all remote ids to local ones, extend local dist_grid data,
4228 // if necessary
4230 dist_grid, id_recv_buffer, remote_count, YAC_LOC_CELL, new_local_cells);
4231
4232 // extract results from local and remote search
4233 for (size_t i = 0, k = 0; i < count; ++i) {
4234 if (ranks[i] == comm_rank) {
4235 cells[i] = local_cells[request_count + k];
4236 ++k;
4237 } else {
4238 size_t displ = sdispls[ranks[i]]++;
4239 cells[i] = new_local_cells[displ];
4240 }
4241 }
4242
4243 free(new_local_cells);
4244 free(single_remote_point_buffer);
4245 free(local_cells);
4246 free(coord_buffer);
4247 yac_free_comm_buffers(sendcounts, recvcounts, sdispls, rdispls);
4248 free(ranks);
4249}
4250
4252 struct yac_dist_grid_pair * grid_pair, char const * grid_name,
4253 yac_coordinate_pointer search_coords, size_t count, size_t * cells) {
4254
4256 grid_pair, grid_name, search_coords, count, cells, coord_in_cell);
4257}
4258
4260 struct yac_dist_grid_pair * grid_pair, char const * grid_name,
4261 yac_coordinate_pointer search_coords, size_t count, size_t * cells) {
4262
4264 grid_pair, grid_name, search_coords, count, cells, coord_in_cell_gc);
4265}
4266
4267// generates search data structure for the points of a field
4268// (has to be regenerated for each use, because the local part of
4269// the distributed grid may have been extend by a previous search call)
4271 struct yac_dist_grid * dist_grid, struct yac_interp_field field) {
4272
4273 yac_const_coordinate_pointer field_coords =
4274 yac_dist_grid_get_field_coords(dist_grid, field);
4275 yac_int const * global_ids =
4276 yac_dist_grid_get_global_ids(dist_grid, field.location);
4277 int const * mask = yac_dist_grid_get_field_mask(dist_grid, field);
4278 size_t total_count =
4279 yac_dist_grid_get_total_count(dist_grid, field.location);
4280
4281 if (mask == NULL)
4282 return
4284 total_count, field_coords, global_ids);
4285 else
4286 return
4288 total_count, field_coords, global_ids, mask);
4289}
4290
4291// returns n points from the list of locally owned unmasked points;
4292// the data is returned in a format that can be sent to other processes
4293// (remark: this routine assumes the local part actually contains the
4294// required number of points, which is not checked)
4296 struct yac_dist_grid * dist_grid, struct yac_interp_field field,
4297 int comm_rank, size_t n, struct single_remote_point * points) {
4298
4299 size_t count =
4300 yac_dist_grid_get_count(dist_grid, field.location);
4301 int const * field_mask = yac_dist_grid_get_field_mask(dist_grid, field);
4302 int const * owner_mask =
4303 yac_dist_grid_get_owner_mask(dist_grid, field.location);
4304 yac_int const * global_ids =
4305 yac_dist_grid_get_global_ids(dist_grid, field.location);
4306
4307 if (field_mask == NULL) {
4308
4309 for (size_t i = 0, j = 0; i < count; ++i) {
4310 if (owner_mask[i]) {
4311 points[j].global_id = global_ids[i];
4312 points[j].data.rank = comm_rank;
4313 points[j].data.orig_pos = i;
4314 if (n == ++j) return;
4315 }
4316 }
4317
4318 } else {
4319
4320 for (size_t i = 0, j = 0; i < count; ++i) {
4321 if (owner_mask[i] && field_mask[i]) {
4322 points[j].global_id = global_ids[i];
4323 points[j].data.rank = comm_rank;
4324 points[j].data.orig_pos = i;
4325 if (n == ++j) return;
4326 }
4327 }
4328 }
4329}
4330
4332 void const * a, void const * b) {
4333
4334 struct nnn_search_result const * result_a =
4335 (struct nnn_search_result const *)a;
4336 struct nnn_search_result const * result_b =
4337 (struct nnn_search_result const *)b;
4338
4339 int ret = (result_a->cos_angle < result_b->cos_angle) -
4340 (result_a->cos_angle > result_b->cos_angle);
4341 if (ret) return ret;
4342 return (result_a->global_id > result_b->global_id) -
4343 (result_a->global_id < result_b->global_id);
4344}
4345
4346// searches for the n nearest points in the locally available data
4348 struct yac_dist_grid * dist_grid, struct yac_interp_field field,
4349 size_t count, yac_coordinate_pointer search_coords, size_t n,
4350 double cos_max_search_distance, size_t * result_points) {
4351
4352 struct point_sphere_part_search * sphere_part =
4353 yac_dist_grid_get_field_sphere_part(dist_grid, field);
4354
4355 // do local search
4356 double * cos_angles = NULL;
4357 size_t cos_angles_array_size = 0;
4358 size_t * temp_result_points = NULL;
4359 size_t temp_result_points_array_size = 0;
4360 size_t * num_temp_results = xmalloc(count * sizeof(*num_temp_results));
4362 sphere_part, count, search_coords, n, &cos_angles,
4363 &cos_angles_array_size, NULL, NULL, &temp_result_points,
4364 &temp_result_points_array_size, num_temp_results);
4365
4367
4368 // get the maximum number of results found per search point (can be more
4369 // than n, if multiple result distances are identical)
4370 size_t max_num_results = 0;
4371 for (size_t i = 0; i < count; ++i)
4372 if (max_num_results < num_temp_results[i])
4373 max_num_results = num_temp_results[i];
4374
4375 struct nnn_search_result * temp_results =
4376 xmalloc(max_num_results * sizeof(*temp_results));
4377
4378 yac_int const * global_ids =
4379 yac_dist_grid_get_global_ids(dist_grid, field.location);
4380
4381 // for all search points
4382 for (size_t i = 0, k = 0; i < count; ++i) {
4383
4384 size_t curr_num_search_results = num_temp_results[i];
4385 size_t curr_num_results = 0;
4386
4387 // extract results
4388 for (size_t j = 0; j < curr_num_search_results; ++j, ++k) {
4389
4390 // if the current search result is close enough
4391 if (cos_angles[k] >= cos_max_search_distance) {
4392
4393 // extract result
4394 size_t curr_local_id = temp_result_points[k];
4395 temp_results[curr_num_results].local_id = curr_local_id;
4396 temp_results[curr_num_results].global_id = global_ids[curr_local_id];
4397 temp_results[curr_num_results].cos_angle = cos_angles[k];
4398 curr_num_results++;
4399 }
4400
4401 }
4402 // sort results (by distance and global id)
4403 qsort(
4404 temp_results, curr_num_results, sizeof(*temp_results),
4406
4407 if (curr_num_results > n) curr_num_results = n;
4408
4409 for (size_t l = 0; l < curr_num_results; ++l)
4410 result_points[i * n + l] = temp_results[l].local_id;
4411 for (size_t l = curr_num_results; l < n; ++l)
4412 result_points[i * n + l] = UINT64_MAX;
4413 }
4414
4415 free(num_temp_results);
4416 free(cos_angles);
4417 free(temp_results);
4418 free(temp_result_points);
4419}
4420
4421static inline int compare_size_t(const void * a, const void * b) {
4422
4423 size_t const * a_ = a, * b_ = b;
4424
4425 return (*a_ > *b_) - (*b_ > *a_);
4426}
4427
4429 struct yac_dist_grid_pair * grid_pair, char const * grid_name,
4430 yac_coordinate_pointer search_coords, size_t count, size_t * local_ids,
4431 size_t n, struct yac_interp_field field, double max_search_distance) {
4432
4433 char const * routine = "yac_dist_grid_pair_do_nnn_search";
4434
4435 MPI_Comm comm = grid_pair->comm;
4436 int comm_rank, comm_size;
4437 yac_mpi_call(MPI_Comm_rank(comm, &comm_rank), comm);
4438 yac_mpi_call(MPI_Comm_size(comm, &comm_size), comm);
4439
4441 (max_search_distance >= 0.0) && (max_search_distance <= M_PI),
4442 "ERROR(%s): invalid max_search_distance (%lf)",
4443 routine, max_search_distance)
4444
4445 struct sin_cos_angle max_search_distance_angle =
4446 sin_cos_angle_new(sin(max_search_distance), cos(max_search_distance));
4447
4448 struct yac_dist_grid * dist_grid =
4449 yac_dist_grid_pair_get_dist_grid(grid_pair, grid_name);
4450
4451 //---------------------------------------------------------------------------
4452 // At first we have to make sure that each process has at least N unmasked
4453 // points locally available. This enables each process to locally perform a
4454 // first rough nnn search, which is an upper bound for searching on other
4455 // processes.
4456 //---------------------------------------------------------------------------
4457
4458 uint64_t unmasked_local_count =
4460
4461 uint64_t * unmasked_local_counts =
4462 xmalloc((size_t)comm_size * sizeof(*unmasked_local_counts));
4463
4464 // exchange number of local source points and target points
4466 MPI_Allgather(
4467 &unmasked_local_count, 1, MPI_UINT64_T,
4468 unmasked_local_counts, 1, MPI_UINT64_T, comm), comm);
4469
4470 // check whether there is a rank with too few source points
4471 int flag = 0;
4472 for (int i = 0; i < comm_size; ++i)
4473 flag |= unmasked_local_counts[i] < (uint64_t)n;
4474
4475 // if ranks with insufficient number of local source points
4476 if (flag) {
4477
4478 uint64_t global_num_unmasked_count = 0;
4479 for (int i = 0; i < comm_size; ++i)
4480 global_num_unmasked_count += unmasked_local_counts[i];
4481
4483 (size_t)global_num_unmasked_count >= n, "ERROR(%s): "
4484 "insufficient number of unmasked points (available: %zu required: %zu",
4485 routine, (size_t)global_num_unmasked_count, n)
4486
4487 size_t * sendcounts, * recvcounts, * sdispls, * rdispls;
4489 1, &sendcounts, &recvcounts, &sdispls, &rdispls, comm);
4490
4491 // get ranks of processes that have additional data or require data in
4492 // order to have enough source points to do a initial nnn search
4493 int * flag_buffer = xcalloc(2 * (size_t)comm_size, sizeof(*flag_buffer));
4494 int * send_flags = flag_buffer;
4495 int * recv_flags = flag_buffer + comm_size;
4497 grid_pair->proc_sphere_part, unmasked_local_counts, (uint64_t)n,
4498 send_flags, recv_flags, comm_rank, comm_size);
4499 for (int i = 0; i < comm_size; ++i) {
4500 sendcounts[i] = (size_t)send_flags[i];
4501 recvcounts[i] = (size_t)recv_flags[i];
4502 }
4503 free(flag_buffer);
4504
4505 size_t local_send_count = (size_t)(MIN(unmasked_local_count, n));
4506
4507 size_t raccu = 0;
4508 for (int i = 0; i < comm_size; ++i) {
4509 sdispls[i] = 0;
4510 rdispls[i] = raccu;
4511 sendcounts[i] *= local_send_count;
4512 raccu += (recvcounts[i] *= (int)(MIN(unmasked_local_counts[i], n)));
4513 }
4514
4515 size_t recv_count = recvcounts[comm_size-1] + rdispls[comm_size-1];
4516
4517 struct single_remote_point * single_remote_point_buffer =
4518 xmalloc(
4519 (local_send_count + recv_count) * sizeof(*single_remote_point_buffer));
4520 struct single_remote_point * local_send_ids = single_remote_point_buffer;
4521 struct single_remote_point * recv_ids =
4522 single_remote_point_buffer + local_send_count;
4523
4524 // get local source points that can be sent to other processes
4526 dist_grid, field, comm_rank, local_send_count, local_send_ids);
4527
4528 MPI_Datatype single_remote_point_dt =
4530
4531 // exchange source points (integrate points into local data)
4533 local_send_ids, sendcounts, sdispls, recv_ids, recvcounts, rdispls,
4534 sizeof(*local_send_ids), single_remote_point_dt, comm,
4535 routine, __LINE__);
4536
4537 yac_mpi_call(MPI_Type_free(&single_remote_point_dt), comm);
4538
4539 size_t * dummy = xmalloc(recv_count * sizeof(*dummy));
4540
4541 // convert all remote ids to local ones, extend local dist_grid data,
4542 // if necessary
4544 dist_grid, recv_ids, recv_count, field.location, dummy);
4545
4546 free(dummy);
4547 free(single_remote_point_buffer);
4548 yac_free_comm_buffers(sendcounts, recvcounts, sdispls, rdispls);
4549 }
4550 free(unmasked_local_counts);
4551
4552 //---------------------------------------------------------------------------
4553 // The actual search starts by determining locally the upper bound for
4554 // the distance for all search points
4555 //---------------------------------------------------------------------------
4556
4557 struct sin_cos_angle * ubounds = xmalloc(count * sizeof(*ubounds));
4558
4559 struct point_sphere_part_search * sphere_part =
4560 yac_dist_grid_get_field_sphere_part(dist_grid, field);
4561
4563 sphere_part, count, search_coords, n, ubounds);
4564
4565 //---------------------------------------------------------------------------
4566 // Now for each search points the global decomposition is checked to
4567 // determine whether other processes may contribute data
4568 //---------------------------------------------------------------------------
4569
4570 int * request_ranks = NULL;
4571 size_t request_ranks_array_size = 0;
4572 size_t num_request_ranks = 0;
4573 int * num_requests = xmalloc(count * sizeof(*num_requests));
4574
4575 // for all search points
4576 for (size_t i = 0; i < count; ++i) {
4577
4578 // generate bounding circles for all search points
4579 struct bounding_circle bnd_circle;
4580 memcpy(bnd_circle.base_vector, search_coords[i],
4581 3 * sizeof(search_coords[0][0]));
4582 if (compare_angles(max_search_distance_angle, ubounds[i]) < 0)
4583 ubounds[i] = max_search_distance_angle;
4584
4585 bnd_circle.inc_angle = ubounds[i];
4586
4587 ENSURE_ARRAY_SIZE(request_ranks, request_ranks_array_size,
4588 num_request_ranks + (size_t)comm_size);
4589
4590 // search for processes that might be able to contribute to the search
4591 // results
4592 int * curr_request_ranks = request_ranks + num_request_ranks;
4594 grid_pair->proc_sphere_part, bnd_circle,
4595 curr_request_ranks, num_requests + i);
4596
4597 // remove requests for local process
4598 int new_num_requests = 0;
4599 for (int j = 0; j < num_requests[i]; ++j) {
4600 if (curr_request_ranks[j] == comm_rank) continue;
4601 if (new_num_requests != j)
4602 curr_request_ranks[new_num_requests] = curr_request_ranks[j];
4603 ++new_num_requests;
4604 }
4605
4606 num_request_ranks += (size_t)(num_requests[i] = new_num_requests);
4607 }
4608
4609 //---------------------------------------------------------------------------
4610 // send bounding circles to remote processes and receive potential results
4611 // (center of the bounding circle is the actual search point and the radius
4612 // is the upper bound for the search distance for each point)
4613 //---------------------------------------------------------------------------
4614
4615 size_t * sendcounts, * recvcounts, * sdispls, * rdispls;
4617 1, &sendcounts, &recvcounts, &sdispls, &rdispls, comm);
4618
4619 for (size_t i = 0; i < num_request_ranks; ++i) sendcounts[request_ranks[i]]++;
4620
4622 1, sendcounts, recvcounts, sdispls, rdispls, comm);
4623
4624 size_t recv_count = rdispls[comm_size-1] + recvcounts[comm_size-1];
4625
4626 struct bounding_circle * bnd_circles =
4627 xmalloc((num_request_ranks + recv_count) * sizeof(*bnd_circles));
4628 struct bounding_circle * send_bnd_circles = bnd_circles;
4629 struct bounding_circle * recv_bnd_circles = bnd_circles + num_request_ranks;
4630
4631 // pack bounding circles
4632 for (size_t i = 0, k = 0; i < count; ++i) {
4633 for (int j = 0; j < num_requests[i]; ++j, ++k) {
4634 struct bounding_circle * curr_bnd_circle =
4635 send_bnd_circles + sdispls[request_ranks[k]+1];
4636 sdispls[request_ranks[k]+1]++;
4637 memcpy(curr_bnd_circle->base_vector, search_coords[i],
4638 3 * sizeof(search_coords[0][0]));
4639 curr_bnd_circle->inc_angle = ubounds[i];
4640 }
4641 }
4642
4643 free(num_requests);
4644 free(request_ranks);
4645 free(ubounds);
4646
4647 MPI_Datatype bnd_circle_dt = yac_get_bounding_circle_mpi_datatype(comm);
4648
4649 // exchange requests to other processes
4651 send_bnd_circles, sendcounts, sdispls,
4652 recv_bnd_circles, recvcounts, rdispls,
4653 sizeof(*send_bnd_circles), bnd_circle_dt, comm, routine, __LINE__);
4654
4655 yac_mpi_call(MPI_Type_free(&bnd_circle_dt), comm);
4656
4657 //---------------------------------------------------------------------------
4658 // do n nearest neighbour search for the received coordinates and return
4659 // results potentially required by original process
4660 //---------------------------------------------------------------------------
4661
4662 size_t * result_points = NULL;
4663 size_t result_points_array_size = 0;
4664 size_t * num_results_points =
4665 xmalloc(recv_count * sizeof(*num_results_points));
4667 sphere_part, recv_count, recv_bnd_circles, n, &result_points,
4668 &result_points_array_size, num_results_points);
4669
4670 free(bnd_circles);
4672
4673 // compact results
4674 size_t total_num_result_points = 0;
4675 size_t offset = 0, k = 0;
4676 for (int i = 0; i < comm_size; ++i) {
4677 size_t curr_num_result_points = 0;
4678 for (size_t j = 0; j < recvcounts[i]; ++j, ++k)
4679 curr_num_result_points += num_results_points[k];
4680 size_t new_num_result_points = curr_num_result_points;
4681 qsort(
4682 result_points + offset,
4683 new_num_result_points, sizeof(*result_points), compare_size_t);
4685 result_points + offset, &new_num_result_points);
4686 memmove(
4687 result_points + total_num_result_points,
4688 result_points + offset, new_num_result_points *
4689 sizeof(*result_points));
4690 total_num_result_points += new_num_result_points;
4691 offset += curr_num_result_points;
4692 sendcounts[i] = new_num_result_points;
4693 }
4694 free(num_results_points);
4695
4697 1, sendcounts, recvcounts, sdispls, rdispls, comm);
4698 recv_count = rdispls[comm_size-1] + recvcounts[comm_size-1];
4699
4700 yac_int const * global_ids =
4701 yac_dist_grid_get_global_ids(dist_grid, field.location);
4702
4703 struct single_remote_point * single_remote_point_buffer =
4704 xmalloc((total_num_result_points + recv_count) *
4705 sizeof(*single_remote_point_buffer));
4706 struct single_remote_point * id_send_buffer = single_remote_point_buffer;
4707 struct single_remote_point * id_recv_buffer = single_remote_point_buffer +
4708 total_num_result_points;
4709 for (size_t i = 0; i < total_num_result_points; ++i) {
4710 size_t orig_pos = result_points[i];
4711 id_send_buffer[i].global_id = global_ids[orig_pos];
4712 id_send_buffer[i].data.rank = comm_rank;
4713 id_send_buffer[i].data.orig_pos = (uint64_t)orig_pos;
4714 }
4715 free(result_points);
4716
4717 MPI_Datatype single_remote_point_dt =
4719
4720 // exchange results to other processes
4722 id_send_buffer, sendcounts, sdispls+1, id_recv_buffer, recvcounts, rdispls,
4723 sizeof(*id_send_buffer), single_remote_point_dt, comm, routine, __LINE__);
4724 yac_mpi_call(MPI_Type_free(&single_remote_point_dt), comm);
4725 yac_free_comm_buffers(sendcounts, recvcounts, sdispls, rdispls);
4726
4727 //---------------------------------------------------------------------------
4728 // integrate potential results into local part of the distributed grid
4729 //---------------------------------------------------------------------------
4730
4731 // convert all remote ids to local ones, extend local dist_grid data,
4732 // if necessary
4733 size_t * temp_idx = xmalloc(recv_count * sizeof(*temp_idx));
4735 dist_grid, id_recv_buffer, recv_count, field.location, temp_idx);
4736 free(temp_idx);
4737 free(single_remote_point_buffer);
4738
4739 //---------------------------------------------------------------------------
4740 // do the actual nnn search
4741 //---------------------------------------------------------------------------
4742
4744 dist_grid, field, count, search_coords, n, max_search_distance_angle.cos,
4745 local_ids);
4746}
4747
4749 struct yac_dist_grid_pair * grid_pair, char const * grid_name,
4750 const_bounding_circle_pointer bnd_circles, size_t count, size_t ** cells,
4751 size_t * num_results_per_bnd_circle, struct yac_interp_field field) {
4752
4753 char const * routine = "yac_dist_grid_pair_do_bnd_circle_search";
4754
4755 MPI_Comm comm = grid_pair->comm;
4756 int comm_rank, comm_size;
4757 yac_mpi_call(MPI_Comm_rank(comm, &comm_rank), comm);
4758 yac_mpi_call(MPI_Comm_size(comm, &comm_size), comm);
4759
4760 //---------------------------------------------------------------------------
4761 // match bounding circles with YAC internal decomposition
4762 //---------------------------------------------------------------------------
4763
4764 struct yac_dist_grid * dist_grid =
4765 yac_dist_grid_pair_get_dist_grid(grid_pair, grid_name);
4766
4767 int * num_ranks = xcalloc(count, sizeof(*num_ranks));
4768 int * rank_buffer = NULL;
4769 size_t rank_buffer_size = 0;
4770 size_t rank_buffer_array_size = 0;
4771
4772 for (size_t i = 0; i < count; ++i) {
4773
4774 ENSURE_ARRAY_SIZE(rank_buffer, rank_buffer_array_size,
4775 rank_buffer_size + (size_t)comm_size);
4776
4777 // finds all processes whose core area overlaps with the bounding circle
4778 // of the current cell
4779 // beware: even if the core area of a process does not overlap with the
4780 // bounding circle, it may have core cells that overlap nevertheless
4782 grid_pair->proc_sphere_part, bnd_circles[i],
4783 rank_buffer + rank_buffer_size, num_ranks + i);
4784 rank_buffer_size += (size_t)(num_ranks[i]);
4785 }
4786
4787 //---------------------------------------------------------------------------
4788 // relocate bounding circles according to YAC internal decomposition
4789 //---------------------------------------------------------------------------
4790
4791 size_t * size_t_buffer =
4792 xmalloc(4 * (size_t)comm_size * sizeof(*size_t_buffer));
4793 size_t * result_sendcounts = size_t_buffer + 0 * comm_size;
4794 size_t * result_recvcounts = size_t_buffer + 1 * comm_size;
4795 size_t * result_sdispls = size_t_buffer + 2 * comm_size;
4796 size_t * result_rdispls = size_t_buffer + 3 * comm_size;
4797
4798 size_t * sendcounts, * recvcounts, * sdispls, * rdispls;
4800 1, &sendcounts, &recvcounts, &sdispls, &rdispls, comm);
4801
4802 for (size_t i = 0, offset = 0; i < count; ++i) {
4803 int curr_num_ranks = num_ranks[i];
4804 int * ranks = rank_buffer + offset;
4805 offset += (size_t)curr_num_ranks;
4806 for (int j = 0; j < curr_num_ranks; ++j) sendcounts[ranks[j]]++;
4807 }
4808
4809 // local overlaps do not need to be send around
4810 size_t local_count = sendcounts[comm_rank];
4811 sendcounts[comm_rank] = 0;
4812
4814 1, sendcounts, recvcounts, sdispls, rdispls, comm);
4815
4816 size_t send_count = sdispls[comm_size] + sendcounts[comm_size-1];
4817 size_t recv_count = rdispls[comm_size-1] + recvcounts[comm_size-1];
4818
4819 struct bounding_circle * bnd_circle_buffer =
4820 xmalloc((send_count + recv_count + local_count) *
4821 sizeof(*bnd_circle_buffer));
4822 struct bounding_circle * send_buffer = bnd_circle_buffer;
4823 struct bounding_circle * recv_buffer = bnd_circle_buffer + send_count;
4824 struct bounding_circle * local_buffer =
4825 bnd_circle_buffer + send_count + recv_count;
4826
4827 // pack bounding circles
4828 for (size_t i = 0, offset = 0, local_offset = 0; i < count; ++i) {
4829 int curr_num_ranks = num_ranks[i];
4830 int * ranks = rank_buffer + offset;
4831 offset += (size_t)curr_num_ranks;
4832 for (int j = 0; j < curr_num_ranks; ++j) {
4833 int rank = ranks[j];
4834 if (rank == comm_rank)
4835 local_buffer[local_offset++] = bnd_circles[i];
4836 else
4837 send_buffer[sdispls[rank + 1]++] = bnd_circles[i];
4838 }
4839 }
4840
4841 MPI_Datatype bnd_circle_dt = yac_get_bounding_circle_mpi_datatype(comm);
4842 yac_mpi_call(MPI_Type_commit(&bnd_circle_dt), comm);
4843
4844 // exchange bounding circles
4846 send_buffer, sendcounts, sdispls, recv_buffer, recvcounts, rdispls,
4847 sizeof(*send_buffer), bnd_circle_dt, comm, routine, __LINE__);
4848
4849 //---------------------------------------------------------------------------
4850 // match bounding circles with the locally stored cells
4851 //---------------------------------------------------------------------------
4852
4853 yac_mpi_call(MPI_Type_free(&bnd_circle_dt), comm);
4854
4855 struct bnd_sphere_part_search * cell_sphere_part =
4856 dist_grid_pair_get_cell_sphere_part(grid_pair, grid_name);
4857
4858 size_t * local_cells = NULL;
4859 size_t * num_local_cells_per_bnd_circle =
4860 xmalloc((recv_count + local_count) *
4861 sizeof(*num_local_cells_per_bnd_circle));
4862
4863 uint64_t * uint64_t_buffer =
4864 xmalloc((send_count + recv_count + local_count) *
4865 sizeof(*uint64_t_buffer));
4866 uint64_t * num_local_cells_per_bnd_circle_uint64_t = uint64_t_buffer;
4867 uint64_t * num_remote_cells_per_bnd_circle =
4868 uint64_t_buffer + recv_count + local_count;
4869
4870 // search for received bounding circles in local data
4872 cell_sphere_part, recv_buffer, recv_count + local_count, &local_cells,
4873 num_local_cells_per_bnd_circle);
4874
4875 //---------------------------------------------------------------------------
4876 // check results (apply cell field mask, if available, and check actual
4877 // overlap of cells with the bounding circle
4878 //---------------------------------------------------------------------------
4879
4880 int const * field_mask =
4881 (field.location == YAC_LOC_CELL)?
4882 yac_dist_grid_get_field_mask(dist_grid, field):NULL;
4883
4884 struct bounding_circle * cell_bnd_circles = dist_grid->cell_bnd_circles;
4885
4886 // check field mask and actual overlap of bounding circles
4887 for (size_t i = 0, offset = 0, new_offset = 0;
4888 i < recv_count + local_count; ++i) {
4889
4890 struct bounding_circle * curr_bnd_circle = recv_buffer + i;
4891 size_t curr_num_results = num_local_cells_per_bnd_circle[i];
4892
4893 // remove cells whose bounding circle do not overlap with the current one
4894 uint64_t new_num_results = 0;
4895 for (size_t j = 0; j < curr_num_results; ++j, ++offset) {
4896 size_t local_cell_id = local_cells[offset];
4897 if (!yac_extents_overlap(curr_bnd_circle,
4898 cell_bnd_circles + local_cell_id)) continue;
4899 if ((field_mask == NULL) || (field_mask[local_cell_id])) {
4900 if (offset != new_offset) local_cells[new_offset] = local_cell_id;
4901 new_num_results++;
4902 new_offset++;
4903 }
4904 }
4905 num_local_cells_per_bnd_circle_uint64_t[i] = new_num_results;
4906 }
4907 free(num_local_cells_per_bnd_circle);
4908 free(bnd_circle_buffer);
4909
4910 //---------------------------------------------------------------------------
4911 // return results
4912 //---------------------------------------------------------------------------
4913
4914 // exchange number of results per bounding circle
4916 num_local_cells_per_bnd_circle_uint64_t, recvcounts, rdispls,
4917 num_remote_cells_per_bnd_circle, sendcounts, sdispls,
4918 sizeof(*num_local_cells_per_bnd_circle_uint64_t), MPI_UINT64_T, comm,
4919 routine, __LINE__);
4920
4921 size_t saccu = 0, raccu = 0, soffset = 0, roffset = 0;
4922 for (int i = 0; i < comm_size; ++i) {
4923
4924 result_sdispls[i] = saccu;
4925 result_rdispls[i] = raccu;
4926
4927 size_t sendcount = recvcounts[i];
4928 size_t recvcount = sendcounts[i];
4929
4930 result_sendcounts[i] = 0;
4931 result_recvcounts[i] = 0;
4932 for (size_t j = 0; j < sendcount; ++j, ++soffset)
4933 result_sendcounts[i] +=
4934 (size_t)(num_local_cells_per_bnd_circle_uint64_t[soffset]);
4935 for (size_t j = 0; j < recvcount; ++j, ++roffset)
4936 result_recvcounts[i] +=
4937 (size_t)(num_remote_cells_per_bnd_circle[roffset]);
4938
4939 saccu += result_sendcounts[i];
4940 raccu += result_recvcounts[i];
4941 }
4942
4943 // count the number of results for bounding circles, which had a match with#
4944 // their original process
4945 size_t result_local_count = 0;
4946 for (size_t i = recv_count; i < recv_count + local_count; ++i)
4947 result_local_count += (size_t)(num_local_cells_per_bnd_circle_uint64_t[i]);
4948
4949 size_t result_send_count = (size_t)(result_sdispls[comm_size-1]) +
4950 (size_t)(result_sendcounts[comm_size-1]);
4951 size_t result_recv_count = (size_t)(result_rdispls[comm_size-1]) +
4952 (size_t)(result_recvcounts[comm_size-1]);
4953
4954 struct single_remote_point * single_remote_point_buffer =
4955 xmalloc((result_recv_count + result_send_count) *
4956 sizeof(*single_remote_point_buffer));
4957 struct single_remote_point * id_send_buffer = single_remote_point_buffer;
4958 struct single_remote_point * id_recv_buffer = single_remote_point_buffer +
4959 result_send_count;
4960
4961 yac_int * cell_ids = dist_grid->ids[YAC_LOC_CELL];
4962
4963 for (size_t i = 0; i < result_send_count; ++i) {
4964 size_t local_cell_id = local_cells[i];
4965 id_send_buffer[i].global_id = cell_ids[local_cell_id];
4966 id_send_buffer[i].data.rank = comm_rank;
4967 id_send_buffer[i].data.orig_pos = local_cell_id;
4968 }
4969
4970 MPI_Datatype single_remote_point_dt =
4972
4973 // redistribute results (global ids of found source cells)
4975 id_send_buffer, result_sendcounts, result_sdispls,
4976 id_recv_buffer, result_recvcounts, result_rdispls,
4977 sizeof(*id_send_buffer), single_remote_point_dt, comm,
4978 routine, __LINE__);
4979
4980 yac_mpi_call(MPI_Type_free(&single_remote_point_dt), comm);
4981
4982 size_t * new_local_cells =
4983 xmalloc((result_recv_count + result_local_count) *
4984 sizeof(*new_local_cells));
4985
4986 memcpy(new_local_cells + result_recv_count,
4987 local_cells + result_send_count,
4988 result_local_count * sizeof(*new_local_cells));
4989 free(local_cells);
4990
4991 //---------------------------------------------------------------------------
4992 // convert results into local ids and update local part of the distributed
4993 // grid if necessary
4994 //---------------------------------------------------------------------------
4995
4996 // convert all remote ids to local ones, extend local dist_grid data,
4997 // if necessary
4999 dist_grid, id_recv_buffer, result_recv_count, YAC_LOC_CELL, new_local_cells);
5000
5001 free(single_remote_point_buffer);
5002
5003 size_t * reorder_idx =
5004 xmalloc((result_recv_count + result_local_count) * sizeof(*reorder_idx));
5005
5006 memset(
5007 num_results_per_bnd_circle, 0, count * sizeof(*num_results_per_bnd_circle));
5008
5009 for (size_t i = 0, offset = 0, reorder = 0, local_search_idx = recv_count,
5010 local_offset = result_recv_count; i < count; ++i) {
5011 int curr_num_ranks = num_ranks[i];
5012 int * ranks = rank_buffer + offset;
5013 offset += (size_t)curr_num_ranks;
5014 for (int j = 0; j < curr_num_ranks; ++j) {
5015 int rank = ranks[j];
5016 if (rank == comm_rank) {
5017 uint64_t curr_num_results =
5018 num_local_cells_per_bnd_circle_uint64_t[local_search_idx++];
5019 num_results_per_bnd_circle[i] += (size_t)curr_num_results;
5020 for (uint64_t k = 0; k < curr_num_results; ++k, ++reorder)
5021 reorder_idx[local_offset++] = reorder;
5022 } else {
5023 size_t rank_pos = sdispls[rank]++;
5024 uint64_t curr_num_results = num_remote_cells_per_bnd_circle[rank_pos];
5025 num_results_per_bnd_circle[i] += (size_t)curr_num_results;
5026 for (uint64_t k = 0; k < curr_num_results; ++k, ++reorder)
5027 reorder_idx[result_rdispls[rank]++] = reorder;
5028 }
5029 }
5030 }
5031 free(uint64_t_buffer);
5032 free(num_ranks);
5033 free(rank_buffer);
5034 free(size_t_buffer);
5035 yac_free_comm_buffers(sendcounts, recvcounts, sdispls, rdispls);
5036
5038 reorder_idx, result_recv_count + result_local_count, new_local_cells);
5039 free(reorder_idx);
5040
5041 // remove duplicated results
5042 for (size_t i = 0, offset = 0, new_offset = 0; i < count; ++i) {
5043
5044 size_t * curr_local_cells = new_local_cells + offset;
5045 size_t curr_num_results_per_bnd_circle = num_results_per_bnd_circle[i];
5046 size_t new_num_results_per_bnd_circle = 0;
5047 size_t prev_cell = SIZE_MAX;
5048 offset += curr_num_results_per_bnd_circle;
5049
5051 curr_local_cells, curr_num_results_per_bnd_circle, NULL);
5052
5053 for (size_t j = 0; j < curr_num_results_per_bnd_circle; ++j) {
5054 size_t curr_cell = curr_local_cells[j];
5055 if (curr_cell != prev_cell) {
5056 new_local_cells[new_offset++] = (prev_cell = curr_cell);
5057 ++new_num_results_per_bnd_circle;
5058 }
5059 }
5060 num_results_per_bnd_circle[i] = new_num_results_per_bnd_circle;
5061 }
5062
5063 *cells = new_local_cells;
5064}
5065
5067 struct yac_dist_grid_pair * grid_pair,
5068 char const * search_grid_name, char const * result_grid_name,
5069 size_t * search_cells, size_t count, size_t ** result_cells,
5070 size_t * num_results_per_search_cell, struct yac_interp_field result_field) {
5071
5072 struct bounding_circle * search_bnd_circles =
5073 xmalloc(count * sizeof(*search_bnd_circles));
5074
5075 struct yac_dist_grid * search_dist_grid =
5076 yac_dist_grid_pair_get_dist_grid(grid_pair, search_grid_name);
5077 struct yac_dist_grid * result_dist_grid =
5078 yac_dist_grid_pair_get_dist_grid(grid_pair, result_grid_name);
5079
5080 const_bounding_circle_pointer search_grid_cell_bnd_circles =
5081 search_dist_grid->cell_bnd_circles;
5082
5083 for (size_t i = 0; i < count; ++i)
5084 search_bnd_circles[i] = search_grid_cell_bnd_circles[search_cells[i]];
5085
5087 grid_pair, result_grid_name, search_bnd_circles, count, result_cells,
5088 num_results_per_search_cell, result_field);
5089
5090 size_t total_num_result_cells = 0;
5091
5092 // struct yac_grid_cell search_cell, result_cell;
5093 // yac_init_grid_cell(&search_cell);
5094 // yac_init_grid_cell(&result_cell);
5095
5096 // filter out obvious mismachtes
5097 // (currently only the bounding circles are checked)
5098 for (size_t i = 0, offset = 0; i < count; ++i) {
5099
5100 size_t curr_num_results_per_bnd_circle = num_results_per_search_cell[i];
5101 size_t new_num_results_per_search_cell = 0;
5102 size_t * curr_result_cells = *result_cells + offset;
5103 offset += curr_num_results_per_bnd_circle;
5104
5105 // yac_const_basic_grid_data_get_grid_cell(
5106 // (struct yac_const_basic_grid_data *)search_dist_grid,
5107 // search_cells[i], &search_cell);
5108
5109 for (size_t j = 0; j < curr_num_results_per_bnd_circle; ++j) {
5110
5111 size_t curr_result_cell = curr_result_cells[j];
5112
5113 // yac_const_basic_grid_data_get_grid_cell(
5114 // (struct yac_const_basic_grid_data *)result_dist_grid,
5115 // curr_result_cell, &result_cell);
5116
5117 // if (yac_check_overlap_cells2(
5118 // search_cell, search_dist_grid->cell_bnd_circles[search_cells[i]],
5119 // result_cell, result_dist_grid->cell_bnd_circles[curr_result_cell])) {
5121 search_bnd_circles + i,
5122 result_dist_grid->cell_bnd_circles + curr_result_cell)) {
5123
5124 (*result_cells)[total_num_result_cells++] = curr_result_cell;
5125 ++new_num_results_per_search_cell;
5126 }
5127 }
5128
5129 num_results_per_search_cell[i] = new_num_results_per_search_cell;
5130 }
5131
5132 // yac_free_grid_cell(&result_cell);
5133 // yac_free_grid_cell(&search_cell);
5134
5135 // *result_cells =
5136 // xrealloc(*result_cells, total_num_result_cells * sizeof(**result_cells));
5137 free(search_bnd_circles);
5138}
5139
5141 struct yac_dist_grid * dist_grid, size_t edge_id) {
5142
5143 return
5145 dist_grid->edge_to_vertex, dist_grid->vertex_coordinates, edge_id);
5146}
5147
5149 struct yac_dist_grid * dist_grid,
5150 struct proc_sphere_part_node * proc_sphere_part,
5151 size_t * cells, size_t count, size_t * neighbours) {
5152
5153 char const * routine = "yac_dist_grid_get_cell_neighbours";
5154
5155 // generate edge to cell
5156 yac_size_t_2_pointer edge_to_cell =
5158 dist_grid->cell_to_edge, dist_grid->num_vertices_per_cell,
5159 NULL, dist_grid->total_count[YAC_LOC_CELL],
5160 dist_grid->total_count[YAC_LOC_EDGE]);
5161
5162 // get maximum number of edges per cell
5163 int max_num_edges_per_cell = 0;
5164 for (size_t i = 0; i < dist_grid->total_count[YAC_LOC_CELL]; ++i)
5165 if (max_num_edges_per_cell < dist_grid->num_vertices_per_cell[i])
5166 max_num_edges_per_cell = dist_grid->num_vertices_per_cell[i];
5167
5168 yac_size_t_2_pointer edge_vertices =
5169 xmalloc((size_t)max_num_edges_per_cell * sizeof(*edge_vertices));
5170
5171 size_t neigh_idx = 0;
5172
5174 size_t missing_edge_neighbour_array_size = 0;
5175 size_t num_missing_neighbours = 0;
5176
5177 // for each cell
5178 for (size_t i = 0; i < count; ++i) {
5179
5180 size_t curr_cell = cells[i];
5181
5182 // get all edges
5183 size_t curr_num_edges = dist_grid->num_vertices_per_cell[curr_cell];
5184 size_t const * cell_edges =
5185 dist_grid->cell_to_edge + dist_grid->cell_to_edge_offsets[curr_cell];
5186 for (size_t j = 0; j < curr_num_edges; ++j) {
5187 size_t const * curr_edge_to_vertex =
5188 dist_grid->edge_to_vertex[cell_edges[j]];
5189 edge_vertices[j][0] = curr_edge_to_vertex[0];
5190 edge_vertices[j][1] = curr_edge_to_vertex[1];
5191 }
5192
5194 missing_edge_neighbour, missing_edge_neighbour_array_size,
5195 num_missing_neighbours + curr_num_edges);
5196
5197 // get the neighbour cells by following the edges and vertices around
5198 // the cell
5199 size_t prev_vertex = edge_vertices[0][0];
5200 for (size_t j = 0, edge_idx = 0; j < curr_num_edges; ++j, ++neigh_idx) {
5201
5202 // get the neighbour cell associated with the current edge
5203 size_t curr_edge = cell_edges[edge_idx];
5204 size_t * curr_edge_cells = edge_to_cell[curr_edge];
5205 size_t other_cell = curr_edge_cells[curr_edge_cells[0] == curr_cell];
5206 neighbours[neigh_idx] = other_cell;
5207
5208 if (other_cell == SIZE_MAX) {
5209 struct missing_edge_neighbour * curr_miss_neigh =
5210 missing_edge_neighbour + num_missing_neighbours++;
5211 curr_miss_neigh->edge.local_id = curr_edge;
5212 curr_miss_neigh->edge.global_id =
5213 dist_grid->ids[YAC_LOC_EDGE][curr_edge];
5214 curr_miss_neigh->cell.local_id = curr_cell;
5215 curr_miss_neigh->cell.global_id =
5216 dist_grid->ids[YAC_LOC_CELL][curr_cell];
5217 curr_miss_neigh->neigh_idx = neigh_idx;
5218 }
5219
5220 // get an edge that shares a vertex with the current edge
5221 size_t new_edge_idx = SIZE_MAX;
5222 for (size_t k = 0; k < curr_num_edges; ++k) {
5223 if (k == edge_idx) continue;
5224 else if (edge_vertices[k][0] == prev_vertex) {
5225 new_edge_idx = k;
5226 prev_vertex = edge_vertices[k][1];
5227 break;
5228 } else if (edge_vertices[k][1] == prev_vertex) {
5229 new_edge_idx = k;
5230 prev_vertex = edge_vertices[k][0];
5231 break;
5232 }
5233 }
5235 new_edge_idx < SIZE_MAX,
5236 "ERROR(%s): inconsistent cell_to_edge/edge_to_vertex data", routine)
5237 edge_idx = new_edge_idx;
5238 }
5239
5240 // check whether we went once completely around the cell
5242 prev_vertex == edge_vertices[0][0],
5243 "ERROR(%s): inconsistent cell_to_edge/edge_to_vertex data", routine)
5244 }
5245
5246 { // get the missing neighbours
5247 MPI_Comm comm = dist_grid->comm;
5248 int comm_rank, comm_size;
5249 yac_mpi_call(MPI_Comm_rank(comm, &comm_rank), comm);
5250 yac_mpi_call(MPI_Comm_size(comm, &comm_size), comm);
5251
5252 size_t * sendcounts, * recvcounts, * sdispls, * rdispls;
5254 1, &sendcounts, &recvcounts, &sdispls, &rdispls, comm);
5255 int * int_buffer =
5256 xmalloc(
5257 ((size_t)comm_size + num_missing_neighbours) * sizeof(*int_buffer));
5258 int * temp_ranks = int_buffer;
5259 int * num_ranks = int_buffer + comm_size;
5260 memset(num_ranks, 0, num_missing_neighbours * sizeof(*num_ranks));
5261
5262 int * rank_buffer = NULL;
5263 size_t rank_buffer_array_size = 0;
5264 size_t rank_buffer_size = 0;
5265
5266 for (size_t i = 0; i < num_missing_neighbours; ++i) {
5267
5268 // alternatively get the dist owner ranks for all cell vertices
5269 int curr_num_ranks;
5271 proc_sphere_part,
5273 dist_grid, missing_edge_neighbour[i].edge.local_id),
5274 temp_ranks, &curr_num_ranks);
5275
5276 ENSURE_ARRAY_SIZE(rank_buffer, rank_buffer_array_size,
5277 rank_buffer_size + (size_t)curr_num_ranks);
5278
5279 for (int j = 0; j < curr_num_ranks; ++j) {
5280 int curr_rank = temp_ranks[j];
5281 if (curr_rank != comm_rank) {
5282 sendcounts[curr_rank] += 2;
5283 num_ranks[i]++;
5284 rank_buffer[rank_buffer_size++] = curr_rank;
5285 }
5286 }
5287 }
5288
5290 1, sendcounts, recvcounts, sdispls, rdispls, comm);
5291
5292 size_t send_count =
5293 (sdispls[comm_size] + sendcounts[comm_size-1])/2;
5294 size_t recv_count =
5295 (rdispls[comm_size-1] + recvcounts[comm_size-1])/2;
5296
5297 yac_int * yac_int_buffer =
5298 xmalloc(2 * (send_count + recv_count) * sizeof(*yac_int_buffer));
5299 yac_int * send_buffer = yac_int_buffer;
5300 yac_int * recv_buffer = yac_int_buffer + 2 * send_count;
5301 size_t * result_reorder_idx =
5302 xmalloc(send_count * sizeof(*result_reorder_idx));
5303
5304 // pack send buffer
5305 for (size_t i = 0, k = 0, rank_offset = 0; i < num_missing_neighbours; ++i) {
5306
5307 int * curr_rank_buffer = rank_buffer + rank_offset;
5308 int curr_num_ranks = num_ranks[i];
5309 rank_offset += (size_t)curr_num_ranks;
5310
5311 for (int j = 0; j < curr_num_ranks; ++j, ++k) {
5312
5313 int rank = curr_rank_buffer[j];
5314
5315 if (rank == comm_rank) continue;
5316
5317 size_t pos = sdispls[rank + 1];
5318 sdispls[rank + 1] += 2;
5319
5320 send_buffer[pos + 0] = missing_edge_neighbour[i].edge.global_id;
5321 send_buffer[pos + 1] = missing_edge_neighbour[i].cell.global_id;
5322 result_reorder_idx[pos / 2] = missing_edge_neighbour[i].neigh_idx;
5323 }
5324 }
5325 free(rank_buffer);
5327
5328 // redistribute requested global ids and remote points of core points
5329 yac_alltoallv_yac_int_p2p(
5330 send_buffer, sendcounts, sdispls,
5331 recv_buffer, recvcounts, rdispls, comm, routine, __LINE__);
5332
5333 yac_int * request_edge_ids =
5334 xmalloc(recv_count * sizeof(*request_edge_ids));
5335 size_t * reorder_idx = xmalloc(recv_count * sizeof(*reorder_idx));
5336 struct single_remote_point * point_info_buffer =
5337 xmalloc(
5338 (send_count + recv_count) * sizeof(*point_info_buffer));
5339 struct single_remote_point * point_send_buffer = point_info_buffer;
5340 struct single_remote_point * point_recv_buffer =
5341 point_info_buffer + recv_count;
5342 for (size_t i = 0; i < recv_count; ++i) {
5343 request_edge_ids[i] = recv_buffer[2 * i + 0];
5344 reorder_idx[i] = i;
5345 }
5346
5348 request_edge_ids, recv_count, reorder_idx);
5349 yac_int * sorted_edge_ids = dist_grid->sorted_ids[YAC_LOC_EDGE];
5350 size_t * sorted_edge_reorder_idx =
5351 dist_grid->sorted_reorder_idx[YAC_LOC_EDGE];
5352 size_t num_edges = dist_grid->total_count[YAC_LOC_EDGE];
5353 yac_int * cell_ids = dist_grid->ids[YAC_LOC_CELL];
5354
5355 // lookup the requested edge locally
5356 for (size_t i = 0, j = 0; i < recv_count; ++i) {
5357
5358 yac_int curr_edge_id = request_edge_ids[i];
5359 size_t curr_reorder_idx = reorder_idx[i];
5360
5361 while ((j < num_edges) && (sorted_edge_ids[j] < curr_edge_id)) ++j;
5362
5363 // if the edge is not available locally
5364 if ((j >= num_edges) || (sorted_edge_ids[j] != curr_edge_id)) {
5365 point_send_buffer[curr_reorder_idx] =
5366 (struct single_remote_point)
5367 {.global_id = XT_INT_MAX,
5368 .data = {.rank = comm_rank, .orig_pos = UINT64_MAX}};
5369 continue;
5370 }
5371
5372 // id of the cell that is available on the other process
5373 yac_int available_edge_cell_id = recv_buffer[2 * curr_reorder_idx + 1];
5374
5375 size_t * local_edge_cell_ids = edge_to_cell[sorted_edge_reorder_idx[j]];
5376 yac_int global_edge_cell_ids[2];
5377 for (int k = 0; k < 2; ++k)
5378 global_edge_cell_ids[k] =
5379 (local_edge_cell_ids[k] == SIZE_MAX)?
5380 XT_INT_MAX:cell_ids[local_edge_cell_ids[k]];
5381
5382 int missing_idx = global_edge_cell_ids[0] == available_edge_cell_id;
5383
5384 // consistency check
5386 (global_edge_cell_ids[missing_idx^1] == available_edge_cell_id) ||
5387 (global_edge_cell_ids[missing_idx^1] == XT_INT_MAX),
5388 "ERROR(%s): inconsistent cell edge grid data", routine)
5389
5390 point_send_buffer[curr_reorder_idx].global_id =
5391 global_edge_cell_ids[missing_idx];
5392 point_send_buffer[curr_reorder_idx].data.rank = comm_rank;
5393 point_send_buffer[curr_reorder_idx].data.orig_pos =
5394 (local_edge_cell_ids[missing_idx] == SIZE_MAX)?
5395 (uint64_t)UINT64_MAX:local_edge_cell_ids[missing_idx];
5396 }
5397 free(reorder_idx);
5398 free(request_edge_ids);
5399 free(yac_int_buffer);
5400
5401 for (int i = 0; i < comm_size; ++i) {
5402 sdispls[i] /= 2;
5403 rdispls[i] /= 2;
5404 sendcounts[i] /= 2;
5405 recvcounts[i] /= 2;
5406 }
5407
5408 MPI_Datatype single_remote_point_dt =
5410
5412 point_send_buffer, recvcounts, rdispls,
5413 point_recv_buffer, sendcounts, sdispls,
5414 sizeof(*point_send_buffer), single_remote_point_dt, comm,
5415 routine, __LINE__);
5416
5417 yac_mpi_call(MPI_Type_free(&single_remote_point_dt), comm);
5418
5419 struct single_remote_point_reorder * results =
5420 xmalloc(send_count * sizeof(*results));
5421
5422 for (size_t i = 0; i < send_count; ++i) {
5423 results[i].data = point_recv_buffer[i];
5424 results[i].reorder_idx = result_reorder_idx[i];
5425 }
5426
5427 qsort(results, send_count, sizeof(*results),
5429
5430 // remove duplicated results
5431 size_t result_count = 0;
5432 yac_int prev_global_id = XT_INT_MAX;
5433 for (size_t i = 0, prev_reorder_idx = SIZE_MAX; i < send_count; ++i) {
5434
5435 // if the current result does not contain useful data
5436 yac_int curr_global_id = results[i].data.global_id;
5437 if (curr_global_id == XT_INT_MAX) continue;
5438
5439 size_t curr_reorder_idx = results[i].reorder_idx;
5440 if (curr_reorder_idx != prev_reorder_idx){
5441
5442 results[result_count++] = results[i];
5443 prev_reorder_idx = curr_reorder_idx;
5444 prev_global_id = curr_global_id;
5445
5446 } else {
5447
5449 prev_global_id == curr_global_id,
5450 "ERROR(%s): inconsistent cell edge data", routine)
5451 }
5452 }
5453 for (size_t i = 0; i < result_count; ++i) {
5454 point_send_buffer[i] = results[i].data;
5455 result_reorder_idx[i] = results[i].reorder_idx;
5456 }
5457 free(results);
5458
5459 size_t * local_ids = xmalloc(result_count * sizeof(*local_ids));
5460
5462 dist_grid, point_send_buffer, result_count, YAC_LOC_CELL, local_ids);
5463
5464 for (size_t i = 0; i < result_count; ++i)
5465 neighbours[result_reorder_idx[i]] = local_ids[i];
5466
5467 free(local_ids);
5468 free(result_reorder_idx);
5469 free(point_send_buffer);
5470 free(int_buffer);
5471 yac_free_comm_buffers(sendcounts, recvcounts, sdispls, rdispls);
5472 }
5473
5474 free(edge_vertices);
5475 free(edge_to_cell);
5476}
5477
5479 struct yac_dist_grid_pair * grid_pair, char const * grid_name,
5480 size_t * cells, size_t count, size_t * neighbours) {
5481
5483 yac_dist_grid_pair_get_dist_grid(grid_pair, grid_name),
5484 grid_pair->proc_sphere_part, cells, count, neighbours);
5485}
5486
5488 struct yac_dist_grid * dist_grid, enum yac_location location,
5489 size_t * points, size_t count) {
5490
5491 struct remote_point * remote_points = xmalloc(count * sizeof(*remote_points));
5492
5493 CHECK_LOCATION("yac_dist_grid_get_remote_points")
5494 yac_int * global_ids = dist_grid->ids[location];
5495 struct remote_point_infos * point_infos = dist_grid->owners[location];
5496
5497 for (size_t i = 0; i < count; ++i) {
5498 remote_points[i].global_id = global_ids[points[i]];
5499 remote_points[i].data = point_infos[points[i]];
5500 }
5501
5502 return remote_points;
5503}
5504
5505static inline int
5507 return (int)(value / 128) % comm_size;
5508}
5509
5510static int get_global_id_pack_size(MPI_Comm comm) {
5511
5512 int global_id_pack_size;
5513
5515 MPI_Pack_size(1, yac_int_dt, comm, &global_id_pack_size), comm);
5516
5517 return global_id_pack_size;
5518}
5519
5520static void pack_global_id(
5521 yac_int global_id, void * buffer, int buffer_size, int * position,
5522 MPI_Comm comm) {
5523
5525 MPI_Pack(&global_id, 1, yac_int_dt, buffer,
5526 buffer_size, position, comm), comm);
5527}
5528
5530 void * buffer, int buffer_size, int * position, yac_int * global_id,
5531 MPI_Comm comm) {
5532
5534 MPI_Unpack(buffer, buffer_size, position, global_id, 1,
5535 yac_int_dt, comm), comm);
5536}
5537
5539 MPI_Datatype single_remote_point_dt, MPI_Comm comm) {
5540
5541 int pack_size;
5542
5544 MPI_Pack_size(1, single_remote_point_dt, comm, &pack_size), comm);
5545
5546 return pack_size;
5547}
5548
5550 struct single_remote_point * point,
5551 void * buffer, int buffer_size, int * position,
5552 MPI_Datatype single_remote_point_dt, MPI_Comm comm) {
5553
5555 MPI_Pack(point, 1, single_remote_point_dt, buffer,
5556 buffer_size, position, comm), comm);
5557}
5558
5560 void * buffer, int buffer_size, int * position,
5561 struct single_remote_point * point, MPI_Datatype single_remote_point_dt,
5562 MPI_Comm comm) {
5563
5565 MPI_Unpack(buffer, buffer_size, position, point, 1,
5566 single_remote_point_dt, comm), comm);
5567}
5568
5570 struct yac_dist_grid * dist_grid, enum yac_location location,
5571 yac_int * global_ids, size_t count, size_t * local_ids) {
5572
5573 char const * routine = "yac_dist_grid_global_to_local";
5574
5575 MPI_Comm comm = dist_grid->comm;
5576 int comm_rank, comm_size;
5577 yac_mpi_call(MPI_Comm_rank(comm, &comm_rank), comm);
5578 yac_mpi_call(MPI_Comm_size(comm, &comm_size), comm);
5579
5580 size_t * size_t_buffer =
5581 xmalloc((8 * (size_t)comm_size + 1) * sizeof(*size_t_buffer));
5582 size_t * sendcounts = size_t_buffer + 0 * comm_size;
5583 size_t * recvcounts = size_t_buffer + 2 * comm_size;
5584 size_t * sdispls = size_t_buffer + 4 * comm_size;
5585 size_t * rdispls = size_t_buffer + 5 * comm_size + 1;
5586 size_t * total_sendcounts = size_t_buffer + 6 * comm_size + 1;
5587 size_t * total_recvcounts = size_t_buffer + 7 * comm_size + 1;
5588 memset(sendcounts, 0, 2 * (size_t)comm_size * sizeof(*sendcounts));
5589
5590 size_t * core_points, core_count;
5591 struct yac_interp_field dummy_interp_field =
5592 {.location = location,
5593 .coordinates_idx = SIZE_MAX,
5594 .masks_idx = SIZE_MAX};
5596 dist_grid, dummy_interp_field, &core_points, &core_count);
5597 yac_int const * grid_global_ids =
5599
5600 int * rank_buffer = xmalloc((count + core_count) * sizeof(*rank_buffer));
5601 int * core_point_ranks = rank_buffer;
5602 int * global_id_ranks = rank_buffer + core_count;
5603
5604 size_t * global_id_reorder_idx =
5605 xmalloc(count * sizeof(*global_id_reorder_idx));
5606
5607 for (size_t i = 0; i < count; ++i) {
5608 int rank =
5609 (global_id_ranks[i] = compute_bucket(global_ids[i], comm_size));
5610 sendcounts[2 * rank + 0]++;
5611 global_id_reorder_idx[i] = i;
5612 }
5613
5614 yac_quicksort_index_int_size_t(global_id_ranks, count, global_id_reorder_idx);
5615
5616 for (size_t i = 0; i < core_count; ++i) {
5617 size_t point_idx = core_points[i];
5618 int rank =
5619 (core_point_ranks[i] =
5620 compute_bucket(grid_global_ids[point_idx], comm_size));
5621 sendcounts[2 * rank + 1]++;
5622 }
5623
5624 // sort core points by rank
5625 yac_quicksort_index_int_size_t(core_point_ranks, core_count, core_points);
5626
5627 // exchange number of requsted global ids, number of core points in dist_grid
5628 // and total pack size
5629 yac_mpi_call(MPI_Alltoall(sendcounts, 2, YAC_MPI_SIZE_T,
5630 recvcounts, 2, YAC_MPI_SIZE_T, comm), comm);
5631
5632 size_t recv_core_count = 0;
5633 for (int i = 0; i < comm_size; ++i)
5634 recv_core_count += recvcounts[2*i+1];
5635
5636 MPI_Datatype single_remote_point_dt =
5638 int global_id_pack_size = get_global_id_pack_size(comm);
5639 int core_point_pack_size =
5640 get_single_remote_point_pack_size(single_remote_point_dt, comm);
5641
5642 for (int i = 0; i < comm_size; ++i) {
5643 total_sendcounts[i] = sendcounts[2*i+0] * (size_t)global_id_pack_size +
5644 sendcounts[2*i+1] * (size_t)core_point_pack_size;
5645 total_recvcounts[i] = recvcounts[2*i+0] * (size_t)global_id_pack_size +
5646 recvcounts[2*i+1] * (size_t)core_point_pack_size;
5647 }
5648
5649 size_t saccu = 0, raccu = 0;
5650 sdispls[0] = 0;
5651 for (int i = 0; i < comm_size; ++i) {
5652 sdispls[i+1] = saccu;
5653 rdispls[i] = raccu;
5654 saccu += total_sendcounts[i];
5655 raccu += total_recvcounts[i];
5656 }
5657
5658 size_t send_size = sdispls[comm_size] + total_sendcounts[comm_size-1];
5659 size_t recv_size = rdispls[comm_size-1] + total_recvcounts[comm_size-1];
5660 void * pack_buffer = xmalloc(send_size + recv_size);
5661 void * send_buffer = pack_buffer;
5662 void * recv_buffer = (void*)((unsigned char *)pack_buffer + send_size);
5663
5664 // pack data
5665 for (size_t i = 0; i < count; ++i) {
5666 yac_int curr_global_id = global_ids[global_id_reorder_idx[i]];
5667 int rank = global_id_ranks[i];
5668 size_t pos = sdispls[rank + 1];
5669 int position = 0;
5671 curr_global_id, (void*)((unsigned char*)send_buffer + pos),
5672 global_id_pack_size, &position, comm);
5673 sdispls[rank + 1] += global_id_pack_size;
5674 }
5675 for (size_t i = 0; i < core_count; ++i) {
5676 size_t point_idx = core_points[i];
5677 int rank = core_point_ranks[i];
5678 size_t pos = sdispls[rank + 1];
5679 struct single_remote_point curr_core_point;
5680 curr_core_point.global_id = grid_global_ids[point_idx];
5681 curr_core_point.data.rank = comm_rank;
5682 curr_core_point.data.orig_pos = point_idx;
5683 int position = 0;
5685 &curr_core_point,
5686 (void*)((unsigned char*)send_buffer + pos),
5687 core_point_pack_size, &position, single_remote_point_dt, comm);
5688 sdispls[rank + 1] += core_point_pack_size;
5689 }
5690 free(rank_buffer);
5691 free(core_points);
5692
5693 // redistribute requested global ids and remote points of core points
5694 yac_alltoallv_packed_p2p(
5695 send_buffer, total_sendcounts, sdispls,
5696 recv_buffer, total_recvcounts, rdispls, comm, routine, __LINE__);
5697
5698 size_t num_requested_ids = 0;
5699 for(int i = 0; i < comm_size; ++i)
5700 num_requested_ids += recvcounts[2*i+0];
5701
5702 yac_int * request_global_ids =
5703 xmalloc(num_requested_ids * sizeof(*request_global_ids));
5704 size_t * reorder_idx =
5705 xmalloc(num_requested_ids * sizeof(*reorder_idx));
5706 struct single_remote_point * point_info_buffer =
5707 xmalloc((recv_core_count + num_requested_ids + count) *
5708 sizeof(*point_info_buffer));
5709 struct single_remote_point * recv_core_points = point_info_buffer;
5710 struct single_remote_point * send_point_info =
5711 point_info_buffer + recv_core_count;
5712 struct single_remote_point * recv_point_info =
5713 point_info_buffer + recv_core_count + num_requested_ids;
5714
5715 // unpack data
5716 num_requested_ids = 0;
5717 recv_core_count = 0;
5718 for (int i = 0; i < comm_size; ++i) {
5719
5720 size_t curr_num_requested_ids = recvcounts[2*i+0];
5721 size_t curr_num_core_points = recvcounts[2*i+1];
5722
5723 for (size_t j = 0; j < curr_num_requested_ids; ++j, ++num_requested_ids) {
5724
5725 int position = 0;
5727 recv_buffer, global_id_pack_size, &position,
5728 request_global_ids + num_requested_ids, comm);
5729 reorder_idx[num_requested_ids] = num_requested_ids;
5730 recv_buffer = (void*)((unsigned char*)recv_buffer + global_id_pack_size);
5731 }
5732 for (size_t j = 0; j < curr_num_core_points; ++j, ++recv_core_count) {
5733
5734 int position = 0;
5736 recv_buffer, core_point_pack_size, &position,
5737 recv_core_points + recv_core_count, single_remote_point_dt, comm);
5738 recv_buffer = (void*)((unsigned char*)recv_buffer + core_point_pack_size);
5739 }
5740 }
5741 free(pack_buffer);
5742
5743 // sort the requested global ids
5745 request_global_ids, num_requested_ids, reorder_idx);
5746
5747 // sort the received core remote_points
5748 qsort(recv_core_points, recv_core_count, sizeof(*recv_core_points),
5750
5751 // match request global ids with remote_points
5752 for (size_t i = 0, j = 0; i < num_requested_ids; ++i) {
5753
5754 yac_int curr_global_id = request_global_ids[i];
5755 while ((j < recv_core_count) &&
5756 (recv_core_points[j].global_id < curr_global_id)) ++j;
5757
5759 (j < recv_core_count) &&
5760 (recv_core_points[j].global_id == curr_global_id),
5761 "ERROR(%s): no matching core point found for global id %zu",
5762 routine, (size_t)curr_global_id)
5763
5764 send_point_info[reorder_idx[i]] = recv_core_points[j];
5765 }
5766 free(reorder_idx);
5767 free(request_global_ids);
5768
5769 saccu = 0, raccu = 0;
5770 for (int i = 0; i < comm_size; ++i) {
5771
5772 sdispls[i] = saccu;
5773 rdispls[i] = raccu;
5774 int recvcount = sendcounts[2*i+0];
5775 int sendcount = recvcounts[2*i+0];
5776 saccu += (sendcounts[i] = sendcount);
5777 raccu += (recvcounts[i] = recvcount);
5778 }
5779
5780 // redistribute remote_point_infos
5782 send_point_info, sendcounts, sdispls,
5783 recv_point_info, recvcounts, rdispls,
5784 sizeof(*send_point_info), single_remote_point_dt, comm,
5785 routine, __LINE__);
5786
5787 free(size_t_buffer);
5788 yac_mpi_call(MPI_Type_free(&single_remote_point_dt), comm);
5789
5791 dist_grid, recv_point_info, count, location, local_ids);
5792
5793 yac_quicksort_index_size_t_size_t(global_id_reorder_idx, count, local_ids);
5794
5795 free(global_id_reorder_idx);
5796 free(point_info_buffer);
5797}
5798
5800 struct yac_dist_grid_pair * grid_pair, char const * grid_name,
5801 size_t * vertices, size_t count, size_t ** cells,
5802 size_t * num_cells_per_vertex, struct yac_interp_field field) {
5803
5804 struct yac_dist_grid * dist_grid =
5805 yac_dist_grid_pair_get_dist_grid(grid_pair, grid_name);
5806
5807 // generate small bounding circle for all vertices
5808 struct bounding_circle * vertex_bnd_circles =
5809 xmalloc(count * sizeof(*vertex_bnd_circles));
5810
5811 struct sin_cos_angle sin_cos_high_tol =
5812 {yac_angle_tol*100.0, cos(yac_angle_tol*100.0)};
5813
5814 for (size_t i = 0; i < count; ++i) {
5815 memcpy(vertex_bnd_circles[i].base_vector,
5816 dist_grid->vertex_coordinates[vertices[i]], 3 * sizeof(double));
5817 vertex_bnd_circles[i].inc_angle = sin_cos_high_tol;
5818 vertex_bnd_circles[i].sq_crd = DBL_MAX;
5819 }
5820
5821 // do bounding circle search
5823 grid_pair, grid_name, vertex_bnd_circles, count,
5824 cells, num_cells_per_vertex, field);
5825 free(vertex_bnd_circles);
5826
5827 // for all vertices
5828 size_t total_num_cells = 0;
5829 for (size_t i = 0, k = 0; i < count; ++i) {
5830
5831 size_t curr_vertex = vertices[i];
5832 size_t curr_num_cells_per_vertex = num_cells_per_vertex[i];
5833
5834 size_t new_num_cells_per_vertex = 0;
5835
5836 // remove all cells that do not contain the current vertex
5837 for (size_t j = 0; j < curr_num_cells_per_vertex; ++j, ++k) {
5838
5839 size_t curr_cell = (*cells)[k];
5840 size_t * curr_cell_vertices =
5841 dist_grid->cell_to_vertex +
5842 dist_grid->cell_to_vertex_offsets[curr_cell];
5843 size_t curr_cell_size = dist_grid->num_vertices_per_cell[curr_cell];
5844
5845 size_t vertex_idx = 0;
5846 for (; vertex_idx < curr_cell_size; ++vertex_idx)
5847 if (curr_cell_vertices[vertex_idx] == curr_vertex) break;
5848
5849 // if the current cell is not linked to the current vertex
5850 if (vertex_idx == curr_cell_size) continue;
5851
5852 if (total_num_cells != k)
5853 (*cells)[total_num_cells] = curr_cell;
5854 ++new_num_cells_per_vertex;
5855 ++total_num_cells;
5856 }
5857
5858 num_cells_per_vertex[i] = new_num_cells_per_vertex;
5859 }
5860
5861 *cells = xrealloc(*cells, total_num_cells * sizeof(**cells));
5862}
5863
5886 struct yac_dist_grid_pair * grid_pair, char const * grid_name,
5887 size_t * vertices, size_t count, size_t ** cells,
5888 int * num_cells_per_vertex, struct yac_interp_field field) {
5889
5890 struct yac_dist_grid * dist_grid =
5891 yac_dist_grid_pair_get_dist_grid(grid_pair, grid_name);
5892
5893 // get all cells connected to the provided vertices
5894 size_t * result_cells;
5895 size_t * num_result_per_vertex =
5896 xmalloc(count * sizeof(*num_result_per_vertex));
5898 grid_pair, grid_name, vertices, count,
5899 &result_cells, num_result_per_vertex, field);
5900
5901 size_t max_num_cell_per_vertex = 0;
5902 for (size_t i = 0; i < count; ++i)
5903 if (num_result_per_vertex[i] > max_num_cell_per_vertex)
5904 max_num_cell_per_vertex = num_result_per_vertex[i];
5905 size_t (*neigh_vertices)[2] =
5906 xmalloc(max_num_cell_per_vertex * sizeof(*neigh_vertices));
5907 size_t * temp_vertex_cell =
5908 xmalloc(max_num_cell_per_vertex * sizeof(*temp_vertex_cell));
5909 yac_int * global_cell_ids =
5910 xmalloc(max_num_cell_per_vertex * sizeof(*global_cell_ids));
5911
5912 // for all vertices
5913 for (size_t i = 0, offset = 0, new_offset = 0; i < count; ++i) {
5914
5915 size_t curr_vertex = vertices[i];
5916 size_t * curr_cells = result_cells + offset;
5917 size_t curr_num_cells_per_vertex = num_result_per_vertex[i];
5918
5919 // remove all cells that do not contain the current vertex
5920 for (size_t j = 0; j < curr_num_cells_per_vertex; ++j) {
5921
5922 size_t curr_cell = curr_cells[j];
5923 size_t * curr_cell_vertices =
5924 dist_grid->cell_to_vertex + dist_grid->cell_to_vertex_offsets[curr_cell];
5925 size_t curr_cell_size = dist_grid->num_vertices_per_cell[curr_cell];
5926
5927 size_t vertex_idx = 0;
5928 for (; vertex_idx < curr_cell_size; ++vertex_idx)
5929 if (curr_cell_vertices[vertex_idx] == curr_vertex) break;
5930
5931 // get the vertex adjacent to the current vertex
5932 neigh_vertices[j][0] =
5933 curr_cell_vertices[((vertex_idx + curr_cell_size) - 1)%curr_cell_size];
5934 neigh_vertices[j][1] =
5935 curr_cell_vertices[(vertex_idx + 1)%curr_cell_size];
5936
5937 if (new_offset != offset) result_cells[new_offset + j] = curr_cell;
5938 }
5939
5940 offset += curr_num_cells_per_vertex;
5941 curr_cells = result_cells + new_offset;
5942
5943 if (curr_num_cells_per_vertex > 0) {
5944
5945 // determine order of cell around the current vertex
5946 temp_vertex_cell[0] = curr_cells[0];
5947 size_t start_neigh_vertex = neigh_vertices[0][0];
5948 size_t prev_vertex = neigh_vertices[0][1];
5949 for (size_t j = 1, prev_cell_idx = 0; j < curr_num_cells_per_vertex; ++j) {
5950
5951 size_t k;
5952 for (k = 0; k < curr_num_cells_per_vertex; ++k) {
5953
5954 if (k == prev_cell_idx) continue;
5955
5956 int flag = neigh_vertices[k][0] == prev_vertex;
5957 if (flag || (neigh_vertices[k][1] == prev_vertex)) {
5958 temp_vertex_cell[j] = curr_cells[k];
5959 prev_cell_idx = k;
5960 prev_vertex = neigh_vertices[k][flag];
5961 break;
5962 }
5963 }
5964
5965 // if we could not find the next neighbour
5966 // (vertex is at an edge of the grid)
5967 if (k == curr_num_cells_per_vertex) {
5968 curr_num_cells_per_vertex = 0;
5969 break;
5970 }
5971 }
5972 if ((prev_vertex != start_neigh_vertex) ||
5973 (curr_num_cells_per_vertex < 3))
5974 curr_num_cells_per_vertex = 0;
5975 }
5976
5977 new_offset += curr_num_cells_per_vertex;
5978 num_cells_per_vertex[i] = (int)curr_num_cells_per_vertex;
5979
5980 if (curr_num_cells_per_vertex == 0) continue;
5981
5982 // get global ids of all cells
5983 yac_int min_global_cell_id = XT_INT_MAX;
5984 size_t min_global_cell_id_idx = SIZE_MAX;
5985 for (size_t j = 0; j < curr_num_cells_per_vertex; ++j) {
5986 yac_int curr_global_cell_id =
5987 ((global_cell_ids[j] =
5988 dist_grid->ids[YAC_LOC_CELL][temp_vertex_cell[j]]));
5989 if (curr_global_cell_id < min_global_cell_id) {
5990 min_global_cell_id = curr_global_cell_id;
5991 min_global_cell_id_idx = j;
5992 }
5993 }
5994
5995 // determine order in which to store the cells
5996 int order =
5997 (global_cell_ids[
5998 ((min_global_cell_id_idx + curr_num_cells_per_vertex) - 1)%
5999 curr_num_cells_per_vertex] >
6000 global_cell_ids[
6001 (min_global_cell_id_idx + 1)%curr_num_cells_per_vertex])?-1:1;
6002
6003 // store cells in a partition-independent order
6004 for (size_t j = 0; j < curr_num_cells_per_vertex; ++j)
6005 curr_cells[j] =
6006 temp_vertex_cell[
6007 ((int)(min_global_cell_id_idx + curr_num_cells_per_vertex) +
6008 (int)j * order)%(int)curr_num_cells_per_vertex];
6009 }
6010
6011 *cells = result_cells;
6012 free(num_result_per_vertex);
6013 free(global_cell_ids);
6014 free(temp_vertex_cell);
6015 free(neigh_vertices);
6016}
6017
6019 struct yac_dist_grid_pair * grid_pair, char const * grid_name,
6020 size_t * vertices, size_t count, size_t ** neigh_vertices_,
6021 int * num_neighs_per_vertex, struct yac_interp_field field) {
6022
6023 struct yac_dist_grid * dist_grid =
6024 yac_dist_grid_pair_get_dist_grid(grid_pair, grid_name);
6025
6026 size_t * result_cells;
6027 size_t * num_result_per_vertex =
6028 xmalloc(count * sizeof(*num_result_per_vertex));
6030 grid_pair, grid_name, vertices, count, &result_cells,
6031 num_result_per_vertex, field);
6032
6033 size_t total_num_neigh = 0;
6034 size_t max_num_neigh = 0;
6035 for (size_t i = 0; i < count; ++i) {
6036 total_num_neigh += num_result_per_vertex[i];
6037 if (num_result_per_vertex[i] > max_num_neigh)
6038 max_num_neigh = num_result_per_vertex[i];
6039 }
6040
6041 int const * vertex_mask = NULL;
6042 if (field.location == YAC_LOC_CORNER)
6043 vertex_mask = yac_dist_grid_get_field_mask(dist_grid, field);
6044
6045 size_t * neigh_vertices =
6046 xmalloc(total_num_neigh * sizeof(*neigh_vertices));
6047 size_t * temp_neigh_vertices =
6048 xmalloc(2 * max_num_neigh * sizeof(*temp_neigh_vertices));
6049 total_num_neigh = 0;
6050
6051 // for all vertices
6052 for (size_t i = 0, offset = 0; i < count; ++i) {
6053
6054 size_t curr_vertex = vertices[i];
6055 size_t * curr_cells = result_cells + offset;
6056 size_t curr_num_cells_per_vertex = num_result_per_vertex[i];
6057
6058 size_t curr_num_neigh_vertices = 0;
6059
6060 // remove all cells that do not contain the current vertex
6061 for (size_t j = 0; j < curr_num_cells_per_vertex; ++j) {
6062
6063 size_t curr_cell = curr_cells[j];
6064 size_t * curr_cell_vertices =
6065 dist_grid->cell_to_vertex +
6066 dist_grid->cell_to_vertex_offsets[curr_cell];
6067 size_t curr_cell_size = dist_grid->num_vertices_per_cell[curr_cell];
6068
6069 size_t vertex_idx = 0;
6070 for (; vertex_idx < curr_cell_size; ++vertex_idx)
6071 if (curr_cell_vertices[vertex_idx] == curr_vertex) break;
6072
6073 // get the vertex adjacent to the current vertex
6074 size_t neigh_vertex_idx =
6075 curr_cell_vertices[((vertex_idx + curr_cell_size) - 1)%curr_cell_size];
6076 if ((vertex_mask != NULL) && (vertex_mask[neigh_vertex_idx]))
6077 temp_neigh_vertices[curr_num_neigh_vertices++] = neigh_vertex_idx;
6078 neigh_vertex_idx =
6079 curr_cell_vertices[(vertex_idx + 1)%curr_cell_size];
6080 if ((vertex_mask != NULL) && (vertex_mask[neigh_vertex_idx]))
6081 temp_neigh_vertices[curr_num_neigh_vertices++] = neigh_vertex_idx;
6082 }
6083
6084 qsort(temp_neigh_vertices, curr_num_neigh_vertices,
6085 sizeof(*temp_neigh_vertices), compare_size_t);
6087 temp_neigh_vertices, &curr_num_neigh_vertices);
6088 memcpy(neigh_vertices + total_num_neigh, temp_neigh_vertices,
6089 curr_num_neigh_vertices * sizeof(*neigh_vertices));
6090
6091 total_num_neigh += curr_num_neigh_vertices;
6092 num_neighs_per_vertex[i] = curr_num_neigh_vertices;
6093
6094 offset += curr_num_cells_per_vertex;
6095 }
6096 free(temp_neigh_vertices);
6097
6098 free(result_cells);
6099 free(num_result_per_vertex);
6100
6101 *neigh_vertices_ = neigh_vertices;
6102}
6103
6105 struct yac_dist_grid_pair * grid_pair, char const * grid_name,
6106 size_t * vertices, size_t count, size_t ** vertex_to_cell,
6107 size_t * num_cells_per_vertex) {
6108
6109 struct yac_dist_grid * dist_grid =
6110 yac_dist_grid_pair_get_dist_grid(grid_pair, grid_name);
6111
6112 // get for each vertex all cells surrounding it
6113 struct yac_interp_field dummy_interp_field =
6115 .coordinates_idx = SIZE_MAX,
6116 .masks_idx = SIZE_MAX};
6118 grid_pair, grid_name, vertices, count, vertex_to_cell,
6119 num_cells_per_vertex, dummy_interp_field);
6120
6121 size_t max_num_cells_per_vertex = 0;
6122 for (size_t i = 0; i < count; ++i)
6123 if (num_cells_per_vertex[i] > max_num_cells_per_vertex)
6124 max_num_cells_per_vertex = num_cells_per_vertex[i];
6125
6126 yac_int * global_id_buffer =
6127 xmalloc(max_num_cells_per_vertex * sizeof(*global_id_buffer));
6128
6129 yac_int const * global_cell_ids = dist_grid->ids[YAC_LOC_CELL];
6130
6131 YAC_ASSERT(
6132 (count == 0) || (global_cell_ids != NULL),
6133 "ERROR(yac_dist_grid_pair_get_corner_cells): no global cell ids")
6134
6135 // for all vertices
6136 for (size_t i = 0, offset = 0; i < count; ++i) {
6137
6138 size_t curr_num_cells_per_vertex = num_cells_per_vertex[i];
6139 size_t * curr_vertex_to_cell = *vertex_to_cell + offset;
6140 offset += curr_num_cells_per_vertex;
6141
6142 // get global ids of all cells surrounding the current vertex
6143 for (size_t j = 0; j < curr_num_cells_per_vertex; ++j)
6144 global_id_buffer[j] = global_cell_ids[curr_vertex_to_cell[j]];
6145
6146 // sort cells by their global ids
6148 global_id_buffer, curr_num_cells_per_vertex, curr_vertex_to_cell);
6149 }
6150
6151 free(global_id_buffer);
6152}
6153
6155 struct yac_dist_grid_pair * grid_pair, char const * grid_name,
6156 size_t * cells, size_t count,
6157 size_t ** vertex_to_cell, size_t ** vertex_to_cell_offsets_,
6158 int ** num_cells_per_vertex_, struct yac_interp_field field) {
6159
6160 struct yac_dist_grid * dist_grid =
6161 yac_dist_grid_pair_get_dist_grid(grid_pair, grid_name);
6162
6163 // determine required vertices
6164 size_t * temp_cells = xmalloc(count * sizeof(*temp_cells));
6165 int * required_vertices =
6166 xcalloc(dist_grid->total_count[YAC_LOC_CORNER], sizeof(*required_vertices));
6167 memcpy(temp_cells, cells, count * sizeof(*cells));
6168 qsort(temp_cells, count, sizeof(*temp_cells), compare_size_t);
6169 for (size_t i = 0, prev_cell = SIZE_MAX; i < count; ++i) {
6170 size_t curr_cell = temp_cells[i];
6171 if (curr_cell == SIZE_MAX) break;
6172 if (curr_cell != prev_cell) {
6173 prev_cell = curr_cell;
6174 size_t curr_num_vertices = dist_grid->num_vertices_per_cell[curr_cell];
6175 size_t const * curr_vertices =
6176 dist_grid->cell_to_vertex + dist_grid->cell_to_vertex_offsets[curr_cell];
6177 for (size_t j = 0; j < curr_num_vertices; ++j)
6178 required_vertices[curr_vertices[j]] = 1;
6179 }
6180 }
6181 free(temp_cells);
6182
6183 // generate list of all required vertices
6184 size_t num_unique_vertices = 0;
6185 for (size_t i = 0; i < dist_grid->total_count[YAC_LOC_CORNER]; ++i)
6186 if (required_vertices[i]) ++num_unique_vertices;
6187 size_t * unique_vertices =
6188 xmalloc(num_unique_vertices * sizeof(*unique_vertices));
6189 for (size_t i = 0, j = 0; i < dist_grid->total_count[YAC_LOC_CORNER]; ++i)
6190 if (required_vertices[i]) unique_vertices[j++] = i;
6191 free(required_vertices);
6192
6193 // get aux cells for all unique vertices
6194 int * num_cells_per_vertex =
6195 xcalloc(num_unique_vertices, sizeof(*num_cells_per_vertex));
6197 grid_pair, grid_name, unique_vertices, num_unique_vertices,
6198 vertex_to_cell, num_cells_per_vertex, field);
6199
6200 int * grid_num_cells_per_vertex =
6201 xcalloc(
6202 dist_grid->total_count[YAC_LOC_CORNER],
6203 sizeof(*grid_num_cells_per_vertex));
6204
6205 for (size_t i = 0; i < num_unique_vertices; ++i)
6206 grid_num_cells_per_vertex[unique_vertices[i]] =
6207 num_cells_per_vertex[i];
6208 free(num_cells_per_vertex);
6209 free(unique_vertices);
6210
6211 size_t * vertex_to_cell_offsets =
6212 xmalloc(
6213 dist_grid->total_count[YAC_LOC_CORNER] *
6214 sizeof(*vertex_to_cell_offsets));
6215 for (size_t i = 0, offset = 0; i < dist_grid->total_count[YAC_LOC_CORNER];
6216 ++i) {
6217 vertex_to_cell_offsets[i] = offset;
6218 offset += grid_num_cells_per_vertex[i];
6219 }
6220
6221 *vertex_to_cell_offsets_ = vertex_to_cell_offsets;
6222 *num_cells_per_vertex_ = grid_num_cells_per_vertex;
6223}
6224
6226 size_t ** points, size_t * reorder_idx, int * ranks, size_t count,
6227 enum yac_location location, size_t local_count, size_t recv_count,
6228 struct single_remote_point * id_send_buffer,
6229 struct single_remote_point * id_recv_buffer,
6230 size_t * sendcounts, size_t * sdispls, size_t * recvcounts, size_t * rdispls,
6231 MPI_Datatype single_remote_point_dt, MPI_Comm comm,
6232 struct yac_dist_grid * dist_grid) {
6233
6234 char const * routine = "relocate_points";
6235
6236 yac_int const * global_ids =
6237 yac_dist_grid_get_global_ids(dist_grid, location);
6238
6239 int comm_rank;
6240 yac_mpi_call(MPI_Comm_rank(comm, &comm_rank), comm);
6241
6242 size_t * old_points = *points;
6243 size_t * new_points =
6244 xmalloc((local_count + recv_count) * sizeof(*new_points));
6245
6246 for (size_t i = 0, j = 0, k = 0; i < count; ++i) {
6247 size_t idx = reorder_idx[i];
6248 size_t curr_point = old_points[idx];
6249 int curr_rank = ranks[i];
6250 if (curr_rank == comm_rank) {
6251 new_points[j++] = curr_point;
6252 } else {
6253 id_send_buffer[k].global_id = global_ids[curr_point];
6254 id_send_buffer[k].data.rank = comm_rank;
6255 id_send_buffer[k].data.orig_pos = curr_point;
6256 ++k;
6257 }
6258 }
6259
6260 // redistribute points
6262 id_send_buffer, sendcounts, sdispls,
6263 id_recv_buffer, recvcounts, rdispls,
6264 sizeof(*id_send_buffer), single_remote_point_dt, comm, routine, __LINE__);
6265
6266 // convert all remote ids to local ones, extend local dist_grid data,
6267 // if necessary
6269 dist_grid, id_recv_buffer, recv_count, location,
6270 new_points + local_count);
6271
6272 *points = new_points;
6273 free(old_points);
6274}
6275
6277 double ** weights, size_t * reorder_idx, int * ranks, size_t count,
6278 size_t send_count, size_t local_count, size_t recv_count,
6279 size_t * sendcounts, size_t * sdispls, size_t * recvcounts, size_t * rdispls,
6280 MPI_Comm comm) {
6281
6282 char const * routine = "relocate_weights";
6283
6284 int comm_rank;
6285 yac_mpi_call(MPI_Comm_rank(comm, &comm_rank), comm);
6286
6287 double * old_weights = *weights;
6288 double * send_buffer = xmalloc(send_count * sizeof(*send_buffer));
6289 double * recv_buffer =
6290 xmalloc((local_count + recv_count) * sizeof(*recv_buffer));
6291
6292 for (size_t i = 0, j = 0, k = 0; i < count; ++i) {
6293 size_t idx = reorder_idx[i];
6294 double curr_weight = old_weights[idx];
6295 int curr_rank = ranks[i];
6296 if (curr_rank == comm_rank) recv_buffer[j++] = curr_weight;
6297 else send_buffer[k++] = curr_weight;
6298 }
6299
6300 // redistribute points
6302 send_buffer, sendcounts, sdispls,
6303 recv_buffer + local_count, recvcounts, rdispls,
6304 sizeof(*send_buffer), MPI_DOUBLE, comm, routine, __LINE__);
6305
6306 free(old_weights);
6307 *weights = recv_buffer;
6308 free(send_buffer);
6309}
6310
6312 struct yac_dist_grid * dist_grid,
6313 struct proc_sphere_part_node * proc_sphere_part,
6314 size_t * vertices, size_t count, int * ranks) {
6315
6316 size_t * reorder_idx = xmalloc(count * sizeof(*reorder_idx));
6317 for (size_t i = 0; i < count; ++i) reorder_idx[i] = i;
6318 yac_quicksort_index_size_t_size_t(vertices, count, reorder_idx);
6319
6320 size_t valid_count;
6321 for (valid_count = 0;
6322 (valid_count < count) && (vertices[valid_count] != SIZE_MAX);
6323 ++valid_count);
6324
6325 for (size_t i = valid_count; i < count; ++i) ranks[reorder_idx[i]] = 0;
6326
6327 size_t unique_count = 0;
6328 size_t prev_vertex = SIZE_MAX;
6329 for (size_t i = 0; i < valid_count; ++i) {
6330 size_t curr_vertex = vertices[i];
6331 if (curr_vertex != prev_vertex) {
6332 prev_vertex = curr_vertex;
6333 ++unique_count;
6334 }
6335 }
6336
6337 yac_coordinate_pointer grid_coords = dist_grid->vertex_coordinates;
6338 yac_coordinate_pointer search_coords =
6339 xmalloc(unique_count * sizeof(*search_coords));
6340
6341 prev_vertex = SIZE_MAX;
6342 for (size_t i = 0, j = 0; i < valid_count; ++i) {
6343 size_t curr_vertex = vertices[i];
6344 if (curr_vertex != prev_vertex) {
6345 prev_vertex = curr_vertex;
6346 memcpy(
6347 search_coords[j++], grid_coords[curr_vertex], 3 * sizeof(double));
6348 }
6349 }
6350
6351 int * temp_ranks = xmalloc(unique_count * sizeof(*temp_ranks));
6353 proc_sphere_part, search_coords, unique_count, temp_ranks);
6354
6355 prev_vertex = SIZE_MAX;
6356 for (size_t i = 0, j = 0; i < valid_count; ++i) {
6357 size_t curr_vertex = vertices[i];
6358 if (curr_vertex != prev_vertex) {
6359 prev_vertex = curr_vertex;
6360 ++j;
6361 }
6362 ranks[reorder_idx[i]] = temp_ranks[j-1];
6363 }
6364
6365 yac_quicksort_index_size_t_size_t(reorder_idx, count, vertices);
6366 free(temp_ranks);
6367 free(search_coords);
6368 free(reorder_idx);
6369}
6370
6372 struct yac_dist_grid * dist_grid,
6373 struct proc_sphere_part_node * proc_sphere_part,
6374 size_t * indices, size_t count, int * ranks,
6375 size_t (*get_ce_reference_vertex)(struct yac_dist_grid *, size_t)) {
6376
6377 size_t * reorder_idx = xmalloc(count * sizeof(*reorder_idx));
6378 for (size_t i = 0; i < count; ++i) reorder_idx[i] = i;
6379 yac_quicksort_index_size_t_size_t(indices, count, reorder_idx);
6380
6381 size_t unique_count = 0;
6382 size_t prev_index = SIZE_MAX;
6383 for (size_t i = 0; i < count; ++i) {
6384 size_t curr_index = indices[i];
6385 if (curr_index != prev_index) {
6386 prev_index = curr_index;
6387 ++unique_count;
6388 }
6389 }
6390
6391 size_t * ref_vertices = xmalloc(unique_count * sizeof(*ref_vertices));
6392 prev_index = SIZE_MAX;
6393 for (size_t i = 0, j = 0; i < count; ++i) {
6394 size_t curr_index = indices[i];
6395 if (curr_index != prev_index) {
6396 prev_index = curr_index;
6397 ref_vertices[j++] =
6398 get_ce_reference_vertex(dist_grid, curr_index);
6399 }
6400 }
6401
6402 int * temp_ranks = xmalloc(unique_count * sizeof(*temp_ranks));
6404 dist_grid, proc_sphere_part, ref_vertices, unique_count, temp_ranks);
6405 free(ref_vertices);
6406
6407 prev_index = SIZE_MAX;
6408 for (size_t i = 0, j = 0; i < count; ++i) {
6409 size_t curr_index = indices[i];
6410 if (curr_index != prev_index) {
6411 prev_index = curr_index;
6412 ++j;
6413 }
6414 ranks[reorder_idx[i]] = temp_ranks[j-1];
6415 }
6416
6417 yac_quicksort_index_size_t_size_t(reorder_idx, count, indices);
6418 free(temp_ranks);
6419 free(reorder_idx);
6420}
6421
6423 struct yac_dist_grid * dist_grid,
6424 struct proc_sphere_part_node * proc_sphere_part,
6425 size_t * cells, size_t count, int * ranks) {
6426
6428 dist_grid, proc_sphere_part, cells, count, ranks,
6430}
6431
6433 struct yac_dist_grid * dist_grid,
6434 struct proc_sphere_part_node * proc_sphere_part,
6435 size_t * edges, size_t count, int * ranks) {
6436
6438 dist_grid, proc_sphere_part, edges, count, ranks,
6440}
6441
6443 struct yac_dist_grid_pair * grid_pair, char const * grid_name,
6444 size_t * points, size_t count, enum yac_location location, int * ranks) {
6445
6446 struct yac_dist_grid * dist_grid =
6447 yac_dist_grid_pair_get_dist_grid(grid_pair, grid_name);
6448
6449 CHECK_LOCATION("yac_dist_grid_pair_determine_dist_owner")
6450
6451 void (*determine_dist_owner[3])(
6452 struct yac_dist_grid * dist_grid,
6453 struct proc_sphere_part_node * proc_sphere_part,
6454 size_t * cells, size_t count, int * ranks) =
6458 determine_dist_owner[location](
6459 dist_grid, grid_pair->proc_sphere_part, points, count, ranks);
6460}
6461
6463 struct yac_dist_grid_pair * grid_pair, char const * grid_name,
6464 size_t * points, size_t count, enum yac_location location, int * ranks) {
6465
6466 struct yac_dist_grid * dist_grid =
6467 yac_dist_grid_pair_get_dist_grid(grid_pair, grid_name);
6468
6469 struct remote_point_infos * orig_owners;
6470
6471 CHECK_LOCATION("yac_dist_grid_pair_determine_orig_owner")
6472 orig_owners = dist_grid->owners[location];
6473
6474 for (size_t i = 0; i < count; ++i) {
6475
6476 struct remote_point_infos * curr_orig_owner = orig_owners + points[i];
6477
6478 int min_rank;
6479 int curr_count = curr_orig_owner->count;
6480 if (curr_count == 1) {
6481 min_rank = curr_orig_owner->data.single.rank;
6482 } else {
6483 min_rank = curr_orig_owner->data.multi[0].rank;
6484 for (int j = 1; j < curr_count; ++j) {
6485 int curr_rank = curr_orig_owner->data.multi[j].rank;
6486 if (min_rank > curr_rank) min_rank = curr_rank;
6487 }
6488 }
6489 ranks[i] = min_rank;
6490 }
6491}
6492
6494 struct yac_dist_grid_pair * grid_pair, int a_is_ref, int to_dist_owner,
6495 char const * grid_name_a, size_t ** points_a, enum yac_location location_a,
6496 char const * grid_name_b, size_t ** points_b, enum yac_location location_b,
6497 double ** weights, size_t * count) {
6498
6499 size_t count_ = *count;
6500
6501 MPI_Comm comm = grid_pair->comm;
6502 int comm_rank, comm_size;
6503 yac_mpi_call(MPI_Comm_rank(comm, &comm_rank), comm);
6504 yac_mpi_call(MPI_Comm_size(comm, &comm_size), comm);
6505
6506 // check whether we have to exchange weights
6507 int weight_flag_local =
6508 (count_ > 0) && (weights != NULL) && (*weights != NULL);
6509 int weight_flag;
6510 yac_mpi_call(MPI_Allreduce(&weight_flag_local, &weight_flag, 1,
6511 MPI_INT, MPI_MAX, comm), comm);
6512
6513 // if there are points defined locally for the current grid
6514 YAC_ASSERT(
6515 (count_ <= 0) || weight_flag_local || !weight_flag,
6516 "ERROR(yac_dist_grid_pair_relocate_point_pairs): weights")
6517
6518 // get the owner ranks for the reference points
6519 int * ranks = xmalloc(count_ * sizeof(ranks));
6520 size_t * reorder_idx = xmalloc(count_ * sizeof(reorder_idx));
6521 {
6522 char const * grid_name = (a_is_ref)?grid_name_a:grid_name_b;
6523 size_t * points = (a_is_ref)?*points_a:*points_b;
6524 enum yac_location location = (a_is_ref)?location_a:location_b;
6525 if (to_dist_owner)
6527 grid_pair, grid_name, points, count_, location, ranks);
6528 else
6530 grid_pair, grid_name, points, count_, location, ranks);
6531 }
6532 for (size_t i = 0; i < count_; ++i) reorder_idx[i] = i;
6533 yac_quicksort_index_int_size_t(ranks, count_, reorder_idx);
6534
6535 size_t * sendcounts, * recvcounts, * sdispls, * rdispls;
6537 1, &sendcounts, &recvcounts, &sdispls, &rdispls, comm);
6538 for (size_t i = 0; i < count_; ++i) sendcounts[ranks[i]]++;
6539
6540 size_t local_count = sendcounts[comm_rank];
6541 sendcounts[comm_rank] = 0;
6542
6544 1, sendcounts, recvcounts, sdispls, rdispls, comm);
6545
6546 size_t send_count = sdispls[comm_size] + sendcounts[comm_size-1];
6547 size_t recv_count = rdispls[comm_size-1] + recvcounts[comm_size-1];
6548
6549 struct single_remote_point * single_remote_point_buffer =
6550 xmalloc((send_count + recv_count) *
6551 sizeof(*single_remote_point_buffer));
6552 struct single_remote_point * id_send_buffer = single_remote_point_buffer;
6553 struct single_remote_point * id_recv_buffer = single_remote_point_buffer +
6554 send_count;
6555
6556 MPI_Datatype single_remote_point_dt =
6558
6560 points_a, reorder_idx, ranks, count_, location_a,
6561 local_count, recv_count, id_send_buffer, id_recv_buffer,
6562 sendcounts, sdispls + 1, recvcounts, rdispls,
6563 single_remote_point_dt, comm,
6564 yac_dist_grid_pair_get_dist_grid(grid_pair, grid_name_a));
6566 points_b, reorder_idx, ranks, count_, location_b,
6567 local_count, recv_count, id_send_buffer, id_recv_buffer,
6568 sendcounts, sdispls + 1, recvcounts, rdispls,
6569 single_remote_point_dt, comm,
6570 yac_dist_grid_pair_get_dist_grid(grid_pair, grid_name_b));
6571 yac_mpi_call(MPI_Type_free(&single_remote_point_dt), comm);
6572
6573 if (weight_flag)
6575 weights, reorder_idx, ranks, count_,
6576 send_count, local_count, recv_count,
6577 sendcounts, sdispls + 1, recvcounts, rdispls, comm);
6578
6579 yac_free_comm_buffers(sendcounts, recvcounts, sdispls, rdispls);
6580 free(single_remote_point_buffer);
6581 free(reorder_idx);
6582 free(ranks);
6583
6584 *count = local_count + recv_count;
6585}
struct yac_field_data * yac_basic_grid_get_field_data(struct yac_basic_grid *grid, enum yac_location location)
Definition basic_grid.c:309
struct yac_basic_grid_data * yac_basic_grid_get_data(struct yac_basic_grid *grid)
Definition basic_grid.c:137
char const * yac_basic_grid_get_name(struct yac_basic_grid *grid)
Definition basic_grid.c:128
void yac_get_cell_bounding_circle(struct yac_grid_cell cell, struct bounding_circle *bnd_circle)
Definition bnd_circle.c:422
int yac_extents_overlap(struct bounding_circle *extent_a, struct bounding_circle *extent_b)
Definition bnd_circle.c:533
int yac_point_in_cell2(double point_coords[3], struct yac_grid_cell cell, struct bounding_circle bnd_circle)
#define UNUSED(x)
Definition core.h:73
static int compare_n_ids_reorder_ids(const void *a, const void *b)
Definition dist_grid.c:311
#define CHECK_LOCATION(caller)
Definition dist_grid.c:27
void yac_dist_grid_pair_do_point_search_gc(struct yac_dist_grid_pair *grid_pair, char const *grid_name, yac_coordinate_pointer search_coords, size_t count, size_t *cells)
Definition dist_grid.c:4259
void yac_dist_grid_pair_delete(struct yac_dist_grid_pair *grid_pair)
Definition dist_grid.c:2618
yac_const_coordinate_pointer yac_dist_grid_get_field_coords(struct yac_dist_grid *dist_grid, struct yac_interp_field field)
Definition dist_grid.c:2555
void yac_dist_grid_determine_dist_ce_owner(struct yac_dist_grid *dist_grid, struct proc_sphere_part_node *proc_sphere_part, size_t *indices, size_t count, int *ranks, size_t(*get_ce_reference_vertex)(struct yac_dist_grid *, size_t))
Definition dist_grid.c:6371
static int get_pack_size_base_cell(struct yac_field_data *cell_field_data, MPI_Datatype bnd_circle_dt, MPI_Comm comm)
Definition dist_grid.c:2814
static int compare_single_remote_point_reorder_global_id(const void *a, const void *b)
Definition dist_grid.c:1701
static void unpack_global_id(void *buffer, int buffer_size, int *position, yac_int *global_id, MPI_Comm comm)
Definition dist_grid.c:5529
size_t yac_dist_grid_get_unmasked_local_count(struct yac_dist_grid *dist_grid, struct yac_interp_field field)
Definition dist_grid.c:2571
static struct point_sphere_part_search * yac_dist_grid_get_field_sphere_part(struct yac_dist_grid *dist_grid, struct yac_interp_field field)
Definition dist_grid.c:4270
static void pack_grid_data_vertex(struct yac_dist_grid *dist_grid, size_t idx, void *buffer, int buffer_size, int *position, MPI_Datatype bnd_circle_dt, MPI_Datatype point_info_dt, MPI_Comm comm)
Definition dist_grid.c:3001
static void ensure_temp_field_data_sizes(struct temp_field_data *temp_field_data, size_t size)
Definition dist_grid.c:3664
static void yac_dist_grid_get_cell_neighbours(struct yac_dist_grid *dist_grid, struct proc_sphere_part_node *proc_sphere_part, size_t *cells, size_t count, size_t *neighbours)
Definition dist_grid.c:5148
static int get_pack_size_base_edge(struct yac_field_data *edge_field_data, MPI_Comm comm)
Definition dist_grid.c:2849
static MPI_Datatype yac_get_id_reorder_coord_coord_mpi_datatype(MPI_Comm comm)
Definition dist_grid.c:436
static Xt_xmap generate_xmap_data(struct remote_point_infos *point_infos, size_t count, MPI_Comm comm)
Definition dist_grid.c:1613
void yac_dist_grid_pair_determine_dist_owner(struct yac_dist_grid_pair *grid_pair, char const *grid_name, size_t *points, size_t count, enum yac_location location, int *ranks)
Definition dist_grid.c:6442
void yac_dist_grid_pair_do_point_search(struct yac_dist_grid_pair *grid_pair, char const *grid_name, yac_coordinate_pointer search_coords, size_t count, size_t *cells)
Definition dist_grid.c:4251
size_t yac_dist_grid_get_local_count(struct yac_dist_grid *dist_grid, enum yac_location location)
Definition dist_grid.c:2459
static void dist_grid_pair_do_point_search_local(struct yac_dist_grid_pair *grid_pair, char const *grid_name, yac_coordinate_pointer search_coords, size_t count, size_t *cells, int(*coord_in_cell)(double coord[3], struct yac_dist_grid *dist_grid, size_t cell_idx, struct yac_grid_cell *buffer_cell))
Definition dist_grid.c:2705
static int * determine_edge_owner_mask(struct yac_dist_grid *dist_grid, int *vertex_owner_mask)
Definition dist_grid.c:228
void yac_dist_grid_pair_do_nnn_search(struct yac_dist_grid_pair *grid_pair, char const *grid_name, yac_coordinate_pointer search_coords, size_t count, size_t *local_ids, size_t n, struct yac_interp_field field, double max_search_distance)
Definition dist_grid.c:4428
static int compare_size_t(const void *a, const void *b)
Definition dist_grid.c:4421
static void redistribute_vertex_data(struct yac_basic_grid *grid, struct remote_point_infos *dist_vertex_infos, size_t num_vertices, MPI_Comm comm, MPI_Datatype dt_coord, int *vertex_ranks, yac_coordinate_pointer *vertex_coordinates_, int **vertex_owner_, struct yac_field_data **vertex_field_data_)
Definition dist_grid.c:1841
static void temp_field_data_free(struct temp_field_data temp_field_data)
Definition dist_grid.c:3711
void yac_dist_grid_pair_get_vertex_neighbours(struct yac_dist_grid_pair *grid_pair, char const *grid_name, size_t *vertices, size_t count, size_t **neigh_vertices_, int *num_neighs_per_vertex, struct yac_interp_field field)
Definition dist_grid.c:6018
static struct yac_field_data * field_data_init(struct yac_field_data *orig_field_data, size_t dist_size, Xt_redist redist_mask, Xt_redist redist_coords, MPI_Comm comm)
Definition dist_grid.c:1727
static int * determine_cell_owner_mask(struct yac_dist_grid *dist_grid, int is_root, int *vertex_owner_mask)
Definition dist_grid.c:196
static struct yac_dist_grid generate_dist_grid(struct proc_sphere_part_node *proc_sphere_part, struct yac_basic_grid *grid, MPI_Comm comm)
Definition dist_grid.c:2184
static int compare_id_reorder_coord_coord(const void *a, const void *b)
Definition dist_grid.c:466
static int compare_single_remote_point_reorder_reorder_idx(const void *a, const void *b)
Definition dist_grid.c:1710
void yac_dist_grid_determine_dist_cell_owner(struct yac_dist_grid *dist_grid, struct proc_sphere_part_node *proc_sphere_part, size_t *cells, size_t count, int *ranks)
Definition dist_grid.c:6422
static void unpack_field_data(void *buffer, int buffer_size, int *position, size_t idx, struct temp_field_data temp_field_data, MPI_Comm comm)
Definition dist_grid.c:3152
static yac_size_t_2_pointer generate_edge_to_cell(const_size_t_pointer cell_to_edge, const_int_pointer num_edges_per_cell, int *core_cell_mask, size_t num_cells, size_t num_edges)
Definition dist_grid.c:1070
static int get_pack_size_field_data(struct yac_field_data *field_data, MPI_Comm comm)
Definition dist_grid.c:2796
static void generate_sorted_ids(yac_int *global_ids, size_t count, yac_int **sorted_global_ids, size_t **reorder_idx)
Definition dist_grid.c:1603
static void do_nnn_search_local(struct yac_dist_grid *dist_grid, struct yac_interp_field field, size_t count, yac_coordinate_pointer search_coords, size_t n, double cos_max_search_distance, size_t *result_points)
Definition dist_grid.c:4347
static MPI_Datatype yac_get_coordinate_mpi_datatype(MPI_Comm comm)
Definition dist_grid.c:1719
static int compute_bucket(yac_int value, int comm_size)
Definition dist_grid.c:5506
static size_t yac_dist_grid_get_count(struct yac_dist_grid *dist_grid, enum yac_location location)
Definition dist_grid.c:2483
static void add_field_data(struct yac_field_data *field_data, struct temp_field_data temp_field_data, void *reorder_idx, size_t reorder_idx_size, size_t old_count, size_t new_count)
Definition dist_grid.c:3228
static int get_single_remote_point_pack_size(MPI_Datatype single_remote_point_dt, MPI_Comm comm)
Definition dist_grid.c:5538
static void get_pack_sizes_edge(struct yac_dist_grid *dist_grid, uint64_t *pos, size_t count, int *pack_sizes, MPI_Datatype point_info_dt, MPI_Comm comm)
Definition dist_grid.c:2925
static struct bounding_circle compute_dist_edge_bnd_circle(struct yac_dist_grid *dist_grid, size_t edge_id)
Definition dist_grid.c:5140
struct yac_dist_grid * yac_dist_grid_pair_get_dist_grid(struct yac_dist_grid_pair *grid_pair, char const *grid_name)
Definition dist_grid.c:2439
static int compare_single_remote_point_reorder_owner(const void *a, const void *b)
Definition dist_grid.c:3939
static size_t yac_dist_grid_get_total_count(struct yac_dist_grid *dist_grid, enum yac_location location)
Definition dist_grid.c:2473
static void insert_global_id(yac_int *ids, size_t n, yac_int id)
Definition dist_grid.c:284
static void get_pack_sizes_vertex(struct yac_dist_grid *dist_grid, uint64_t *pos, size_t count, int *pack_sizes, MPI_Datatype point_info_dt, MPI_Comm comm)
Definition dist_grid.c:2910
static void relocate_weights(double **weights, size_t *reorder_idx, int *ranks, size_t count, size_t send_count, size_t local_count, size_t recv_count, size_t *sendcounts, size_t *sdispls, size_t *recvcounts, size_t *rdispls, MPI_Comm comm)
Definition dist_grid.c:6276
static void setup_search_data(struct yac_dist_grid_pair *dist_grid_pair)
Definition dist_grid.c:2323
void generate_dist_remote_points(struct proc_sphere_part_node *proc_sphere_part, struct yac_basic_grid *grid, int *vertex_ranks, int max_num_vertices_per_cell, MPI_Comm comm, struct remote_point_infos **dist_point_infos, yac_int **dist_global_ids, size_t *dist_count)
Definition dist_grid.c:1345
static struct temp_field_data temp_field_data_init(struct yac_field_data *field_data, size_t count)
Definition dist_grid.c:3676
struct yac_dist_grid_pair * yac_dist_grid_pair_new(struct yac_basic_grid *grid_a, struct yac_basic_grid *grid_b, MPI_Comm comm)
Definition dist_grid.c:2370
int const * yac_dist_grid_get_field_mask(struct yac_dist_grid *dist_grid, struct yac_interp_field field)
Definition dist_grid.c:2543
static void relocate_points(size_t **points, size_t *reorder_idx, int *ranks, size_t count, enum yac_location location, size_t local_count, size_t recv_count, struct single_remote_point *id_send_buffer, struct single_remote_point *id_recv_buffer, size_t *sendcounts, size_t *sdispls, size_t *recvcounts, size_t *rdispls, MPI_Datatype single_remote_point_dt, MPI_Comm comm, struct yac_dist_grid *dist_grid)
Definition dist_grid.c:6225
static void get_pack_sizes_cell(struct yac_dist_grid *dist_grid, uint64_t *pos, size_t count, int *pack_sizes, MPI_Datatype bnd_circle_dt, MPI_Datatype point_info_dt, MPI_Comm comm)
Definition dist_grid.c:2867
static int compare_single_remote_point_global_id(const void *a, const void *b)
Definition dist_grid.c:1333
static void generate_vertex_to_edge(yac_size_t_2_pointer edge_to_vertex, size_t num_edges, size_t num_vertices, size_t *vertex_to_edge, int *num_edges_per_vertex)
Definition dist_grid.c:1223
static void yac_dist_grid_add_vertices(struct yac_dist_grid *dist_grid, struct global_vertex_reorder *vertices, size_t count, size_t *idx, struct temp_field_data temp_vertex_field_data)
Definition dist_grid.c:3272
static int get_global_id_pack_size(MPI_Comm comm)
Definition dist_grid.c:5510
void yac_dist_grid_determine_dist_vertex_owner(struct yac_dist_grid *dist_grid, struct proc_sphere_part_node *proc_sphere_part, size_t *vertices, size_t count, int *ranks)
Definition dist_grid.c:6311
static int * generate_vertex_ids(struct proc_sphere_part_node *proc_sphere_part, struct yac_basic_grid_data *grid, MPI_Comm comm)
Definition dist_grid.c:485
static void unpack_grid_data_edge(struct global_edge_reorder *edge, size_t idx, void *buffer, int buffer_size, int *position, struct temp_field_data temp_edge_field_data, MPI_Datatype point_info_dt, MPI_Comm comm)
Definition dist_grid.c:3190
static int get_pack_size_base_vertex(struct yac_field_data *vertex_field_data, MPI_Comm comm)
Definition dist_grid.c:2834
static void yac_dist_grid_get_n_unmasked_local_points(struct yac_dist_grid *dist_grid, struct yac_interp_field field, int comm_rank, size_t n, struct single_remote_point *points)
Definition dist_grid.c:4295
struct yac_dist_grid_pair * yac_dist_grid_pair_new_f2c(struct yac_basic_grid *grid_a, struct yac_basic_grid *grid_b, MPI_Fint comm)
Definition dist_grid.c:2426
static size_t get_cell_reference_vertex(struct yac_dist_grid *dist_grid, size_t cell_idx)
Definition dist_grid.c:172
static void yac_single_remote_point_unpack(void *buffer, int buffer_size, int *position, struct single_remote_point *point, MPI_Datatype single_remote_point_dt, MPI_Comm comm)
Definition dist_grid.c:5559
void yac_dist_grid_pair_get_cell_neighbours(struct yac_dist_grid_pair *grid_pair, char const *grid_name, size_t *cells, size_t count, size_t *neighbours)
Definition dist_grid.c:5478
void yac_dist_grid_get_local_unmasked_points(struct yac_dist_grid *dist_grid, struct yac_interp_field field, size_t **indices, size_t *num_indices)
Definition dist_grid.c:2510
static void yac_remote_point_infos_single_free(struct remote_point_infos *point_infos)
Definition dist_grid.c:3266
static struct bounding_circle * generate_cell_bounding_circles(size_t num_cells, int max_num_vertices_per_cell, int *num_vertices_per_cell, size_t *cell_to_vertex, size_t *cell_to_vertex_offsets, yac_coordinate_pointer vertex_coordinates, size_t *cell_to_edge, size_t *cell_to_edge_offsets, enum yac_edge_type *edge_type)
Definition dist_grid.c:2106
void yac_dist_grid_determine_dist_edge_owner(struct yac_dist_grid *dist_grid, struct proc_sphere_part_node *proc_sphere_part, size_t *edges, size_t count, int *ranks)
Definition dist_grid.c:6432
static void get_dist_vertex_cells(struct yac_dist_grid_pair *grid_pair, char const *grid_name, size_t *vertices, size_t count, size_t **cells, size_t *num_cells_per_vertex, struct yac_interp_field field)
Definition dist_grid.c:5799
static void generate_ce_ids(struct yac_basic_grid *grid, int *vertex_ranks, int max_num_vertices_per_cell, MPI_Comm comm)
Definition dist_grid.c:641
struct remote_point * yac_dist_grid_get_remote_points(struct yac_dist_grid *dist_grid, enum yac_location location, size_t *points, size_t count)
Definition dist_grid.c:5487
struct yac_const_basic_grid_data * yac_dist_grid_get_basic_grid_data(struct yac_dist_grid *dist_grid)
Definition dist_grid.c:2451
void yac_dist_grid_pair_relocate_point_pairs(struct yac_dist_grid_pair *grid_pair, int a_is_ref, int to_dist_owner, char const *grid_name_a, size_t **points_a, enum yac_location location_a, char const *grid_name_b, size_t **points_b, enum yac_location location_b, double **weights, size_t *count)
Definition dist_grid.c:6493
static MPI_Datatype yac_get_id_reorder_coord_id_mpi_datatype(MPI_Comm comm)
Definition dist_grid.c:451
static void determine_dist_edge_ranks(struct proc_sphere_part_node *proc_sphere_part, struct yac_basic_grid *grid, MPI_Comm comm, size_t *dist_cell_rank_offsets, size_t *dist_edge_rank_offsets, int *num_cell_ranks, int *num_edge_ranks, int **rank_buffer, size_t *rank_buffer_array_size)
Definition dist_grid.c:1135
static int coord_in_cell(double coord[3], struct yac_dist_grid *dist_grid, size_t cell_idx, struct yac_grid_cell *buffer_cell)
Definition dist_grid.c:2633
static void check_core_masks(struct yac_basic_grid *grid)
Definition dist_grid.c:943
static void pack_grid_data_edge(struct yac_dist_grid *dist_grid, size_t idx, void *buffer, int buffer_size, int *position, MPI_Datatype bnd_circle_dt, MPI_Datatype point_info_dt, MPI_Comm comm)
Definition dist_grid.c:3062
static size_t get_edge_reference_vertex(struct yac_dist_grid *dist_grid, size_t edge_idx)
Definition dist_grid.c:215
static void insert_rank(int *ranks, int *count, int rank)
Definition dist_grid.c:295
static void pack_field_data(size_t idx, void *buffer, int buffer_size, int *position, struct yac_field_data *field_data, MPI_Comm comm)
Definition dist_grid.c:2977
static void yac_dist_grid_add_cells(struct yac_dist_grid *dist_grid, yac_int *cell_ids, int *num_vertices_per_cell, struct bounding_circle *cell_bnd_circles, size_t count, size_t *cell_to_vertex, size_t *cell_to_edge, struct remote_point_infos *cell_owners, struct temp_field_data temp_cell_field_data)
Definition dist_grid.c:3521
void yac_dist_grid_pair_do_bnd_circle_search(struct yac_dist_grid_pair *grid_pair, char const *grid_name, const_bounding_circle_pointer bnd_circles, size_t count, size_t **cells, size_t *num_results_per_bnd_circle, struct yac_interp_field field)
Definition dist_grid.c:4748
void yac_dist_grid_pair_do_cell_search(struct yac_dist_grid_pair *grid_pair, char const *search_grid_name, char const *result_grid_name, size_t *search_cells, size_t count, size_t **result_cells, size_t *num_results_per_search_cell, struct yac_interp_field result_field)
Definition dist_grid.c:5066
static void id2idx(char const *caller, yac_int *ids, size_t *idx, size_t num_ids, yac_int *ref_sorted_ids, size_t *ref_sorted_reorder_idx, size_t num_sorted_ids)
Definition dist_grid.c:148
static int compare_n_ids_reorder_reorder(const void *a, const void *b)
Definition dist_grid.c:324
static MPI_Datatype yac_get_id_pos_mpi_datatype(MPI_Comm comm)
Definition dist_grid.c:265
static void pack_grid_data(struct yac_dist_grid *dist_grid, enum yac_location location, uint64_t *pos, size_t count, void **pack_data, int *pack_sizes, MPI_Datatype bnd_circle_dt, MPI_Datatype point_info_dt, MPI_Comm comm)
Definition dist_grid.c:3119
static void generate_global_ids(struct proc_sphere_part_node *proc_sphere_part, struct yac_basic_grid *grid, int **vertex_ranks_, int max_num_vertices_per_cell, MPI_Comm comm)
Definition dist_grid.c:1052
MPI_Comm yac_dist_grid_pair_get_MPI_Comm(struct yac_dist_grid_pair *grid_pair)
Definition dist_grid.c:2434
static void pack_global_id(yac_int global_id, void *buffer, int buffer_size, int *position, MPI_Comm comm)
Definition dist_grid.c:5520
static void yac_dist_grid_pair_get_aux_grid_cells(struct yac_dist_grid_pair *grid_pair, char const *grid_name, size_t *vertices, size_t count, size_t **cells, int *num_cells_per_vertex, struct yac_interp_field field)
Definition dist_grid.c:5885
static int compare_global_vertex_reorder_global_id(const void *a, const void *b)
Definition dist_grid.c:3219
static yac_int const * yac_dist_grid_get_global_ids(struct yac_dist_grid *dist_grid, enum yac_location location)
Definition dist_grid.c:2499
static void pack_grid_data_cell(struct yac_dist_grid *dist_grid, size_t idx, void *buffer, int buffer_size, int *position, MPI_Datatype bnd_circle_dt, MPI_Datatype point_info_dt, MPI_Comm comm)
Definition dist_grid.c:3078
static struct bounding_circle compute_edge_bnd_circle(yac_size_t_2_pointer edge_to_vertex, const yac_coordinate_pointer vertex_coordinates, size_t edge_id)
Definition dist_grid.c:1113
static void unpack_grid_data_vertex(struct global_vertex_reorder *vertex, size_t idx, void *buffer, int buffer_size, int *position, struct temp_field_data temp_vertex_field_data, MPI_Datatype point_info_dt, MPI_Comm comm)
Definition dist_grid.c:3168
static void unpack_grid_data(struct yac_dist_grid *dist_grid, enum yac_location location, size_t count, void *buffer, int buffer_size, MPI_Datatype bnd_circle_dt, MPI_Datatype point_info_dt, MPI_Comm comm)
Definition dist_grid.c:3914
void yac_dist_grid_global_to_local(struct yac_dist_grid *dist_grid, enum yac_location location, yac_int *global_ids, size_t count, size_t *local_ids)
Definition dist_grid.c:5569
static void unpack_grid_data_vertices(struct yac_dist_grid *dist_grid, size_t count, void *buffer, int buffer_size, MPI_Datatype point_info_dt, MPI_Comm comm)
Definition dist_grid.c:3833
static void yac_remote_point_infos_free(struct remote_point_infos *point_infos, size_t count)
Definition dist_grid.c:2590
static struct proc_sphere_part_node * generate_dist_grid_decomposition(struct yac_basic_grid *grid_a, struct yac_basic_grid *grid_b, MPI_Comm comm)
Definition dist_grid.c:2343
void yac_const_basic_grid_data_get_grid_cell(struct yac_const_basic_grid_data *grid_data, size_t cell_idx, struct yac_grid_cell *buffer_cell)
Definition dist_grid.c:2659
static int compare_id_reorder_coord_reorder_idx(const void *a, const void *b)
Definition dist_grid.c:473
static int compare_nnn_search_results_cos_angle(void const *a, void const *b)
Definition dist_grid.c:4331
void yac_dist_grid_pair_determine_orig_owner(struct yac_dist_grid_pair *grid_pair, char const *grid_name, size_t *points, size_t count, enum yac_location location, int *ranks)
Definition dist_grid.c:6462
void yac_dist_grid_pair_get_aux_grid(struct yac_dist_grid_pair *grid_pair, char const *grid_name, size_t *cells, size_t count, size_t **vertex_to_cell, size_t **vertex_to_cell_offsets_, int **num_cells_per_vertex_, struct yac_interp_field field)
Definition dist_grid.c:6154
static void generate_owner_masks(struct yac_dist_grid *dist_grid, int comm_rank, int *vertex_owner)
Definition dist_grid.c:246
static void unpack_grid_data_cells(struct yac_dist_grid *dist_grid, size_t count, void *buffer, int buffer_size, MPI_Datatype bnd_circle_dt, MPI_Datatype point_info_dt, MPI_Comm comm)
Definition dist_grid.c:3723
void yac_dist_grid_pair_do_point_search_(struct yac_dist_grid_pair *grid_pair, char const *grid_name, yac_coordinate_pointer search_coords, size_t count, size_t *cells, int(*coord_in_cell)(double coord[3], struct yac_dist_grid *dist_grid, size_t cell_idx, struct yac_grid_cell *buffer_cell))
Definition dist_grid.c:4088
static void yac_dist_grid_add_edges(struct yac_dist_grid *dist_grid, struct global_edge_reorder *edges, size_t count, size_t *idx, struct temp_field_data temp_edge_field_data)
Definition dist_grid.c:3388
static int coord_in_cell_gc(double coord[3], struct yac_dist_grid *dist_grid, size_t cell_idx, struct yac_grid_cell *buffer_cell)
Definition dist_grid.c:2645
static void yac_dist_grid_single_remote_point_to_local(struct yac_dist_grid *dist_grid, struct single_remote_point *ids, size_t count, enum yac_location location, size_t *idx)
Definition dist_grid.c:3946
static void redistribute_cell_data(struct yac_basic_grid *grid, struct remote_point_infos *dist_cell_infos, size_t num_cells, MPI_Comm comm, MPI_Datatype dt_coord, size_t num_edges, yac_int *sorted_edge_ids, size_t *sorted_edge_reorder_idx, size_t num_vertices, yac_int *sorted_vertex_ids, size_t *sorted_vertex_reorder_idx, int max_num_vertices_per_cell, size_t **cell_to_vertex_, size_t **cell_to_edge_, int **num_vertices_per_cell_, struct yac_field_data **cell_field_data_)
Definition dist_grid.c:1975
void yac_dist_grid_pair_get_corner_cells(struct yac_dist_grid_pair *grid_pair, char const *grid_name, size_t *vertices, size_t count, size_t **vertex_to_cell, size_t *num_cells_per_vertex)
Definition dist_grid.c:6104
static int const * yac_dist_grid_get_owner_mask(struct yac_dist_grid *dist_grid, enum yac_location location)
Definition dist_grid.c:2491
static int compare_global_edge_reorder_global_id(const void *a, const void *b)
Definition dist_grid.c:3379
static void redistribute_edge_data(struct yac_basic_grid *grid, struct remote_point_infos *dist_edge_infos, size_t num_edges, MPI_Comm comm, MPI_Datatype dt_coord, size_t num_vertices, yac_int *sorted_vertex_ids, size_t *sorted_vertex_reorder_idx, yac_size_t_2_pointer *edge_to_vertex_, enum yac_edge_type **edge_type_, struct yac_field_data **edge_field_data_)
Definition dist_grid.c:1882
static void determine_dist_vertex_ranks(int *vertex_ranks, struct yac_basic_grid *grid, MPI_Comm comm, size_t *dist_edge_rank_offsets, int *num_edge_ranks, int *num_vertex_ranks, int **rank_buffer, size_t *rank_buffer_array_size)
Definition dist_grid.c:1255
static void unpack_grid_data_edges(struct yac_dist_grid *dist_grid, size_t count, void *buffer, int buffer_size, MPI_Datatype point_info_dt, MPI_Comm comm)
Definition dist_grid.c:3866
static struct yac_field_data * yac_dist_grid_get_field_data(struct yac_dist_grid *dist_grid, enum yac_location location)
Definition dist_grid.c:2536
static void get_pack_sizes(struct yac_dist_grid *dist_grid, enum yac_location location, uint64_t *pos, size_t count, int *pack_sizes, MPI_Datatype bnd_circle_dt, MPI_Datatype point_info_dt, MPI_Comm comm)
Definition dist_grid.c:2953
static void determine_dist_cell_ranks(struct proc_sphere_part_node *proc_sphere_part, struct yac_basic_grid_data *grid_data, MPI_Comm comm, int **dist_cell_ranks, int *dist_cell_rank_counts, size_t *dist_cell_rank_offsets, int max_num_vertices_per_cell)
Definition dist_grid.c:336
static void yac_single_remote_point_pack(struct single_remote_point *point, void *buffer, int buffer_size, int *position, MPI_Datatype single_remote_point_dt, MPI_Comm comm)
Definition dist_grid.c:5549
static MPI_Datatype yac_get_single_remote_point_mpi_datatype(MPI_Comm comm)
Definition dist_grid.c:4067
static struct bnd_sphere_part_search * dist_grid_pair_get_cell_sphere_part(struct yac_dist_grid_pair *grid_pair, char const *grid_name)
Definition dist_grid.c:2691
static int get_max_num_vertices_per_cell(struct yac_basic_grid_data *grid_data, MPI_Comm comm)
Definition dist_grid.c:2155
static void pack_grid_data_edge_(struct yac_dist_grid *dist_grid, size_t idx, void *buffer, int buffer_size, int *position, MPI_Datatype bnd_circle_dt, MPI_Datatype point_info_dt, MPI_Comm comm)
Definition dist_grid.c:3026
static void yac_dist_grid_free(struct yac_dist_grid grid)
Definition dist_grid.c:2598
static void lookup_single_remote_point_reorder_locally(struct yac_dist_grid *dist_grid, enum yac_location location, struct single_remote_point_reorder *ids, size_t *count, size_t *idx)
Definition dist_grid.c:2765
int const * const_int_pointer
struct bounding_circle const *const const_bounding_circle_pointer
size_t const *const const_size_t_pointer
#define ENSURE_ARRAY_SIZE(arrayp, curr_array_size, req_size)
size_t yac_field_data_get_masks_count(struct yac_field_data *field_data)
Definition field_data.c:57
void yac_field_data_set_mask_data(struct yac_field_data *field_data, size_t mask_idx, int *mask_data)
Definition field_data.c:72
size_t yac_field_data_get_coordinates_count(struct yac_field_data *field_data)
Definition field_data.c:92
yac_const_coordinate_pointer yac_field_data_get_coordinates_data(struct yac_field_data *field_data, size_t coordinates_idx)
Definition field_data.c:97
int const * yac_field_data_get_mask_data(struct yac_field_data *field_data, size_t mask_idx)
Definition field_data.c:62
char const * yac_field_data_get_mask_name(struct yac_field_data *field_data, size_t mask_idx)
Definition field_data.c:82
void yac_field_data_set_coordinates_data(struct yac_field_data *field_data, size_t coordinates_idx, yac_coordinate_pointer coordinates_data)
Definition field_data.c:108
size_t yac_field_data_add_mask_nocpy(struct yac_field_data *field_data, int const *mask, char const *mask_name)
Definition field_data.c:30
struct yac_field_data * yac_field_data_empty_new()
Definition field_data.c:20
size_t yac_field_data_add_coordinates_nocpy(struct yac_field_data *field_data, yac_coordinate_pointer coordinates)
Definition field_data.c:44
struct yac_field_data_set * yac_field_data_set_new(struct yac_field_data *cell_field_data, struct yac_field_data *vertex_field_data, struct yac_field_data *edge_field_data)
void yac_field_data_set_delete(struct yac_field_data_set *field_data_set)
struct yac_field_data * yac_field_data_set_get_field_data(struct yac_field_data_set *field_data_set, enum yac_location location)
static struct sin_cos_angle get_vector_angle_2(double const a[3], double const b[3])
Definition geometry.h:367
static int compare_coords(double const *a, double const *b)
Definition geometry.h:614
static const struct sin_cos_angle SIN_COS_ZERO
Definition geometry.h:44
static int compare_angles(struct sin_cos_angle a, struct sin_cos_angle b)
Definition geometry.h:380
#define yac_angle_tol
Definition geometry.h:34
static void normalise_vector(double v[])
Definition geometry.h:641
static struct sin_cos_angle sin_cos_angle_new(double sin, double cos)
Definition geometry.h:357
static struct sin_cos_angle half_angle(struct sin_cos_angle angle)
Definition geometry.h:552
void yac_init_grid_cell(struct yac_grid_cell *cell)
Definition grid_cell.c:14
void yac_free_grid_cell(struct yac_grid_cell *cell)
Definition grid_cell.c:44
yac_edge_type
Definition grid_cell.h:12
@ YAC_GREAT_CIRCLE_EDGE
great circle
Definition grid_cell.h:13
struct @7::@8 value
yac_location
Definition location.h:12
@ YAC_LOC_CORNER
Definition location.h:15
@ YAC_LOC_EDGE
Definition location.h:16
@ YAC_LOC_CELL
Definition location.h:14
#define xrealloc(ptr, size)
Definition ppm_xfuncs.h:67
#define xcalloc(nmemb, size)
Definition ppm_xfuncs.h:64
#define xmalloc(size)
Definition ppm_xfuncs.h:66
struct proc_sphere_part_node * yac_redistribute_vertices(struct dist_vertex **vertices, size_t *num_vertices, MPI_Comm comm)
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_remote_point_infos_unpack(void *buffer, int buffer_size, int *position, struct remote_point_infos *infos, MPI_Datatype point_info_dt, MPI_Comm comm)
int yac_remote_point_infos_get_pack_size(struct remote_point_infos const *infos, MPI_Datatype point_info_dt, MPI_Comm comm)
MPI_Datatype yac_get_remote_point_info_mpi_datatype(MPI_Comm comm)
void yac_remote_point_infos_pack(struct remote_point_infos const *infos, void *buffer, int buffer_size, int *position, MPI_Datatype point_info_dt, MPI_Comm comm)
void yac_point_sphere_part_search_NNN_ubound(struct point_sphere_part_search *search, size_t num_points, yac_coordinate_pointer coordinates_xyz, size_t n, struct sin_cos_angle *angles)
void yac_bnd_sphere_part_search_do_bnd_circle_search(struct bnd_sphere_part_search *search, struct bounding_circle *bnd_circles, size_t count, size_t **cells, size_t *num_cells_per_bnd_circle)
void yac_point_sphere_part_search_NNN_bnd_circle(struct point_sphere_part_search *search, size_t num_bnd_circles, struct bounding_circle *bnd_circles, size_t n, size_t **local_point_ids, size_t *local_point_ids_array_size, size_t *num_local_point_ids)
struct bnd_sphere_part_search * yac_bnd_sphere_part_search_new(struct bounding_circle *circles, size_t num_circles)
void yac_delete_point_sphere_part_search(struct point_sphere_part_search *search)
struct point_sphere_part_search * yac_point_sphere_part_search_mask_new(size_t num_points, yac_const_coordinate_pointer coordinates_xyz, yac_int const *ids, int const *mask)
void yac_bnd_sphere_part_search_delete(struct bnd_sphere_part_search *search)
struct point_sphere_part_search * yac_point_sphere_part_search_new(size_t num_points, yac_const_coordinate_pointer coordinates_xyz, yac_int const *ids)
void yac_bnd_sphere_part_search_do_point_search(struct bnd_sphere_part_search *search, yac_coordinate_pointer coordinates_xyz, size_t count, size_t **cells, size_t *num_cells_per_coordinate)
void yac_point_sphere_part_search_NNN(struct point_sphere_part_search *search, size_t num_points, double(*coordinates_xyz)[3], size_t n, double **cos_angles, size_t *cos_angles_array_size, double(**result_coordinates_xyz)[3], size_t *result_coordinates_xyz_array_size, size_t **local_point_ids, size_t *local_point_ids_array_size, size_t *num_local_point_ids)
algorithm for searching cells and points on a grid
struct sin_cos_angle inc_angle
angle between the middle point and the boundary of the spherical cap
Definition geometry.h:61
double base_vector[3]
Definition geometry.h:59
double sq_crd
Definition geometry.h:64
double coord[3]
enum yac_edge_type edge_type
Definition dist_grid.c:57
struct remote_point_infos owners
Definition dist_grid.c:59
yac_int edge_to_vertex[2]
Definition dist_grid.c:58
struct remote_point_infos owners
Definition dist_grid.c:50
uint64_t orig_pos
Definition dist_grid.c:64
yac_int global_id
Definition dist_grid.c:63
double coord[3]
Definition dist_grid.c:78
size_t reorder_idx
Definition dist_grid.c:77
yac_int global_id
Definition dist_grid.c:76
struct missing_edge_neighbour::@0 cell
struct missing_edge_neighbour::@0 edge
size_t reorder_idx
Definition dist_grid.c:71
yac_int * ids
Definition dist_grid.c:70
yac_int global_id
Definition dist_grid.c:72
single location information of a point
location information about a point that is located on one or
union remote_point_infos::@46 data
struct remote_point_info single
struct remote_point_info * multi
information (global id and location) about a point that
yac_int global_id
struct remote_point_infos data
structure containing the information (global id and location)
struct remote_point * data
double sin
Definition geometry.h:41
double cos
Definition geometry.h:41
struct single_remote_point data
Definition dist_grid.c:41
struct remote_point_info data
Definition dist_grid.c:37
yac_coordinate_pointer * coordinates
Definition dist_grid.c:85
size_t masks_count
Definition dist_grid.c:84
size_t * masks_array_sizes
Definition dist_grid.c:83
size_t * coordinates_array_sizes
Definition dist_grid.c:86
size_t coordinates_count
Definition dist_grid.c:87
yac_coordinate_pointer vertex_coordinates
yac_size_t_2_pointer edge_to_vertex
enum yac_edge_type * edge_type
size_t * cell_to_vertex_offsets
const yac_const_coordinate_pointer vertex_coordinates
const_size_t_pointer cell_to_vertex_offsets
const_size_t_pointer cell_to_vertex
const const_int_pointer num_vertices_per_cell
const_size_t_pointer cell_to_edge
const const_yac_int_pointer ids[3]
const_size_t_pointer cell_to_edge_offsets
const_yac_edge_type_pointer edge_type
struct point_sphere_part_search * vertex_sphere_part[2]
Definition dist_grid.c:128
struct proc_sphere_part_node * proc_sphere_part
Definition dist_grid.c:127
struct yac_dist_grid dist_grid[2]
Definition dist_grid.c:125
struct bnd_sphere_part_search * cell_sphere_part[2]
Definition dist_grid.c:129
char * grid_names[2]
Definition dist_grid.c:126
int * owner_mask[3]
Definition dist_grid.c:113
MPI_Comm comm
Definition dist_grid.c:121
size_t count[3]
Definition dist_grid.c:111
size_t * cell_to_edge
Definition dist_grid.c:99
size_t * sorted_reorder_idx[3]
Definition dist_grid.c:116
struct yac_field_data_set * field_data
Definition dist_grid.c:120
yac_int * ids[3]
Definition dist_grid.c:94
size_t * cell_to_vertex
Definition dist_grid.c:96
struct bounding_circle * cell_bnd_circles
Definition dist_grid.c:103
struct remote_point_infos * owners[3]
Definition dist_grid.c:105
enum yac_edge_type * edge_type
Definition dist_grid.c:104
yac_coordinate_pointer vertex_coordinates
Definition dist_grid.c:93
size_t * cell_to_edge_offsets
Definition dist_grid.c:101
yac_int * sorted_ids[3]
Definition dist_grid.c:115
size_t * cell_to_vertex_offsets
Definition dist_grid.c:98
yac_size_t_2_pointer edge_to_vertex
Definition dist_grid.c:102
int * num_vertices_per_cell
Definition dist_grid.c:95
size_t total_count[3]
Definition dist_grid.c:107
size_t num_corners
Definition grid_cell.h:21
enum yac_edge_type * edge_type
Definition grid_cell.h:20
size_t array_size
Definition grid_cell.h:22
double(* coordinates_xyz)[3]
Definition grid_cell.h:19
enum yac_location location
Definition basic_grid.h:21
#define MIN(a, b)
#define MAX(a, b)
void yac_quicksort_index_yac_int_size_t(yac_int *a, size_t n, size_t *idx)
void yac_quicksort_index_int_size_t(int *a, size_t n, size_t *idx)
static void yac_remove_duplicates_size_t(size_t *array, size_t *n)
Definition utils_core.h:108
void yac_quicksort_index_size_t_size_t(size_t *a, size_t n, size_t *idx)
static struct user_input_data_points ** points
Definition yac.c:137
#define YAC_ASSERT_F(exp, format,...)
Definition yac_assert.h:19
#define YAC_ASSERT(exp, msg)
Definition yac_assert.h:16
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:577
void yac_free_comm_buffers(size_t *sendcounts, size_t *recvcounts, size_t *sdispls, size_t *rdispls)
Definition yac_mpi.c:633
MPI_Datatype yac_get_bounding_circle_mpi_datatype(MPI_Comm comm)
Definition yac_mpi.c:536
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:602
MPI_Datatype yac_create_resized(MPI_Datatype dt, size_t new_size, MPI_Comm comm)
Definition yac_mpi.c:556
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:131
#define yac_mpi_call(call, comm)
#define YAC_MPI_SIZE_T
Xt_int yac_int
Definition yac_types.h:15
double const (* yac_const_coordinate_pointer)[3]
Definition yac_types.h:20
size_t(* yac_size_t_2_pointer)[2]
Definition yac_types.h:23
#define yac_int_dt
Definition yac_types.h:16
double(* yac_coordinate_pointer)[3]
Definition yac_types.h:19