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