YAC 3.20.0
Yet Another Coupler
Loading...
Searching...
No Matches
interp_weights.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 <string.h>
11
12#include <yaxt.h>
13
14#define WEIGHT_TOL (1e-9)
15
16#include "ppm/ppm_xfuncs.h"
17#include "yac_mpi_internal.h"
19#include "ensure_array_size.h"
20#include "io_utils.h"
21#include "utils_core.h"
26
27#ifdef YAC_NETCDF_ENABLED
28#include <netcdf.h>
29#endif
30
31#define YAC_YAXT_EXCHANGER_STR "YAC_YAXT_EXCHANGER"
32
43
45
47 union {
48 struct {
49 double value;
51 struct {
52 struct remote_point src; // src id
54 struct {
55 struct remote_points * srcs; // src ids
56 } sum;
57 struct {
58 struct remote_points * srcs; // src ids
59 double * weights;
61 struct {
62 struct remote_point src; // src id
63 size_t field_idx;
65 struct {
66 struct remote_points * srcs; // src ids
67 size_t * field_indices;
69 struct {
70 struct remote_points * srcs; // src ids
71 double * weights;
72 size_t * field_indices;
75 struct remote_point tgt; //tgt id
76};
77
84
90
95
100
105
110
116
121
133
139
155
157 MPI_Comm comm, enum yac_location tgt_location,
159
160 struct yac_interp_weights * weights = xmalloc(1 * sizeof(*weights));
161
162 yac_mpi_call(MPI_Comm_dup(comm, &weights->comm), comm);
163 weights->tgt_location = tgt_location;
164 weights->src_locations = xmalloc(num_src_fields * sizeof(*src_locations));
165 memcpy(
166 weights->src_locations, src_locations,
167 num_src_fields * sizeof(*src_locations));
168 weights->num_src_fields = num_src_fields;
169 weights->stencils = NULL;
170 weights->stencils_array_size = 0;
171 weights->stencils_size = 0;
172
173 return weights;
174}
175
176static inline struct remote_point copy_remote_point(
177 struct remote_point point) {
178
179 int count = point.data.count;
180 if (count > 1) {
181 struct remote_point_info * point_infos =
182 xmalloc((size_t)count * sizeof(*point_infos));
183 memcpy(point_infos, point.data.data.multi,
184 (size_t)count * sizeof(*point_infos));
185 point.data.data.multi = point_infos;
186 }
187 return point;
188}
189
190static inline int remote_point_is_valid(
191 char const * routine, struct remote_point point, int * rank_is_target) {
192
193 const int count = point.data.count;
195 count > 0, routine, "owner count has to be > 0 (got %d)", count)
196 struct remote_point_info * point_infos =
197 (count == 1)?&(point.data.data.single):point.data.data.multi;
198
199 int is_valid = 0;
200 for (int i = 0; i < count; ++i)
201 is_valid |= rank_is_target[point_infos[i].rank];
202
203 return is_valid;
204}
205
207 char const * routine, struct remote_point point, int * rank_is_target) {
208
209 const int count = point.data.count;
211 count > 0, routine, "owner count has to be > 0 (got %d)", count)
213 (count == 1)?&(point.data.data.single):point.data.data.multi;
214
215 int valid_count = 0;
216 for (int i = 0; i < count; ++i) {
217 if (rank_is_target[remote_point_infos[i].rank]) valid_count++;
218 }
219
220 struct remote_point remote_point_copy =
221 {.global_id = point.global_id, .data.count = valid_count};
222 struct remote_point_info * remote_point_infos_copy;
223 if (valid_count > 1) {
224 remote_point_infos_copy =
225 xmalloc((size_t)valid_count * sizeof(*remote_point_infos_copy));
226 remote_point_copy.data.data.multi = remote_point_infos_copy;
227 } else {
228 remote_point_infos_copy = &(remote_point_copy.data.data.single);
229 }
230
231 for (int i = 0, j = 0; i < count; ++i) {
232 if (rank_is_target[remote_point_infos[i].rank]) {
233 remote_point_infos_copy[j] = remote_point_infos[i];
234 ++j;
235 }
236 }
237 return remote_point_copy;
238}
239
241 struct remote_point * points_to, struct remote_point * points_from,
242 size_t count, struct remote_point_info ** point_info_buffer_) {
243
244 struct remote_point_info * point_info_buffer = *point_info_buffer_;
245
246 for (size_t i = 0; i < count; ++i) {
247 int curr_count = points_from[i].data.count;
248 points_to[i] = points_from[i];
249 if (curr_count > 1) {
250 points_to[i].data.data.multi = point_info_buffer;
251 memcpy(
252 point_info_buffer, points_from[i].data.data.multi,
253 (size_t)curr_count * sizeof(*point_info_buffer));
254 point_info_buffer += curr_count;
255 }
256 }
257 *point_info_buffer_ = point_info_buffer;
258}
259
260static inline struct remote_points * copy_remote_points(
261 struct remote_point * points, size_t count) {
262
263 size_t point_info_buffer_size = 0;
264 for (size_t i = 0; i < count; ++i)
265 if (points[i].data.count > 1)
266 point_info_buffer_size += (size_t)(points[i].data.count);
267
268 struct remote_points * points_copy =
269 xmalloc(point_info_buffer_size * sizeof(struct remote_point_info) +
270 sizeof(*points_copy));
271 points_copy->data = xmalloc(count * sizeof(*(points_copy->data)));
272 points_copy->count = count;
273 struct remote_point_info * point_info_buffer = &(points_copy->buffer[0]);
274
276 points_copy->data, points, count, &point_info_buffer);
277
278 return points_copy;
279}
280
282 struct remote_point ** points, size_t * counts, size_t num_fields) {
283
284 size_t point_info_buffer_size = 0;
285 size_t total_count = 0;
286 for (size_t i = 0; i < num_fields; ++i) {
287 total_count += counts[i];
288 for (size_t j = 0; j < counts[i]; ++j) {
289 if (points[i][j].data.count > 1)
290 point_info_buffer_size += (size_t)(points[i][j].data.count);
291 }
292 }
293
294 struct remote_points * points_copy =
295 xmalloc(point_info_buffer_size * sizeof(struct remote_point_info) +
296 sizeof(*points_copy));
297 points_copy->data = xmalloc(total_count * sizeof(*(points_copy->data)));
298 points_copy->count = total_count;
299 struct remote_point_info * point_info_buffer = &(points_copy->buffer[0]);
300
301 for (size_t i = 0, k = 0; i < num_fields; ++i) {
302 for (size_t j = 0; j < counts[i]; ++j, ++k) {
303 int curr_count = points[i][j].data.count;
304 points_copy->data[k] = points[i][j];
305 if (curr_count > 1) {
306 points_copy->data[k].data.data.multi = point_info_buffer;
307 memcpy(
308 point_info_buffer, points[i][j].data.data.multi,
309 (size_t)curr_count * sizeof(*point_info_buffer));
310 point_info_buffer += curr_count;
311 }
312 }
313 }
314 return points_copy;
315}
316
318 struct yac_interp_weights * weights, struct remote_points * tgts,
319 double fixed_value) {
320
321 struct interp_weight_stencil * stencils = weights->stencils;
322 size_t stencils_array_size = weights->stencils_array_size;
323 size_t stencils_size = weights->stencils_size;
324
325 ENSURE_ARRAY_SIZE(stencils, stencils_array_size, stencils_size + tgts->count);
326
327 for (size_t i = 0; i < tgts->count; ++i, ++stencils_size) {
328
329 stencils[stencils_size].type = FIXED;
330 stencils[stencils_size].tgt = copy_remote_point(tgts->data[i]);
331 stencils[stencils_size].data.fixed.value = fixed_value;
332 }
333
334 weights->stencils = stencils;
335 weights->stencils_array_size = stencils_array_size;
336 weights->stencils_size = stencils_size;
337}
338
340 struct yac_interp_weights * weights, struct remote_points * tgts,
341 size_t * num_src_per_tgt, struct remote_point * srcs, double * w) {
342
343 if (tgts->count == 0) return;
344
345 // remove near-zero weights for each target
346 // (relative to max weight per target)
347 for (size_t tgt_idx = 0, old_weight_offset = 0, new_weight_offset = 0;
348 tgt_idx < tgts->count; tgt_idx++) {
349
350 size_t curr_count = num_src_per_tgt[tgt_idx];
351
352 // find maximum weight for this target
353 double max_weight = 0.0;
354 double min_weight = DBL_MAX;
355 for (size_t weight_idx = 0; weight_idx < curr_count; weight_idx++) {
356 double abs_weight = fabs(w[old_weight_offset + weight_idx]);
357 if (abs_weight > max_weight) max_weight = abs_weight;
358 if (abs_weight < min_weight) min_weight = abs_weight;
359 }
360
361 // compute relative weight threshold
362 double const weight_threshold = max_weight * WEIGHT_TOL;
363
364 // if there are near-zero weights
365 if (min_weight < weight_threshold) {
366
367 // for all weights of the current target
368 for (size_t weight_idx = 0; weight_idx < curr_count;
369 weight_idx++, old_weight_offset++) {
370
371 // if current weight is below threshold
372 if (fabs(w[old_weight_offset]) < weight_threshold) {
373 // skip weight
374 num_src_per_tgt[tgt_idx]--;
375 } else {
376 if (new_weight_offset != old_weight_offset) {
377 srcs[new_weight_offset] = srcs[old_weight_offset];
378 w[new_weight_offset] = w[old_weight_offset];
379 }
380 ++new_weight_offset;
381 }
382 }
383
385 (curr_count == 0) || (num_src_per_tgt[tgt_idx] > 0),
386 "internal error; no weights left after removing near-zero weights "
387 "for target with id %" YAC_INT_FMT,
388 tgts->data[tgt_idx].global_id);
389
390 } else { // there are no near-zero weights for the current target
391
392 if (new_weight_offset != old_weight_offset) {
393 memmove(
394 srcs + new_weight_offset, srcs + old_weight_offset,
395 curr_count * sizeof(*srcs));
396 memmove(
397 w + new_weight_offset, w + old_weight_offset,
398 curr_count * sizeof(*w));
399 }
400 new_weight_offset += curr_count;
401 old_weight_offset += curr_count;
402 }
403 }
404
405 // check whether all weights are 1.0 and whether the number of source
406 // points per target is one for all targets
407 int flag_weight_one = 1;
408 int flag_count_one = 1;
409 for (size_t i = 0, j = 0;
410 (i < tgts->count) && (flag_weight_one || flag_count_one); ++i) {
411
412 size_t curr_count = num_src_per_tgt[i];
413 flag_count_one &= curr_count == 1;
414
415 for (size_t k = 0; (k < curr_count) && flag_weight_one; ++k, ++j)
416 flag_weight_one &= fabs(w[j] - 1.0) < WEIGHT_TOL;
417 }
418
419 // if all weights are 1.0 -> use more optimised weight type
420 if (flag_weight_one) {
421
422 // if the number of source points for all target points is one
423 if (flag_count_one)
425 else
426 yac_interp_weights_add_sum(weights, tgts, num_src_per_tgt, srcs);
427
428 } else {
429
430 struct interp_weight_stencil * stencils = weights->stencils;
431 size_t stencils_array_size = weights->stencils_array_size;
432 size_t stencils_size = weights->stencils_size;
433
434 ENSURE_ARRAY_SIZE(stencils, stencils_array_size, stencils_size + tgts->count);
435
436 for (size_t i = 0; i < tgts->count; ++i, ++stencils_size) {
437
438 size_t curr_num_src = num_src_per_tgt[i];
439
440 // remove target for which no weights were provided
441 if (curr_num_src == 0) {
442 --stencils_size;
443 continue;
444 }
445
446 double * curr_weights =
447 xmalloc(curr_num_src * sizeof(*curr_weights));
448
449 stencils[stencils_size].type = WEIGHT_SUM;
450 stencils[stencils_size].tgt = copy_remote_point(tgts->data[i]);
451 stencils[stencils_size].data.weight_sum.srcs =
452 copy_remote_points(srcs, curr_num_src);
453 stencils[stencils_size].data.weight_sum.weights = curr_weights;
454 memcpy(curr_weights, w, curr_num_src * sizeof(*curr_weights));
455
456 srcs += curr_num_src;
457 w += curr_num_src;
458 }
459
460 weights->stencils = stencils;
461 weights->stencils_array_size = stencils_array_size;
462 weights->stencils_size = stencils_size;
463 }
464}
465
467 struct yac_interp_weights * weights, struct remote_points * tgts,
468 size_t * num_src_per_tgt, struct remote_point * srcs) {
469
470 if (tgts->count == 0) return;
471
472 // check whether the number of source points per target is one
473 // for all targets
474 int flag_count_one = 1;
475 for (size_t i = 0; i < tgts->count; ++i) {
476 if (num_src_per_tgt[i] != 1) {
477 flag_count_one = 0;
478 break;
479 }
480 }
481
482 if (flag_count_one) {
483
485
486 } else {
487
488 struct interp_weight_stencil * stencils = weights->stencils;
489 size_t stencils_array_size = weights->stencils_array_size;
490 size_t stencils_size = weights->stencils_size;
491
492 ENSURE_ARRAY_SIZE(stencils, stencils_array_size, stencils_size + tgts->count);
493
494 for (size_t i = 0; i < tgts->count; ++i, ++stencils_size) {
495
496 size_t curr_num_src = num_src_per_tgt[i];
497
498 stencils[stencils_size].type = SUM;
499 stencils[stencils_size].tgt = copy_remote_point(tgts->data[i]);
500 stencils[stencils_size].data.weight_sum.srcs =
501 copy_remote_points(srcs, curr_num_src);
502 stencils[stencils_size].data.weight_sum.weights = NULL;
503
504 srcs += curr_num_src;
505 }
506
507 weights->stencils = stencils;
508 weights->stencils_array_size = stencils_array_size;
509 weights->stencils_size = stencils_size;
510 }
511}
512
514 struct yac_interp_weights * weights, struct remote_points * tgts,
515 struct remote_point * srcs) {
516
517 if (tgts->count == 0) return;
518
519 struct interp_weight_stencil * stencils = weights->stencils;
520 size_t stencils_array_size = weights->stencils_array_size;
521 size_t stencils_size = weights->stencils_size;
522
523 ENSURE_ARRAY_SIZE(stencils, stencils_array_size, stencils_size + tgts->count);
524
525 for (size_t i = 0; i < tgts->count; ++i, ++stencils_size) {
526
527 stencils[stencils_size].type = DIRECT;
528 stencils[stencils_size].tgt = copy_remote_point(tgts->data[i]);
529 stencils[stencils_size].data.direct.src = copy_remote_point(srcs[i]);
530 }
531
532 weights->stencils = stencils;
533 weights->stencils_array_size = stencils_array_size;
534 weights->stencils_size = stencils_size;
535}
536
538 struct yac_interp_weights * weights, struct remote_points * tgts,
539 size_t * src_field_indices, struct remote_point ** srcs_per_field,
540 size_t num_src_fields) {
541
542 if (tgts->count == 0) return;
543
544 if (num_src_fields == 1) {
545 yac_interp_weights_add_direct(weights, tgts, srcs_per_field[0]);
546 return;
547 }
548
549 struct interp_weight_stencil * stencils = weights->stencils;
550 size_t stencils_array_size = weights->stencils_array_size;
551 size_t stencils_size = weights->stencils_size;
552
554 stencils, stencils_array_size, stencils_size + tgts->count);
555 stencils += stencils_size;
556
557 size_t srcs_offsets[num_src_fields];
558 memset(srcs_offsets, 0, num_src_fields * sizeof(srcs_offsets[0]));
559
560 for (size_t i = 0; i < tgts->count; ++i) {
561
562 size_t src_field_idx = src_field_indices[i];
563 stencils[i].type = DIRECT_MF;
564 stencils[i].tgt = copy_remote_point(tgts->data[i]);
565 stencils[i].data.direct_mf.src =
567 srcs_per_field[src_field_idx][srcs_offsets[src_field_idx]++]);
568 stencils[i].data.direct_mf.field_idx = src_field_idx;
569 }
570
571 weights->stencils = stencils;
572 weights->stencils_array_size = stencils_array_size;
573 weights->stencils_size += tgts->count;
574}
575
577 struct yac_interp_weights * weights, struct remote_points * tgts,
578 size_t * num_src_per_field_per_tgt, struct remote_point ** srcs_per_field,
579 size_t num_src_fields) {
580
581 if (tgts->count == 0) return;
582
583 if (num_src_fields == 1) {
585 weights, tgts, num_src_per_field_per_tgt, srcs_per_field[0]);
586 return;
587 }
588
589 // check whether the number of source points per target is one
590 // for all targets
591 int flag_count_one = 1;
592 for (size_t i = 0, k = 0; i < tgts->count; ++i) {
593 size_t count = 0;
594 for (size_t j = 0; j < num_src_fields; ++j, ++k)
595 count += num_src_per_field_per_tgt[k];
596 if (count != 1) {
597 flag_count_one = 0;
598 break;
599 }
600 }
601
602 if (flag_count_one) {
603
604 size_t * src_field_indices =
605 xmalloc(tgts->count * sizeof(*src_field_indices));
606
607 for (size_t i = 0, k = 0; i < tgts->count; ++i)
608 for (size_t j = 0; j < num_src_fields; ++j, ++k)
609 if (num_src_per_field_per_tgt[k])
610 src_field_indices[i] = j;
611
613 weights, tgts, src_field_indices, srcs_per_field, num_src_fields);
614
615 free(src_field_indices);
616
617 } else {
618 struct remote_point * curr_srcs_per_field[num_src_fields];
619 memcpy(curr_srcs_per_field, srcs_per_field,
620 num_src_fields * sizeof(*srcs_per_field));
621
622 struct interp_weight_stencil * stencils = weights->stencils;
623 size_t stencils_array_size = weights->stencils_array_size;
624 size_t stencils_size = weights->stencils_size;
625
627 stencils, stencils_array_size, stencils_size + tgts->count);
628
629 for (size_t i = 0; i < tgts->count; ++i, ++stencils_size) {
630
631 size_t * curr_num_src_per_src_field =
632 num_src_per_field_per_tgt + i * num_src_fields;
633 size_t curr_num_src = 0;
634 for (size_t j = 0; j < num_src_fields; ++j)
635 curr_num_src += curr_num_src_per_src_field[j];
636
637 stencils[stencils_size].type = SUM_MF;
638 stencils[stencils_size].tgt = copy_remote_point(tgts->data[i]);
639 stencils[stencils_size].data.sum_mf.field_indices =
640 xmalloc(
641 curr_num_src *
642 sizeof(*(stencils[stencils_size].data.sum_mf.field_indices)));
643 for (size_t j = 0, l = 0; j < num_src_fields; ++j) {
644 size_t curr_num_src = curr_num_src_per_src_field[j];
645 for (size_t k = 0; k < curr_num_src; ++k, ++l) {
646 stencils[stencils_size].data.sum_mf.field_indices[l] = j;
647 }
648 }
649 stencils[stencils_size].data.sum_mf.srcs =
651 curr_srcs_per_field, curr_num_src_per_src_field, num_src_fields);
652
653 for (size_t j = 0; j < num_src_fields; ++j)
654 curr_srcs_per_field[j] += curr_num_src_per_src_field[j];
655 }
656
657 weights->stencils = stencils;
658 weights->stencils_array_size = stencils_array_size;
659 weights->stencils_size = stencils_size;
660 }
661}
662
664 struct yac_interp_weights * weights, struct remote_points * tgts,
665 size_t * num_src_per_field_per_tgt, struct remote_point ** srcs_per_field,
666 double * w, size_t num_src_fields) {
667
668 if (tgts->count == 0) return;
669
670 if (num_src_fields == 1) {
672 weights, tgts, num_src_per_field_per_tgt, srcs_per_field[0], w);
673 return;
674 }
675
676 // check whether all weights are 1.0 and whether the number of source
677 // points per target is one for all targets
678 int flag_weight_one = 1;
679 for (size_t i = 0, j = 0;
680 (i < tgts->count) && flag_weight_one; ++i) {
681
682 for (size_t src_field_idx = 0; src_field_idx < num_src_fields;
683 ++src_field_idx) {
684
685 size_t curr_count =
686 num_src_per_field_per_tgt[i * num_src_fields + src_field_idx];
687
688 for (size_t k = 0; (k < curr_count) && flag_weight_one; ++k, ++j)
689 flag_weight_one &= fabs(w[j] - 1.0) < WEIGHT_TOL;
690 }
691 }
692
693 // if all weights are 1.0 -> use more optimised weight type
694 if (flag_weight_one) {
695
697 weights, tgts, num_src_per_field_per_tgt, srcs_per_field, num_src_fields);
698
699 } else {
700
701 struct remote_point * curr_srcs_per_field[num_src_fields];
702 memcpy(curr_srcs_per_field, srcs_per_field,
703 num_src_fields * sizeof(*srcs_per_field));
704
705 struct interp_weight_stencil * stencils = weights->stencils;
706 size_t stencils_array_size = weights->stencils_array_size;
707 size_t stencils_size = weights->stencils_size;
708
710 stencils, stencils_array_size, stencils_size + tgts->count);
711
712 for (size_t i = 0; i < tgts->count; ++i, ++stencils_size) {
713
714 size_t * curr_num_src_per_src_field =
715 num_src_per_field_per_tgt + i * num_src_fields;
716 size_t curr_num_weights = 0;
717 for (size_t j = 0; j < num_src_fields; ++j)
718 curr_num_weights += curr_num_src_per_src_field[j];
719 double * curr_weights =
720 xmalloc(curr_num_weights * sizeof(*curr_weights));
721 size_t * field_indices =
722 xmalloc(curr_num_weights * sizeof(*field_indices));
723
724 stencils[stencils_size].type = WEIGHT_SUM_MF;
725 stencils[stencils_size].tgt = copy_remote_point(tgts->data[i]);
726 stencils[stencils_size].data.weight_sum_mf.field_indices = field_indices;
727 for (size_t j = 0, l = 0; j < num_src_fields; ++j) {
728 size_t curr_num_src = curr_num_src_per_src_field[j];
729 for (size_t k = 0; k < curr_num_src; ++k, ++l) field_indices[l] = j;
730 }
731 stencils[stencils_size].data.weight_sum_mf.srcs =
732 copy_remote_points_mf(curr_srcs_per_field, curr_num_src_per_src_field, num_src_fields);
733 stencils[stencils_size].data.weight_sum_mf.weights = curr_weights;
734 memcpy(curr_weights, w, curr_num_weights * sizeof(*curr_weights));
735
736 for (size_t j = 0; j < num_src_fields; ++j)
737 curr_srcs_per_field[j] += curr_num_src_per_src_field[j];
738 w += curr_num_weights;
739 }
740
741 weights->stencils = stencils;
742 weights->stencils_array_size = stencils_array_size;
743 weights->stencils_size = stencils_size;
744 }
745}
746
747static int compare_stencils_fixed(const void * a, const void * b) {
748
749 int ret = (((struct interp_weight_stencil_fixed *)a)->value >
750 ((struct interp_weight_stencil_fixed *)b)->value) -
751 (((struct interp_weight_stencil_fixed *)a)->value <
752 ((struct interp_weight_stencil_fixed *)b)->value);
753
754 if (ret) return ret;
755
756 return (((struct interp_weight_stencil_fixed *)a)->orig_pos >
757 ((struct interp_weight_stencil_fixed *)b)->orig_pos) -
758 (((struct interp_weight_stencil_fixed *)a)->orig_pos <
759 ((struct interp_weight_stencil_fixed *)b)->orig_pos);
760}
761
762static MPI_Datatype get_fixed_stencil_mpi_datatype(MPI_Comm comm) {
763
764 struct interp_weight_stencil_fixed dummy = {0};
765 MPI_Datatype fixed_stencil_dt;
766 enum {NUM_MEMBERS = 2};
767 int array_of_blocklengths[NUM_MEMBERS] = {1, 1};
768 MPI_Aint array_of_displacements[NUM_MEMBERS];
769 {
770 MPI_Aint base_addr;
771 yac_mpi_call(MPI_Get_address(&dummy, &base_addr), comm);
773 MPI_Get_address(
774 &(dummy.value), &array_of_displacements[0]), comm);
775 array_of_displacements[0] -= base_addr;
777 MPI_Get_address(
778 &(dummy.orig_pos), &array_of_displacements[1]), comm);
779 array_of_displacements[1] -= base_addr;
780 }
781 const MPI_Datatype array_of_types[NUM_MEMBERS] =
782 {MPI_DOUBLE, YAC_MPI_SIZE_T};
784 MPI_Type_create_struct(
785 NUM_MEMBERS, array_of_blocklengths, array_of_displacements,
786 array_of_types, &fixed_stencil_dt), comm);
787 return yac_create_resized(fixed_stencil_dt, sizeof(dummy), comm);
788}
789
791 void * interp, double fixed_value, size_t count, size_t * tgt_pos) {
792
794 (struct yac_interpolation*)interp, fixed_value, count, tgt_pos);
795}
796
798 void * interp, double fixed_value, size_t count, size_t * tgt_pos) {
799
801 &((struct yac_interpolation_raw *)interp)->interp_weights_data;
802
804 xrealloc(
810
812 xrealloc(
818
819 size_t total_num_fixed_tgt = 0;
820 for (size_t i = 0; i < interp_weights_data->num_fixed_values; ++i)
821 total_num_fixed_tgt += interp_weights_data->num_tgt_per_fixed_value[i];
823 xrealloc(
825 (total_num_fixed_tgt + count) *
827 memcpy(
828 interp_weights_data->tgt_idx_fixed + total_num_fixed_tgt,
829 tgt_pos, count * sizeof(*tgt_pos));
830
832}
833
835 MPI_Comm comm, size_t count,
836 struct interp_weight_stencil * fixed_stencils,
837 void * interp, void (*interp_add_fixed)(void*, double, size_t, size_t*),
838 int * rank_is_target) {
839
840 //---------------------------------------------------------------------------
841 // redistribute fixed stencils to owners of fixed target points
842 // (a target point can be owned by multiple processes)
843 //---------------------------------------------------------------------------
844
845 int comm_size;
846 yac_mpi_call(MPI_Comm_size(comm, &comm_size), comm);
847
848 size_t * sendcounts, * recvcounts, * sdispls, *rdispls;
850 1, &sendcounts, &recvcounts, &sdispls, &rdispls, comm);
851
852 // count the number of fixed stencils that need to be sent to each process
853 for (size_t i = 0; i < count; ++i) {
854 int curr_count = fixed_stencils[i].tgt.data.count;
855 struct remote_point_info * curr_point_infos =
856 (curr_count == 1)?
857 (&(fixed_stencils[i].tgt.data.data.single)):
858 (fixed_stencils[i].tgt.data.data.multi);
859 for (int j = 0; j < curr_count; ++j)
860 sendcounts[curr_point_infos[j].rank]++;
861 }
862
863 // if a process is not a target, but there are stencils available for it,
864 // ignore them
865 for (int i = 0; i < comm_size; ++i)
866 if (!rank_is_target[i]) sendcounts[i] = 0;
867
869 1, sendcounts, recvcounts, sdispls, rdispls, comm);
870
871 size_t send_buffer_size =
872 sdispls[comm_size] + sendcounts[comm_size - 1];
873 size_t recv_buffer_size =
874 rdispls[comm_size - 1] + recvcounts[comm_size - 1];
875
877 xmalloc((send_buffer_size + recv_buffer_size) * sizeof(*buffer));
878 struct interp_weight_stencil_fixed * send_buffer = buffer + recv_buffer_size;
880
881 // pack fixed stencils
882 for (size_t i = 0; i < count; ++i) {
883 int curr_count = fixed_stencils[i].tgt.data.count;
884 struct remote_point_info * curr_point_infos =
885 (curr_count == 1)?
886 (&(fixed_stencils[i].tgt.data.data.single)):
887 (fixed_stencils[i].tgt.data.data.multi);
888 double value = fixed_stencils[i].data.fixed.value;
889 for (int j = 0; j < curr_count; ++j) {
890 int tgt_rank = curr_point_infos[j].rank;
891 if (rank_is_target[tgt_rank]) {
892 size_t pos = sdispls[tgt_rank + 1]++;
893 send_buffer[pos].value = value;
894 send_buffer[pos].orig_pos = curr_point_infos[j].orig_pos;
895 }
896 }
897 }
898
899 // create MPI Datatype for exchanging fixed stencils
900 MPI_Datatype stencil_fixed_dt = get_fixed_stencil_mpi_datatype(comm);
901
902 // redistribute fixed stencils to owners of respective target points
904 send_buffer, sendcounts, sdispls, recv_buffer, recvcounts, rdispls,
905 sizeof(*send_buffer), stencil_fixed_dt, comm,
906 "yac_interp_weights_redist_fixed", __LINE__);
907
908 yac_free_comm_buffers(sendcounts, recvcounts, sdispls, rdispls);
909 yac_mpi_call(MPI_Type_free(&stencil_fixed_dt), comm);
910
911 if (recv_buffer_size == 0) {
912 free(buffer);
913 return;
914 }
915
916 //---------------------------------------------------------------------------
917 // store received stencils in interp data structure
918 //---------------------------------------------------------------------------
919
920 // sort stencils first by fixed value and second by orig_pos
921 qsort(recv_buffer, recv_buffer_size, sizeof(*recv_buffer),
923
924 size_t * tgt_pos = xmalloc(recv_buffer_size * sizeof(*tgt_pos));
925 for (size_t i = 0; i < recv_buffer_size; ++i)
926 tgt_pos[i] = (size_t)(recv_buffer[i].orig_pos);
927
928 size_t offset = 0, i = 0;
929 while (offset < recv_buffer_size) {
930 double fixed_value = recv_buffer[i].value;
931 // use memcmp for handling NaNs
932 while ((i < recv_buffer_size) &&
933 !memcmp(&fixed_value, &recv_buffer[i].value, sizeof(fixed_value))
934 ) {
935 ++i;
936 }
937 size_t curr_count = i - offset;
939 interp, fixed_value, curr_count, tgt_pos + offset);
940 offset = i;
941 }
942
943 free(buffer);
944 free(tgt_pos);
945}
946
947// a source point may have multiple owners, this routine returns one of them
948static inline struct remote_point_info select_src(
949 char const * routine, struct remote_point_infos src, int * rank_is_source) {
950
952 src.count > 0, routine, "owner count has to be > 0 (got %d)", src.count)
953
954 struct remote_point_info src_point_info = {.rank = -1};
955
956 if (src.count == 1) {
957
958 src_point_info = src.data.single;
959
960 } else {
961
962 int min_rank = INT_MAX;
963 size_t min_rank_idx = SIZE_MAX;
964 for (int i = 0; i < src.count; ++i) {
965 if ((src.data.multi[i].rank < min_rank) &&
966 (rank_is_source[src.data.multi[i].rank])) {
967 min_rank = src.data.multi[i].rank;
968 min_rank_idx = i;
969 }
970 }
971
972 src_point_info =
973 src.data.multi[(min_rank_idx != SIZE_MAX)?min_rank_idx:0];
974 }
975
977 rank_is_source[src_point_info.rank], routine,
978 "missing source field data from rank %d", src_point_info.rank);
979
980 return src_point_info;
981}
982
984 struct Xt_redist_msg * msgs, size_t count, MPI_Comm comm) {
985 for (size_t i = 0; i < count; ++i) {
986 MPI_Datatype * dt = &(msgs[i].datatype);
987 if (*dt != MPI_DATATYPE_NULL) yac_mpi_call(MPI_Type_free(dt), comm);
988 }
989 free(msgs);
990}
991
1006 size_t * src_orig_poses, size_t * sendcounts,
1007 struct interp_weight_stencil_direct * tgt_stencils,
1008 size_t * recvcounts, MPI_Comm comm, Xt_config redist_config) {
1009
1010 int comm_size;
1011 yac_mpi_call(MPI_Comm_size(comm, &comm_size), comm);
1012
1013 size_t nsend = 0, nrecv = 0;
1014 size_t max_buffer_size = 0;
1015 for (int i = 0; i < comm_size; ++i) {
1016 nsend += sendcounts[i] > 0;
1017 nrecv += recvcounts[i] > 0;
1018 if (max_buffer_size < sendcounts[i]) max_buffer_size = sendcounts[i];
1019 if (max_buffer_size < recvcounts[i]) max_buffer_size = recvcounts[i];
1020 }
1021
1022 size_t total_num_msg = nsend + nrecv;
1023
1024 struct Xt_redist_msg * msgs_buffer =
1025 xmalloc(total_num_msg * sizeof(*msgs_buffer));
1026 struct Xt_redist_msg * send_msgs = msgs_buffer;
1027 struct Xt_redist_msg * recv_msgs = msgs_buffer + nsend;
1028
1029 int * pos_buffer = xmalloc((size_t)max_buffer_size * sizeof(*pos_buffer));
1030
1031 // generate yaxt send and receive messages
1032 nsend = 0;
1033 nrecv = 0;
1034 for (int i = 0; i < comm_size; ++i) {
1035 if (recvcounts[i] > 0) {
1036 for (size_t j = 0; j < recvcounts[i]; ++j)
1037 pos_buffer[j] = (int)tgt_stencils[j].orig_pos;
1038 tgt_stencils += recvcounts[i];
1039 recv_msgs[nrecv].rank = i;
1040 recv_msgs[nrecv].datatype =
1041 xt_mpi_generate_datatype(pos_buffer, recvcounts[i], MPI_DOUBLE, comm);
1042 nrecv++;
1043 }
1044 if (sendcounts[i] > 0) {
1045 for (size_t j = 0; j < sendcounts[i]; ++j)
1046 pos_buffer[j] = (int)src_orig_poses[j];
1047 src_orig_poses += sendcounts[i];
1048 send_msgs[nsend].rank = i;
1049 send_msgs[nsend].datatype =
1050 xt_mpi_generate_datatype(pos_buffer, sendcounts[i], MPI_DOUBLE, comm);
1051 nsend++;
1052 }
1053 }
1054
1055 free(pos_buffer);
1056
1057 Xt_redist redist;
1058 MPI_Comm split_comm;
1059
1060 // only processes that have to sent/receive data are included in the redist,
1061 // the others receive a dummy redist
1062 if (total_num_msg > 0) {
1063
1064 // generate MPI communicator containing all ranks taking part in the
1065 // exchange
1066 yac_mpi_call(MPI_Comm_split(comm, 1, 0, &split_comm), comm);
1067
1068 int * rank_buffer =
1069 xmalloc(2 * total_num_msg * sizeof(*rank_buffer));
1070 int * orig_ranks = rank_buffer;
1071 int * split_ranks = rank_buffer + total_num_msg;
1072
1073 for (size_t i = 0; i < total_num_msg; ++i)
1074 orig_ranks[i] = msgs_buffer[i].rank;
1075
1076 MPI_Group orig_group, split_group;
1077 yac_mpi_call(MPI_Comm_group(comm, &orig_group), comm);
1078 yac_mpi_call(MPI_Comm_group(split_comm, &split_group), comm);
1079
1080 // translate the ranks in the sent/receive messages to ones in the
1081 // split comm
1083 MPI_Group_translate_ranks(orig_group, total_num_msg, orig_ranks,
1084 split_group, split_ranks), split_comm);
1085
1086 for (size_t i = 0; i < total_num_msg; ++i)
1087 msgs_buffer[i].rank = split_ranks[i];
1088
1089 free(rank_buffer);
1090
1091 yac_mpi_call(MPI_Group_free(&split_group), comm);
1092 yac_mpi_call(MPI_Group_free(&orig_group), comm);
1093
1094 // generate redist
1095 redist =
1096 xt_redist_single_array_base_custom_new(
1097 nsend, nrecv, send_msgs, recv_msgs, split_comm, redist_config);
1098
1099 } else {
1100 yac_mpi_call(MPI_Comm_split(comm, 0, 0, &split_comm), comm);
1101 redist = NULL;
1102 }
1103
1104 yac_mpi_call(MPI_Comm_free(&split_comm), comm);
1105 xt_redist_msg_free(msgs_buffer, total_num_msg, comm);
1106
1107 return redist;
1108}
1109
1126 size_t * src_orig_poses, size_t * sendcounts,
1127 struct interp_weight_stencil_direct_mf * tgt_stencils,
1128 size_t * recvcounts, size_t num_src_fields, MPI_Comm comm,
1129 Xt_config redist_config) {
1130
1131 int comm_size;
1132 yac_mpi_call(MPI_Comm_size(comm, &comm_size), comm);
1133
1134 size_t nsends[num_src_fields], nrecvs[num_src_fields];
1135 size_t max_buffer_size = 0;
1136 memset(nsends, 0, num_src_fields * sizeof(nsends[0]));
1137 memset(nrecvs, 0, num_src_fields * sizeof(nrecvs[0]));
1138 for (int i = 0; i < comm_size; ++i) {
1139 for (size_t j = 0; j < num_src_fields; ++j) {
1140 size_t idx = (size_t)i * num_src_fields + j;
1141 if (sendcounts[idx] > 0) nsends[j]++;
1142 if (recvcounts[idx] > 0) nrecvs[j]++;
1143 if (max_buffer_size < sendcounts[idx]) max_buffer_size = sendcounts[idx];
1144 if (max_buffer_size < recvcounts[idx]) max_buffer_size = recvcounts[idx];
1145 }
1146 }
1147
1148 size_t nsend = 0, nrecv = 0;
1149 size_t send_offsets[num_src_fields];
1150 size_t recv_offsets[num_src_fields];
1151 for (size_t i = 0; i < num_src_fields; ++i) {
1152 send_offsets[i] = nsend;
1153 recv_offsets[i] = nrecv;
1154 nsend += nsends[i];
1155 nrecv += nrecvs[i];
1156 }
1157
1158 size_t total_num_msg = nsend + nrecv;
1159
1160 struct Xt_redist_msg * msgs_buffer =
1161 xmalloc(total_num_msg * sizeof(*msgs_buffer));
1162 struct Xt_redist_msg * send_msgs = msgs_buffer;
1163 struct Xt_redist_msg * recv_msgs = msgs_buffer + nsend;
1164
1165 int * pos_buffer = xmalloc(max_buffer_size * sizeof(*pos_buffer));
1166
1167 // generate yaxt send and receive messages
1168 for (int i = 0; i < comm_size; ++i) {
1169 for (size_t src_field_idx = 0; src_field_idx < num_src_fields;
1170 ++src_field_idx) {
1171 size_t idx = (size_t)i * num_src_fields + src_field_idx;
1172 if (recvcounts[idx] > 0) {
1173 for (size_t j = 0; j < recvcounts[idx]; ++j)
1174 pos_buffer[j] = (int)tgt_stencils[j].orig_pos;
1175 tgt_stencils += recvcounts[idx];
1176 recv_msgs[recv_offsets[src_field_idx]].rank = i;
1177 recv_msgs[recv_offsets[src_field_idx]].datatype =
1178 xt_mpi_generate_datatype(
1179 pos_buffer, recvcounts[idx], MPI_DOUBLE, comm);
1180 recv_offsets[src_field_idx]++;
1181 }
1182 if (sendcounts[idx] > 0) {
1183 for (size_t j = 0; j < sendcounts[idx]; ++j)
1184 pos_buffer[j] = (int)src_orig_poses[j];
1185 src_orig_poses += sendcounts[idx];
1186 send_msgs[send_offsets[src_field_idx]].rank = i;
1187 send_msgs[send_offsets[src_field_idx]].datatype =
1188 xt_mpi_generate_datatype(
1189 pos_buffer, sendcounts[idx], MPI_DOUBLE, comm);
1190 send_offsets[src_field_idx]++;
1191 }
1192 }
1193 }
1194
1195 free(pos_buffer);
1196
1197 Xt_redist * redists;
1198 MPI_Comm split_comm;
1199
1200 // only processes that have to sent/receive data are included in the redist,
1201 // the others receive a dummy redist
1202 if (total_num_msg > 0) {
1203
1204 // generate MPI communicator containing all ranks taking part in the
1205 // exchange
1206 yac_mpi_call(MPI_Comm_split(comm, 1, 0, &split_comm), comm);
1207
1208 int * rank_buffer =
1209 xmalloc(2 * total_num_msg * sizeof(*rank_buffer));
1210 int * orig_ranks = rank_buffer;
1211 int * split_ranks = rank_buffer + total_num_msg;
1212
1213 for (size_t i = 0; i < total_num_msg; ++i)
1214 orig_ranks[i] = msgs_buffer[i].rank;
1215
1216 MPI_Group orig_group, split_group;
1217 yac_mpi_call(MPI_Comm_group(comm, &orig_group), comm);
1218 yac_mpi_call(MPI_Comm_group(split_comm, &split_group), comm);
1219
1220 // translate the ranks in the sent/receive messages to ones in the
1221 // split comm
1223 MPI_Group_translate_ranks(orig_group, total_num_msg, orig_ranks,
1224 split_group, split_ranks), split_comm);
1225
1226 for (size_t i = 0; i < total_num_msg; ++i)
1227 msgs_buffer[i].rank = split_ranks[i];
1228
1229 free(rank_buffer);
1230
1231 yac_mpi_call(MPI_Group_free(&split_group), comm);
1232 yac_mpi_call(MPI_Group_free(&orig_group), comm);
1233
1234 // generate redists
1235 redists = xmalloc(num_src_fields * sizeof(*redists));
1236 for (size_t src_field_idx = 0; src_field_idx < num_src_fields;
1237 ++src_field_idx) {
1238 redists[src_field_idx] =
1239 xt_redist_single_array_base_custom_new(
1240 nsends[src_field_idx], nrecvs[src_field_idx],
1241 send_msgs, recv_msgs, split_comm, redist_config);
1242 send_msgs += nsends[src_field_idx];
1243 recv_msgs += nrecvs[src_field_idx];
1244 }
1245
1246 } else {
1247 yac_mpi_call(MPI_Comm_split(comm, 0, 0, &split_comm), comm);
1248 redists = NULL;
1249 }
1250
1251 yac_mpi_call(MPI_Comm_free(&split_comm), comm);
1252 xt_redist_msg_free(msgs_buffer, total_num_msg, comm);
1253
1254 return redists;
1255}
1256
1257static MPI_Datatype get_direct_stencil_mpi_datatype(MPI_Comm comm) {
1258
1259 struct interp_weight_stencil_direct dummy = {0};
1260 MPI_Datatype direct_stencil_dt;
1261 enum {NUM_MEMBERS = 2};
1262 int array_of_blocklengths[NUM_MEMBERS] = {1, 1};
1263 MPI_Aint array_of_displacements[NUM_MEMBERS];
1264 {
1265 MPI_Aint base_addr;
1266 yac_mpi_call(MPI_Get_address(&dummy, &base_addr), comm);
1268 MPI_Get_address(
1269 &(dummy.src), &array_of_displacements[0]), comm);
1270 array_of_displacements[0] -= base_addr;
1272 MPI_Get_address(
1273 &(dummy.orig_pos), &array_of_displacements[1]), comm);
1274 array_of_displacements[1] -= base_addr;
1275 }
1276 MPI_Datatype array_of_types[NUM_MEMBERS] =
1279 MPI_Type_create_struct(
1280 NUM_MEMBERS, array_of_blocklengths, array_of_displacements,
1281 array_of_types, &direct_stencil_dt), comm);
1282 yac_mpi_call(MPI_Type_free(&(array_of_types[0])), comm);
1283 return yac_create_resized(direct_stencil_dt, sizeof(dummy), comm);
1284}
1285
1286static int compare_stencils_direct(const void * a, const void * b) {
1287
1288 int ret = ((struct interp_weight_stencil_direct *)a)->src.rank -
1289 ((struct interp_weight_stencil_direct *)b)->src.rank;
1290
1291 if (ret) return ret;
1292
1293 return (((struct interp_weight_stencil_direct *)a)->orig_pos >
1294 ((struct interp_weight_stencil_direct *)b)->orig_pos) -
1295 (((struct interp_weight_stencil_direct *)a)->orig_pos <
1296 ((struct interp_weight_stencil_direct *)b)->orig_pos);
1297}
1298
1300 void * interp, size_t * src_orig_poses, size_t * sendcounts,
1301 struct interp_weight_stencil_direct * tgt_stencils,
1302 size_t * recvcounts, MPI_Comm comm, Xt_config redist_config) {
1303
1304 // generate redist
1305 Xt_redist redist =
1307 src_orig_poses, sendcounts, tgt_stencils, recvcounts,
1308 comm, redist_config);
1309
1310 yac_interpolation_add_direct((struct yac_interpolation*)interp, redist);
1311
1312 if (redist != NULL) xt_redist_delete(redist);
1313}
1314
1316 MPI_Comm comm, size_t count,
1317 struct interp_weight_stencil * direct_stencils,
1318 void * interp,
1319 void (*interp_add_direct)(
1320 void *, size_t *, size_t *, struct interp_weight_stencil_direct *,
1321 size_t *, MPI_Comm, Xt_config), Xt_config redist_config,
1322 int * rank_is_source, int * rank_is_target) {
1323
1324 char const * routine = "yac_interp_weights_redist_direct";
1325
1326 //---------------------------------------------------------------------------
1327 // redistribute direct stencils to owners of direct target points
1328 // (a target point can be owned by multiple processes)
1329 //---------------------------------------------------------------------------
1330
1331 int comm_size;
1332 yac_mpi_call(MPI_Comm_size(comm, &comm_size), comm);
1333
1334 size_t * sendcounts, * recvcounts, * sdispls, *rdispls;
1336 1, &sendcounts, &recvcounts, &sdispls, &rdispls, comm);
1337
1338 // count the number of direct stencils that need to be sent to each process
1339 for (size_t i = 0; i < count; ++i) {
1340 int curr_count = direct_stencils[i].tgt.data.count;
1341 struct remote_point_info * curr_point_info =
1342 (curr_count == 1)?
1343 (&(direct_stencils[i].tgt.data.data.single)):
1344 (direct_stencils[i].tgt.data.data.multi);
1345 for (int j = 0; j < curr_count; ++j)
1346 sendcounts[curr_point_info[j].rank]++;
1347 }
1348
1349 // if a process is not a target, but there are stencils available for it,
1350 // ignore them
1351 for (int i = 0; i < comm_size; ++i)
1352 if (!rank_is_target[i]) sendcounts[i] = 0;
1353
1355 1, sendcounts, recvcounts, sdispls, rdispls, comm);
1356
1357 size_t send_buffer_size =
1358 sdispls[comm_size] + sendcounts[comm_size - 1];
1359 size_t recv_buffer_size =
1360 rdispls[comm_size - 1] + recvcounts[comm_size - 1];
1361 size_t tgt_count = recv_buffer_size;
1362
1363 struct interp_weight_stencil_direct * stencil_buffer =
1364 xmalloc((send_buffer_size + recv_buffer_size) * sizeof(*stencil_buffer));
1365 struct interp_weight_stencil_direct * send_stencil_buffer =
1366 stencil_buffer + recv_buffer_size;
1367 struct interp_weight_stencil_direct * recv_stencil_buffer = stencil_buffer;
1368
1369 // pack direct stencils
1370 for (size_t i = 0; i < count; ++i) {
1371 int curr_count = direct_stencils[i].tgt.data.count;
1372 struct remote_point_info * curr_point_infos =
1373 (curr_count == 1)?
1374 (&(direct_stencils[i].tgt.data.data.single)):
1375 (direct_stencils[i].tgt.data.data.multi);
1376 struct remote_point_info src =
1377 select_src(
1378 routine, direct_stencils[i].data.direct.src.data, rank_is_source);
1379 for (int j = 0; j < curr_count; ++j) {
1380 int tgt_rank = curr_point_infos[j].rank;
1381 if (rank_is_target[tgt_rank]) {
1382 size_t pos = sdispls[tgt_rank + 1]++;
1383 send_stencil_buffer[pos].src = src;
1384 send_stencil_buffer[pos].orig_pos = curr_point_infos[j].orig_pos;
1385 }
1386 }
1387 }
1388
1389 // create MPI Datatype for exchanging direct stencils
1390 MPI_Datatype stencil_direct_dt = get_direct_stencil_mpi_datatype(comm);
1391
1392 // redistribute stencils based on target owners
1394 send_stencil_buffer, sendcounts, sdispls,
1395 recv_stencil_buffer, recvcounts, rdispls,
1396 sizeof(*stencil_buffer), stencil_direct_dt, comm,
1397 routine, __LINE__);
1398
1399 yac_mpi_call(MPI_Type_free(&stencil_direct_dt), comm);
1400
1401 // sort stencils based on src rank first and by target orig pos second
1402 qsort(recv_stencil_buffer, tgt_count, sizeof(*recv_stencil_buffer),
1404
1405 //---------------------------------------------------------------------------
1406 // inform source processes about their requested points
1407 //---------------------------------------------------------------------------
1408
1409 memset(sendcounts, 0, (size_t)comm_size * sizeof(*sendcounts));
1410
1411 for (size_t i = 0; i < tgt_count; ++i)
1412 sendcounts[recv_stencil_buffer[i].src.rank]++;
1413
1415 1, sendcounts, recvcounts, sdispls, rdispls, comm);
1416
1417 send_buffer_size = sdispls[comm_size] + sendcounts[comm_size - 1];
1418 recv_buffer_size = rdispls[comm_size - 1] + recvcounts[comm_size - 1];
1419
1420 size_t * orig_pos_buffer =
1421 xmalloc((send_buffer_size + recv_buffer_size) * sizeof(*orig_pos_buffer));
1422 size_t * send_orig_pos_buffer = orig_pos_buffer + recv_buffer_size;
1423 size_t * recv_orig_pos_buffer = orig_pos_buffer;
1424
1425 for (size_t i = 0; i < tgt_count; ++i)
1426 send_orig_pos_buffer[sdispls[recv_stencil_buffer[i].src.rank + 1]++] =
1427 recv_stencil_buffer[i].src.orig_pos;
1428
1430 send_orig_pos_buffer, sendcounts, sdispls,
1431 recv_orig_pos_buffer, recvcounts, rdispls,
1432 sizeof(*send_orig_pos_buffer), YAC_MPI_SIZE_T, comm,
1433 routine, __LINE__);
1434
1435 //---------------------------------------------------------------------------
1436 // store received stencils in interp data structure
1437 //---------------------------------------------------------------------------
1438
1440 interp, recv_orig_pos_buffer, recvcounts, recv_stencil_buffer, sendcounts,
1441 comm, redist_config);
1442
1443 yac_free_comm_buffers(sendcounts, recvcounts, sdispls, rdispls);
1444 free(orig_pos_buffer);
1445 free(stencil_buffer);
1446}
1447
1448static MPI_Datatype get_direct_mf_stencil_mpi_datatype(MPI_Comm comm) {
1449
1450 struct interp_weight_stencil_direct_mf dummy = {0};
1451 MPI_Datatype direct_stencil_mf_dt;
1452 enum {NUM_MEMBERS = 3};
1453 int array_of_blocklengths[NUM_MEMBERS] = {1, 1, 1};
1454 MPI_Aint array_of_displacements[NUM_MEMBERS];
1455 {
1456 MPI_Aint base_addr;
1457 yac_mpi_call(MPI_Get_address(&dummy, &base_addr), comm);
1459 MPI_Get_address(
1460 &(dummy.src), &array_of_displacements[0]), comm);
1461 array_of_displacements[0] -= base_addr;
1463 MPI_Get_address(
1464 &(dummy.src_field_idx), &array_of_displacements[1]), comm);
1465 array_of_displacements[1] -= base_addr;
1467 MPI_Get_address(
1468 &(dummy.orig_pos), &array_of_displacements[2]), comm);
1469 array_of_displacements[2] -= base_addr;
1470 }
1471 MPI_Datatype array_of_types[NUM_MEMBERS] =
1475 MPI_Type_create_struct(
1476 NUM_MEMBERS, array_of_blocklengths, array_of_displacements,
1477 array_of_types, &direct_stencil_mf_dt), comm);
1478 yac_mpi_call(MPI_Type_free(&(array_of_types[0])), comm);
1479 return yac_create_resized(direct_stencil_mf_dt, sizeof(dummy), comm);
1480}
1481
1482static int compare_stencils_direct_mf(const void * a, const void * b) {
1483
1484 int ret = ((struct interp_weight_stencil_direct_mf *)a)->src.rank -
1485 ((struct interp_weight_stencil_direct_mf *)b)->src.rank;
1486
1487 if (ret) return ret;
1488
1489 ret = (((struct interp_weight_stencil_direct_mf *)a)->src_field_idx >
1490 ((struct interp_weight_stencil_direct_mf *)b)->src_field_idx) -
1493
1494 if (ret) return ret;
1495
1496 return (((struct interp_weight_stencil_direct_mf *)a)->orig_pos >
1498 (((struct interp_weight_stencil_direct_mf *)a)->orig_pos <
1499 ((struct interp_weight_stencil_direct_mf *)b)->orig_pos);
1500}
1501
1503 void * interp, size_t num_src_fields, size_t * src_orig_poses,
1504 size_t * sendcounts, struct interp_weight_stencil_direct_mf * tgt_stencils,
1505 size_t * recvcounts, MPI_Comm comm, Xt_config redist_config) {
1506
1507 // generate redist
1508 Xt_redist * redists =
1510 src_orig_poses, sendcounts, tgt_stencils, recvcounts,
1511 (size_t)num_src_fields, comm, redist_config);
1512
1514 (struct yac_interpolation*)interp, redists, (size_t)num_src_fields);
1515
1516 if (redists != NULL) {
1517 for (size_t i = 0; i < (size_t)num_src_fields; ++i)
1518 xt_redist_delete(redists[i]);
1519 free(redists);
1520 }
1521}
1522
1524 struct yac_src_field_exchange_data * src_field_exchange_data) {
1525
1526 src_field_exchange_data->send.msg = NULL;
1527 src_field_exchange_data->send.num_msg = 0;
1528 src_field_exchange_data->recv.msg = NULL;
1529 src_field_exchange_data->recv.num_msg = 0;
1530}
1531
1532// routine ensures that interp_raw can handle up to num_src_fields source fields
1534 struct yac_interpolation_raw * interp_raw, size_t num_src_fields) {
1535
1536 if (interp_raw->interp_weights_data.num_src_fields < num_src_fields) {
1537
1538 interp_raw->src_field_exchange_data =
1539 xrealloc(
1540 interp_raw->src_field_exchange_data,
1541 num_src_fields * sizeof(*interp_raw->src_field_exchange_data));
1543 xrealloc(
1545 num_src_fields *
1546 sizeof(*interp_raw->interp_weights_data.src_field_buffer_size));
1547
1548 for (size_t i = interp_raw->interp_weights_data.num_src_fields;
1549 i < num_src_fields; ++i) {
1551 interp_raw->interp_weights_data.src_field_buffer_size[i] = 0;
1552 }
1553 interp_raw->interp_weights_data.num_src_fields = num_src_fields;
1554 }
1555}
1556
1578 size_t num_src_fields, size_t tgt_count, size_t * tgt_idx,
1579 size_t * num_src_per_tgt, double * weights, size_t * src_field_idx,
1580 size_t * src_idx, size_t * src_field_buffer_size) {
1581
1582 // compute total number of weights
1583 size_t num_weights = 0;
1584 if (num_src_per_tgt) {
1585 for (size_t i = 0; i < tgt_count; ++i) num_weights += num_src_per_tgt[i];
1586 } else {
1587 num_weights = tgt_count;
1588 }
1589
1590 // compute number of weights already stored in interp_weights_data
1591 size_t weights_offset = 0;
1592 for (size_t i = 0; i < interp_weights_data->num_wgt_tgt; ++i)
1593 weights_offset += interp_weights_data->num_src_per_tgt[i];
1594
1595 // add local target indices to interp_weights_data
1597 xrealloc(
1599 (interp_weights_data->num_wgt_tgt + tgt_count) *
1600 sizeof(*(interp_weights_data->wgt_tgt_idx)));
1601 memcpy(
1603 tgt_idx, tgt_count * sizeof(*tgt_idx));
1604
1605 // add number of source points per target point to interp_weights_data
1607 xrealloc(
1609 (interp_weights_data->num_wgt_tgt + tgt_count) *
1611 if (num_src_per_tgt) {
1612 memcpy(
1614 num_src_per_tgt, tgt_count * sizeof(*num_src_per_tgt));
1615 } else {
1616 for (size_t i = 0, j = interp_weights_data->num_wgt_tgt; i < tgt_count;
1617 ++i, ++j)
1619 }
1620
1621 // add weights to interp_weights_data
1623 xrealloc(
1624 interp_weights_data->weights, (weights_offset + num_weights) *
1625 sizeof(*(interp_weights_data->weights)));
1626 if (weights) {
1627 memcpy(
1628 interp_weights_data->weights + weights_offset,
1629 weights, num_weights * sizeof(*weights));
1630 } else {
1631 for (size_t i = 0, j = weights_offset; i < num_weights; ++i, ++j)
1632 interp_weights_data->weights[j] = 1.0;
1633 }
1634
1635 // add source field indices to interp_weights_data
1637 xrealloc(
1638 interp_weights_data->src_field_idx, (weights_offset + num_weights) *
1640 if (src_field_idx) {
1641 memcpy(
1642 interp_weights_data->src_field_idx + weights_offset,
1643 src_field_idx, num_weights * sizeof(*src_field_idx));
1644 } else {
1645 for (size_t i = 0, j = weights_offset; i < num_weights;
1646 ++i, ++j)
1648 // in case no source field indices were provided, we reference the ones in
1649 // interp_weights_data
1651 }
1652
1653 // add source indices to interp_weights_data
1654 // (since interp_weights_data may already contains source indices, we have to
1655 // offset the ones added here by the number of source indices already in
1656 // interp_weights_data)
1658 xrealloc(
1659 interp_weights_data->src_idx, (weights_offset + num_weights) *
1660 sizeof(*(interp_weights_data->src_idx)));
1661 for (size_t i = 0, j = weights_offset; i < num_weights; ++i, ++j)
1663 src_idx[i] + interp_weights_data->src_field_buffer_size[src_field_idx[i]];
1664
1665 // update src_field_buffer_size in interp_weights_data
1666 for (size_t i = 0; i < num_src_fields; ++i)
1667 interp_weights_data->src_field_buffer_size[i] += src_field_buffer_size[i];
1668
1669 // update number of weighted target points
1670 interp_weights_data->num_wgt_tgt += tgt_count;
1671}
1672
1673static struct yac_src_field_exchange_data_msg *
1675 struct yac_src_field_exchange_data_msgs * msgs, int rank) {
1676
1677 // search for a matching message
1678 size_t msg_idx = 0;
1679 for (; msg_idx < msgs->num_msg; ++msg_idx)
1680 if (msgs->msg[msg_idx].rank == rank) break;
1681
1682 // allocate entry, if non for the current rank exists
1683 if (msg_idx == msgs->num_msg) {
1684 msgs->num_msg++;
1685 msgs->msg = xrealloc(msgs->msg, msgs->num_msg * sizeof(*msgs->msg));
1686 msgs->msg[msg_idx] =
1687 (struct yac_src_field_exchange_data_msg)
1688 {.rank = rank, .pos = NULL, .count = 0};
1689 }
1690
1691 return msgs->msg + msg_idx;
1692}
1693
1704 struct yac_src_field_exchange_data_msgs * msgs,
1705 int rank, size_t count, size_t * pos, size_t offset) {
1706
1707 // search for a message matching the rank (create empty message if it does
1708 // not yet exist
1709 struct yac_src_field_exchange_data_msg * msg =
1711
1712 // add positions
1713 msg->pos =
1714 xrealloc(msg->pos, ((size_t)msg->count + count) * sizeof(*msg->pos));
1715 for (size_t i = 0; i < count; ++i, ++msg->count)
1716 msg->pos[msg->count] = pos[i] + offset;
1717}
1718
1738 struct yac_src_field_exchange_data * src_field_exchange_data,
1739 size_t num_src_fields, MPI_Comm comm,
1740 size_t * send_msg_sizes, size_t * send_pos,
1741 size_t * recv_msg_sizes, size_t * recv_pos,
1742 size_t * recv_offsets) {
1743
1744 int comm_size;
1745 yac_mpi_call(MPI_Comm_size(comm, &comm_size), comm);
1746
1747 size_t msg_idx = 0;
1748 for (int rank = 0; rank < comm_size; ++rank) {
1749
1750 for (size_t src_field_idx = 0; src_field_idx < num_src_fields;
1751 ++src_field_idx, ++msg_idx) {
1752
1753 struct yac_src_field_exchange_data * curr_src_field_exchange_data =
1754 src_field_exchange_data + src_field_idx;
1755
1756 // if data has to be sent to the current rank
1757 size_t send_msg_size = send_msg_sizes[msg_idx];
1758 if (send_msg_sizes[msg_idx] > 0) {
1759
1761 &curr_src_field_exchange_data->send, rank, send_msg_size,
1762 send_pos, 0);
1763 send_pos += send_msg_size;
1764 }
1765
1766 // if data has to be received from the current rank
1767 size_t recv_msg_size = recv_msg_sizes[msg_idx];
1768 if (recv_msg_size > 0) {
1769
1771 &curr_src_field_exchange_data->recv, rank, recv_msg_size,
1772 recv_pos, recv_offsets[src_field_idx]);
1773 recv_pos += recv_msg_size;
1774 }
1775 }
1776 }
1777}
1778
1780 void * interp, size_t * src_orig_poses, size_t * sendcounts,
1781 struct interp_weight_stencil_direct * tgt_stencils,
1782 size_t * recvcounts, MPI_Comm comm, Xt_config redist_config) {
1783
1784 UNUSED(redist_config);
1785
1786 struct yac_interpolation_raw * interp_raw =
1787 (struct yac_interpolation_raw *)interp;
1788
1789 int comm_size;
1790 yac_mpi_call(MPI_Comm_size(comm, &comm_size), comm);
1791
1792 size_t num_src_fields = 1;
1793 yac_src_field_exchange_data_realloc(interp_raw, num_src_fields);
1794
1795 size_t total_sendcounts = 0, total_recvcounts = 0;
1796 for (int i = 0; i < comm_size; ++i) {
1797 total_sendcounts += sendcounts[i];
1798 total_recvcounts += recvcounts[i];
1799 }
1800
1801 size_t * size_t_buffer =
1802 xmalloc(
1803 (MAX(total_sendcounts, total_recvcounts) + total_recvcounts) *
1804 sizeof(*size_t_buffer));
1805 size_t * send_pos = size_t_buffer;
1806 size_t * recv_pos = size_t_buffer + total_sendcounts;
1807
1808 for (size_t i = 0; i < total_sendcounts; ++i)
1809 send_pos[i] = (size_t)src_orig_poses[i];
1810 for (size_t i = 0; i < total_recvcounts; ++i)
1811 recv_pos[i] = i;
1812
1813 // store source field data that needs to be exchanged
1815 interp_raw->src_field_exchange_data, num_src_fields, comm,
1816 sendcounts, send_pos, recvcounts, recv_pos,
1818
1819 size_t * tgt_idx = size_t_buffer;
1820 size_t * src_idx = size_t_buffer + total_recvcounts;
1821
1822 for (size_t i = 0; i < total_recvcounts; ++i) {
1823 tgt_idx[i] = (size_t)(tgt_stencils[i].orig_pos);
1824 src_idx[i] = i;
1825 }
1826
1827 // store mapping formation between source points in the source field buffer
1828 // to the target points
1829 size_t * num_src_per_tgt = NULL;
1830 double * weights = NULL;
1831 size_t * src_field_idx = NULL;
1832 size_t src_field_buffer_size = total_recvcounts;
1834 &(interp_raw->interp_weights_data), num_src_fields, total_recvcounts,
1835 tgt_idx, num_src_per_tgt, weights, src_field_idx, src_idx,
1836 &src_field_buffer_size);
1837
1838 free(size_t_buffer);
1839}
1840
1842 void * interp, size_t num_src_fields, size_t * src_orig_poses,
1843 size_t * sendcounts, struct interp_weight_stencil_direct_mf * tgt_stencils,
1844 size_t * recvcounts, MPI_Comm comm, Xt_config redist_config) {
1845
1846 UNUSED(redist_config);
1847
1848 struct yac_interpolation_raw * interp_raw =
1849 (struct yac_interpolation_raw *)interp;
1850
1851 int comm_size;
1852 yac_mpi_call(MPI_Comm_size(comm, &comm_size), comm);
1853
1854 yac_src_field_exchange_data_realloc(interp_raw, num_src_fields);
1855
1856 size_t total_sendcounts = 0, total_recvcounts = 0;
1857 for (size_t rank = 0, idx = 0; rank < (size_t)comm_size; ++rank) {
1858 for (size_t src_field_idx = 0; src_field_idx < num_src_fields;
1859 ++src_field_idx, ++idx) {
1860 total_sendcounts += sendcounts[idx];
1861 total_recvcounts += recvcounts[idx];
1862 }
1863 }
1864
1865 size_t * size_t_buffer =
1866 xmalloc(
1867 (MAX(total_sendcounts, total_recvcounts) + 2 * total_recvcounts) *
1868 sizeof(*size_t_buffer));
1869 size_t * send_pos = size_t_buffer;
1870 size_t * recv_pos = size_t_buffer + total_sendcounts;
1871 size_t src_field_buffer_size[num_src_fields]; // number of source points to
1872 // be received per source field
1873 memset(
1874 src_field_buffer_size, 0,
1875 num_src_fields * sizeof(src_field_buffer_size[0]));
1876
1877 for (size_t i = 0; i < total_sendcounts; ++i)
1878 send_pos[i] = (size_t)src_orig_poses[i];
1879 for (size_t rank = 0, idx = 0, recv_pos_idx = 0; rank < (size_t)comm_size;
1880 ++rank) {
1881 for (size_t src_field_idx = 0; src_field_idx < num_src_fields;
1882 ++src_field_idx, ++idx) {
1883 if (recvcounts[idx] > 0) {
1884 for (size_t i = 0; i < recvcounts[idx]; ++i, ++recv_pos_idx)
1885 recv_pos[recv_pos_idx] = src_field_buffer_size[src_field_idx]++;
1886 }
1887 }
1888 }
1889
1890 // store source field data that needs to be exchanged
1892 interp_raw->src_field_exchange_data, num_src_fields, comm,
1893 sendcounts, send_pos, recvcounts, recv_pos,
1895
1896 size_t * tgt_idx = size_t_buffer;
1897 size_t * src_idx = size_t_buffer + total_recvcounts;
1898 size_t * src_field_idx = size_t_buffer + 2 * total_recvcounts;
1899 memset(
1900 src_field_buffer_size, 0,
1901 num_src_fields * sizeof(src_field_buffer_size[0]));
1902
1903 for (size_t rank = 0, idx = 0, k = 0; rank < (size_t)comm_size; ++rank) {
1904 for (size_t j = 0; j < num_src_fields; ++j, ++idx) {
1905
1906 if (recvcounts[idx] > 0) {
1907 for (size_t i = 0; i < recvcounts[idx]; ++i, ++k) {
1908 tgt_idx[k] = (size_t)(tgt_stencils[k].orig_pos);
1909 src_idx[k] = src_field_buffer_size[j]++;
1910 src_field_idx[k] = j;
1911 }
1912 }
1913 }
1914 }
1915
1916 // store mapping formation between source points in the source fields buffer
1917 // to the target points
1918 size_t * num_src_per_tgt = NULL;
1919 double * weights = NULL;
1921 &(interp_raw->interp_weights_data), num_src_fields, total_recvcounts,
1922 tgt_idx, num_src_per_tgt, weights, src_field_idx, src_idx,
1923 src_field_buffer_size);
1924
1925 free(size_t_buffer);
1926}
1927
1929 MPI_Comm comm, size_t count,
1930 struct interp_weight_stencil * direct_mf_stencils,
1931 void * interp,
1932 void (*interp_add_direct_mf)(
1933 void *, size_t, size_t *, size_t *,
1934 struct interp_weight_stencil_direct_mf *, size_t *, MPI_Comm, Xt_config),
1935 Xt_config redist_config, int * rank_is_source, int * rank_is_target) {
1936
1937 char const * routine = "yac_interp_weights_redist_direct_mf";
1938
1939 //---------------------------------------------------------------------------
1940 // redistribute multi field direct stencils to owners of direct target points
1941 // (a target point can be owned by multiple processes)
1942 //---------------------------------------------------------------------------
1943
1944 // determine the number of source fields
1945 size_t num_src_fields = 0;
1946 for (size_t i = 0; i < count; ++i) {
1947 size_t src_field_idx = direct_mf_stencils[i].data.direct_mf.field_idx;
1948 if (src_field_idx >= num_src_fields) num_src_fields = src_field_idx + 1;
1949 }
1951 MPI_Allreduce(
1952 MPI_IN_PLACE, &num_src_fields, 1, YAC_MPI_SIZE_T, MPI_MAX, comm), comm);
1953
1954 int comm_size;
1955 yac_mpi_call(MPI_Comm_size(comm, &comm_size), comm);
1956
1957 size_t * sendcounts, * recvcounts, * sdispls, *rdispls;
1959 num_src_fields, &sendcounts, &recvcounts, &sdispls, &rdispls, comm);
1960 size_t * size_t_buffer =
1961 xmalloc(4 * (size_t)comm_size * sizeof(*size_t_buffer));
1962 size_t * total_sendcounts = size_t_buffer + 0 * comm_size;
1963 size_t * total_recvcounts = size_t_buffer + 1 * comm_size;
1964 size_t * total_sdispls = size_t_buffer + 2 * comm_size;
1965 size_t * total_rdispls = size_t_buffer + 3 * comm_size;
1966
1967 // count the number of multi field direct stencils that need to be sent to
1968 // each process
1969 for (size_t i = 0; i < count; ++i) {
1970 int curr_count = direct_mf_stencils[i].tgt.data.count;
1971 struct remote_point_info * curr_point_info =
1972 (curr_count == 1)?
1973 (&(direct_mf_stencils[i].tgt.data.data.single)):
1974 (direct_mf_stencils[i].tgt.data.data.multi);
1975 size_t src_field_idx = direct_mf_stencils[i].data.direct_mf.field_idx;
1976 for (int j = 0; j < curr_count; ++j)
1977 sendcounts[
1978 (size_t)(curr_point_info[j].rank) * num_src_fields + src_field_idx]++;
1979 }
1980
1981
1982 // if a process is not a target, but there are stencils available for it,
1983 // ignore them
1984 for (int i = 0; i < comm_size; ++i) {
1985 if (!rank_is_target[i]) {
1986 for (size_t j = 0; j < num_src_fields; ++j)
1987 sendcounts[(size_t)i * num_src_fields + j] = 0;
1988 }
1989 }
1990
1992 (size_t)num_src_fields, sendcounts, recvcounts, sdispls, rdispls, comm);
1993
1994 size_t saccu = 0, raccu = 0;
1995 for (int i = 0; i < comm_size; ++i) {
1996 total_sdispls[i] = saccu;
1997 total_rdispls[i] = raccu;
1998 total_sendcounts[i] = 0;
1999 total_recvcounts[i] = 0;
2000 for (size_t j = 0; j < num_src_fields; ++j) {
2001 total_sendcounts[i] += sendcounts[num_src_fields * i + j];
2002 total_recvcounts[i] += recvcounts[num_src_fields * i + j];
2003 }
2004 saccu += total_sendcounts[i];
2005 raccu += total_recvcounts[i];
2006 }
2007
2008 size_t send_buffer_size = total_sdispls[comm_size - 1] +
2009 total_sendcounts[comm_size - 1];
2010 size_t recv_buffer_size = total_rdispls[comm_size - 1] +
2011 total_recvcounts[comm_size - 1];
2012 size_t tgt_count = recv_buffer_size;
2013
2014 struct interp_weight_stencil_direct_mf * stencil_buffer =
2015 xmalloc((send_buffer_size + recv_buffer_size) * sizeof(*stencil_buffer));
2016 struct interp_weight_stencil_direct_mf * send_stencil_buffer =
2017 stencil_buffer + recv_buffer_size;
2018 struct interp_weight_stencil_direct_mf * recv_stencil_buffer = stencil_buffer;
2019
2020 // pack direct_mf stencils
2021 for (size_t i = 0; i < count; ++i) {
2022 int curr_count = direct_mf_stencils[i].tgt.data.count;
2023 struct remote_point_info * curr_point_infos =
2024 (curr_count == 1)?
2025 (&(direct_mf_stencils[i].tgt.data.data.single)):
2026 (direct_mf_stencils[i].tgt.data.data.multi);
2027 struct remote_point_info src =
2028 select_src(
2029 routine, direct_mf_stencils[i].data.direct_mf.src.data,
2030 rank_is_source);
2031 size_t src_field_idx = direct_mf_stencils[i].data.direct_mf.field_idx;
2032 for (int j = 0; j < curr_count; ++j) {
2033 int tgt_rank = curr_point_infos[j].rank;
2034 if (rank_is_target[tgt_rank]) {
2035 size_t pos =
2036 sdispls[(size_t)tgt_rank * num_src_fields +
2037 src_field_idx + 1]++;
2038 send_stencil_buffer[pos].src = src;
2039 send_stencil_buffer[pos].src_field_idx = src_field_idx;
2040 send_stencil_buffer[pos].orig_pos = curr_point_infos[j].orig_pos;
2041 }
2042 }
2043 }
2044
2045 // create MPI Datatype for exchanging direct_mf stencils
2046 MPI_Datatype stencil_direct_mf_dt = get_direct_mf_stencil_mpi_datatype(comm);
2047
2048 // redistribute stencils based on target owners
2050 send_stencil_buffer, total_sendcounts, total_sdispls,
2051 recv_stencil_buffer, total_recvcounts, total_rdispls,
2052 sizeof(*stencil_buffer), stencil_direct_mf_dt, comm,
2053 "yac_interp_weights_redist_direct_mf", __LINE__);
2054
2055 yac_mpi_call(MPI_Type_free(&stencil_direct_mf_dt), comm);
2056
2057 // sort stencils based on src rank first, src_field_idx, and
2058 // by target orig pos second
2059 qsort(recv_stencil_buffer, tgt_count, sizeof(*recv_stencil_buffer),
2061
2062 //---------------------------------------------------------------------------
2063 // inform source processes about their requested points
2064 //---------------------------------------------------------------------------
2065
2066 memset(sendcounts, 0,
2067 (size_t)comm_size * (size_t)num_src_fields * sizeof(*sendcounts));
2068
2069 for (size_t i = 0; i < tgt_count; ++i)
2070 sendcounts[(size_t)(recv_stencil_buffer[i].src.rank) * num_src_fields +
2071 recv_stencil_buffer[i].src_field_idx]++;
2072
2074 (size_t)num_src_fields, sendcounts, recvcounts, sdispls, rdispls, comm);
2075
2076 saccu = 0, raccu = 0;
2077 for (int i = 0; i < comm_size; ++i) {
2078 total_sdispls[i] = saccu;
2079 total_rdispls[i] = raccu;
2080 total_sendcounts[i] = 0;
2081 total_recvcounts[i] = 0;
2082 for (size_t j = 0; j < num_src_fields; ++j) {
2083 total_sendcounts[i] += sendcounts[num_src_fields * i + j];
2084 total_recvcounts[i] += recvcounts[num_src_fields * i + j];
2085 }
2086 saccu += total_sendcounts[i];
2087 raccu += total_recvcounts[i];
2088 }
2089
2090 send_buffer_size = total_sdispls[comm_size - 1] +
2091 total_sendcounts[comm_size - 1];
2092 recv_buffer_size = total_rdispls[comm_size - 1] +
2093 total_recvcounts[comm_size - 1];
2094
2095 size_t * orig_pos_buffer =
2096 xmalloc((send_buffer_size + recv_buffer_size) * sizeof(*orig_pos_buffer));
2097 size_t * send_orig_pos_buffer = orig_pos_buffer + recv_buffer_size;
2098 size_t * recv_orig_pos_buffer = orig_pos_buffer;
2099
2100 for (size_t i = 0; i < tgt_count; ++i)
2101 send_orig_pos_buffer[
2102 sdispls[(size_t)(recv_stencil_buffer[i].src.rank) * num_src_fields +
2103 recv_stencil_buffer[i].src_field_idx + 1]++] =
2104 recv_stencil_buffer[i].src.orig_pos;
2105
2106 // inform source processes about their requested points
2108 send_orig_pos_buffer, total_sendcounts, total_sdispls,
2109 recv_orig_pos_buffer, total_recvcounts, total_rdispls,
2110 sizeof(*send_orig_pos_buffer), YAC_MPI_SIZE_T, comm,
2111 "yac_interp_weights_redist_direct_mf", __LINE__);
2112 free(size_t_buffer);
2113
2114 //---------------------------------------------------------------------------
2115 // store received stencils in interp data structure
2116 //---------------------------------------------------------------------------
2117
2119 interp, num_src_fields,
2120 recv_orig_pos_buffer, recvcounts, recv_stencil_buffer, sendcounts,
2121 comm, redist_config);
2122
2123 yac_free_comm_buffers(sendcounts, recvcounts, sdispls, rdispls);
2124 free(orig_pos_buffer);
2125 free(stencil_buffer);
2126}
2127
2129 struct interp_weight_stencil * stencil, MPI_Datatype point_info_dt,
2130 MPI_Comm comm) {
2131
2132 UNUSED(stencil);
2133 UNUSED(point_info_dt);
2134
2135 int pack_size_value;
2136
2137 yac_mpi_call(MPI_Pack_size(1, MPI_DOUBLE, comm, &pack_size_value), comm);
2138
2139 return pack_size_value;
2140}
2141
2143 struct interp_weight_stencil * stencil, MPI_Datatype point_info_dt,
2144 MPI_Comm comm) {
2145
2146 return
2148 &(stencil->data.direct.src), point_info_dt, comm);
2149}
2150
2152 struct interp_weight_stencil * stencil, MPI_Datatype point_info_dt,
2153 MPI_Comm comm) {
2154
2155 return
2157 stencil->data.sum.srcs, point_info_dt, comm);
2158}
2159
2161 struct interp_weight_stencil * stencil, MPI_Datatype point_info_dt,
2162 MPI_Comm comm) {
2163
2164 int pack_size_weights;
2166 MPI_Pack_size(
2167 (int)(stencil->data.weight_sum.srcs->count),
2168 MPI_DOUBLE, comm, &pack_size_weights), comm);
2169
2170 return
2172 stencil->data.weight_sum.srcs, point_info_dt, comm) +
2173 pack_size_weights;
2174}
2175
2177 struct interp_weight_stencil * stencil, MPI_Datatype point_info_dt,
2178 MPI_Comm comm) {
2179
2180 int pack_size_src_field_idx;
2182 MPI_Pack_size(
2183 1, YAC_MPI_SIZE_T, comm, &pack_size_src_field_idx), comm);
2184
2185 return
2187 &(stencil->data.direct_mf.src), point_info_dt, comm) +
2188 pack_size_src_field_idx;
2189}
2190
2192 struct interp_weight_stencil * stencil, MPI_Datatype point_info_dt,
2193 MPI_Comm comm) {
2194
2195 int pack_size_weights, pack_size_field_indices;
2196 int count = (int)(stencil->data.weight_sum_mf.srcs->count);
2198 MPI_Pack_size(
2199 count, MPI_DOUBLE, comm, &pack_size_weights), comm);
2201 MPI_Pack_size(
2202 count, YAC_MPI_SIZE_T, comm, &pack_size_field_indices), comm);
2203
2204 return
2206 stencil->data.weight_sum_mf.srcs, point_info_dt, comm) +
2207 pack_size_weights + pack_size_field_indices;
2208}
2209
2211 struct interp_weight_stencil * stencil, MPI_Datatype point_info_dt,
2212 MPI_Comm comm) {
2213
2214 int pack_size_field_indices;
2216 MPI_Pack_size(
2217 (int)(stencil->data.sum_mf.srcs->count),
2218 YAC_MPI_SIZE_T, comm, &pack_size_field_indices), comm);
2219
2220 return
2222 stencil->data.sum_mf.srcs, point_info_dt, comm) +
2223 pack_size_field_indices;
2224}
2225
2227 struct interp_weight_stencil * stencil, struct remote_point point) {
2228
2229 struct interp_weight_stencil stencil_copy = *stencil;
2230 stencil_copy.tgt = copy_remote_point(point);
2231
2232 YAC_ASSERT(
2233 (stencil->type == FIXED) ||
2234 (stencil->type == DIRECT) ||
2235 (stencil->type == SUM) ||
2236 (stencil->type == WEIGHT_SUM) ||
2237 (stencil->type == DIRECT_MF) ||
2238 (stencil->type == SUM_MF) ||
2239 (stencil->type == WEIGHT_SUM_MF), "invalid stencil type")
2240
2241 switch (stencil->type) {
2242 case(FIXED):
2243 // nothing to be done
2244 break;
2245 case(DIRECT):
2246 stencil_copy.data.direct.src =
2247 copy_remote_point(stencil->data.direct.src);
2248 break;
2249 case(SUM):
2250 stencil_copy.data.weight_sum.weights = NULL;
2251 stencil_copy.data.sum.srcs =
2253 stencil->data.sum.srcs->data, stencil->data.sum.srcs->count);
2254 break;
2255 case(WEIGHT_SUM): {
2256 stencil_copy.data.weight_sum.srcs =
2258 stencil->data.weight_sum.srcs->data,
2259 stencil->data.weight_sum.srcs->count);
2260 size_t weight_size =
2261 stencil->data.weight_sum.srcs->count *
2262 sizeof(*(stencil_copy.data.weight_sum.weights));
2263 stencil_copy.data.weight_sum.weights = xmalloc(weight_size);
2264 memcpy(stencil_copy.data.weight_sum.weights,
2265 stencil->data.weight_sum.weights, weight_size);
2266 break;
2267 }
2268 case(DIRECT_MF):
2269 stencil_copy.data.direct_mf.src =
2271 stencil_copy.data.direct_mf.field_idx =
2272 stencil->data.direct_mf.field_idx;
2273 break;
2274 case(SUM_MF): {
2275 stencil_copy.data.sum_mf.srcs =
2277 stencil->data.sum_mf.srcs->data,
2278 stencil->data.sum_mf.srcs->count);
2279 size_t field_indices_size =
2280 stencil->data.sum_mf.srcs->count *
2281 sizeof(*(stencil_copy.data.sum_mf.field_indices));
2282 stencil_copy.data.sum_mf.field_indices = xmalloc(field_indices_size);
2283 memcpy(stencil_copy.data.sum_mf.field_indices,
2284 stencil->data.sum_mf.field_indices, field_indices_size);
2285 break;
2286 }
2287 default:
2288 case(WEIGHT_SUM_MF): {
2289 stencil_copy.data.weight_sum_mf.srcs =
2291 stencil->data.weight_sum_mf.srcs->data,
2292 stencil->data.weight_sum_mf.srcs->count);
2293 size_t weight_size =
2294 stencil->data.weight_sum_mf.srcs->count *
2295 sizeof(*(stencil_copy.data.weight_sum_mf.weights));
2296 stencil_copy.data.weight_sum_mf.weights = xmalloc(weight_size);
2297 memcpy(stencil_copy.data.weight_sum_mf.weights,
2298 stencil->data.weight_sum_mf.weights, weight_size);
2299 size_t field_indices_size =
2300 stencil->data.weight_sum_mf.srcs->count *
2301 sizeof(*(stencil_copy.data.weight_sum_mf.field_indices));
2302 stencil_copy.data.weight_sum_mf.field_indices =
2303 xmalloc(field_indices_size);
2304 memcpy(stencil_copy.data.weight_sum_mf.field_indices,
2305 stencil->data.weight_sum_mf.field_indices, field_indices_size);
2306 break;
2307 }
2308 };
2309 return stencil_copy;
2310}
2311
2313 struct interp_weight_stencil * stencil, struct remote_point point,
2314 double weight) {
2315
2316 if (weight == 1.0) return copy_interp_weight_stencil(stencil, point);
2317
2318 struct remote_point * srcs;
2319 size_t src_count;
2320 double * weights;
2321
2322 YAC_ASSERT(
2323 (stencil->type == FIXED) ||
2324 (stencil->type == DIRECT) ||
2325 (stencil->type == SUM) ||
2326 (stencil->type == WEIGHT_SUM), "invalid stencil type")
2327
2328 switch (stencil->type) {
2329 case (FIXED):
2330 return
2331 (struct interp_weight_stencil) {
2332 .type = FIXED,
2333 .data.fixed.value = stencil->data.fixed.value * weight,
2334 .tgt = copy_remote_point(point)};
2335 case (DIRECT):
2336 src_count = 1;
2337 srcs = &(stencil->data.direct.src);
2338 weights = NULL;
2339 break;
2340 case (SUM):
2341 src_count = stencil->data.sum.srcs->count;
2342 srcs = stencil->data.sum.srcs->data;
2343 weights = NULL;
2344 break;
2345 default:
2346 case (WEIGHT_SUM):
2347 src_count = stencil->data.weight_sum.srcs->count;
2348 srcs = stencil->data.weight_sum.srcs->data;
2349 weights = stencil->data.weight_sum.weights;
2350 break;
2351 };
2352
2353 double * new_weights = xmalloc(src_count * sizeof(*new_weights));
2354 if (weights == NULL)
2355 for (size_t i = 0; i < src_count; ++i) new_weights[i] = weight;
2356 else
2357 for (size_t i = 0; i < src_count; ++i) new_weights[i] = weights[i] * weight;
2358
2359 struct interp_weight_stencil stencil_wcopy;
2360 stencil_wcopy.type = WEIGHT_SUM;
2361 stencil_wcopy.data.weight_sum.srcs = copy_remote_points(srcs, src_count);
2362 stencil_wcopy.data.weight_sum.weights = new_weights;
2363 stencil_wcopy.tgt = copy_remote_point(point);
2364
2365 return stencil_wcopy;
2366}
2367
2368static int compare_w_global_id(const void * a, const void * b) {
2369
2370 int ret = (((struct weighted_global_id *)a)->global_id >
2371 ((struct weighted_global_id *)b)->global_id) -
2372 (((struct weighted_global_id *)a)->global_id <
2373 ((struct weighted_global_id *)b)->global_id);
2374
2375 if (ret) return ret;
2376
2377 return (((struct weighted_global_id *)a)->weight >
2378 ((struct weighted_global_id *)b)->weight) -
2379 (((struct weighted_global_id *)a)->weight <
2380 ((struct weighted_global_id *)b)->weight);
2381}
2382
2383static int compare_remote_point(const void * a, const void * b) {
2384
2385 return ((const struct remote_point*)a)->global_id -
2386 ((const struct remote_point*)b)->global_id;
2387}
2388
2389static void compact_srcs_w(
2390 struct remote_points * srcs, double ** w) {
2391
2392 struct remote_point * data = srcs->data;
2393 size_t count = srcs->count;
2394
2395 struct weighted_global_id * w_global_id =
2396 xmalloc(count * sizeof(*w_global_id));
2397
2398 // extract global ids and weights
2399 for (size_t i = 0; i < count; ++i) {
2400 w_global_id[i].global_id = data[i].global_id;
2401 w_global_id[i].weight = (*w)[i];
2402 }
2403
2404 // sort by global ids and weights
2405 qsort(w_global_id, count, sizeof(*w_global_id), compare_w_global_id);
2406
2407 // sort sources by global ids
2408 qsort(data, count, sizeof(*data), compare_remote_point);
2409
2410 size_t new_count = 0;
2411
2412 // compact sources
2413 for (size_t i = 0; i < count;) {
2414
2415 data[new_count] = data[i];
2416
2417 yac_int curr_global_id = w_global_id[i].global_id;
2418 double curr_weight = w_global_id[i].weight;
2419
2420 ++i;
2421
2422 while((i < count) && (curr_global_id == w_global_id[i].global_id)) {
2423
2424 curr_weight += w_global_id[i].weight;
2425 ++i;
2426 }
2427
2428 (*w)[new_count] = curr_weight;
2429 ++new_count;
2430 }
2431
2432 free(w_global_id);
2433
2434 srcs->data = xrealloc(data, new_count * sizeof(*data));
2435 srcs->count = new_count;
2436 *w = xrealloc(*w, new_count * sizeof(**w));
2437}
2438
2440 struct interp_weight_stencil ** stencils, double * w, size_t num_stencils) {
2441
2442 size_t src_count = 0;
2443 size_t point_info_buffer_size = 0;
2444
2445 for (size_t i = 0; i < num_stencils; ++i) {
2446 size_t curr_src_count;
2447 struct remote_point * srcs;
2448 switch (stencils[i]->type) {
2449 YAC_UNREACHABLE_DEFAULT("invalid stencil type")
2450 case (DIRECT):
2451 curr_src_count = 1;
2452 srcs = &(stencils[i]->data.direct.src);
2453 break;
2454 case (SUM):
2455 curr_src_count = stencils[i]->data.sum.srcs->count;
2456 srcs = stencils[i]->data.sum.srcs->data;
2457 break;
2458 case (WEIGHT_SUM):
2459 curr_src_count = stencils[i]->data.weight_sum.srcs->count;
2460 srcs = stencils[i]->data.weight_sum.srcs->data;
2461 break;
2462 };
2463 src_count += curr_src_count;
2464 for (size_t j = 0, curr_src_data_count; j < curr_src_count; ++j)
2465 if (((curr_src_data_count = srcs[j].data.count)) > 1)
2466 point_info_buffer_size += curr_src_data_count;
2467 }
2468
2469 struct remote_points * srcs =
2470 xmalloc(point_info_buffer_size * sizeof(struct remote_point_info) +
2471 sizeof(*srcs));
2472 srcs->data = xmalloc(src_count * sizeof(*(srcs->data)));
2473 srcs->count = src_count;
2474 struct remote_point_info * point_info_buffer = &(srcs->buffer[0]);
2475 double * new_w = xmalloc(src_count * sizeof(*new_w));
2476
2477 for (size_t i = 0, offset = 0; i < num_stencils; ++i) {
2478 size_t curr_src_count;
2479 struct remote_point * curr_srcs;
2480 double * stencil_w;
2481 switch (stencils[i]->type) {
2482 YAC_UNREACHABLE_DEFAULT("invalid stencil type")
2483 case (DIRECT):
2484 curr_src_count = 1;
2485 curr_srcs = &(stencils[i]->data.direct.src);
2486 stencil_w = NULL;
2487 break;
2488 case (SUM):
2489 curr_src_count = stencils[i]->data.sum.srcs->count;
2490 curr_srcs = stencils[i]->data.sum.srcs->data;
2491 stencil_w = NULL;
2492 break;
2493 case (WEIGHT_SUM):
2494 curr_src_count = stencils[i]->data.weight_sum.srcs->count;
2495 curr_srcs = stencils[i]->data.weight_sum.srcs->data;
2496 stencil_w = stencils[i]->data.weight_sum.weights;
2497 break;
2498 };
2500 srcs->data + offset, curr_srcs, curr_src_count, &point_info_buffer);
2501 if (stencil_w == NULL)
2502 for (size_t j = 0; j < curr_src_count; ++j, ++offset)
2503 new_w[offset] = w[i];
2504 else
2505 for (size_t j = 0; j < curr_src_count; ++j, ++offset)
2506 new_w[offset] = w[i] * stencil_w[j];
2507 }
2508
2509 compact_srcs_w(srcs, &new_w);
2510
2511 struct interp_weight_stencil merge_stencil;
2512 merge_stencil.type = WEIGHT_SUM;
2513 merge_stencil.data.weight_sum.srcs = srcs;
2514 merge_stencil.data.weight_sum.weights = new_w;
2515
2516 return merge_stencil;
2517}
2518
2520 struct interp_weight_stencil ** stencils, double * w, size_t num_stencils) {
2521
2522 for (size_t i = 0; i < num_stencils; ++i)
2523 if (w[i] != 1.0)
2524 return stencils_merge_wsum(stencils, w, num_stencils);
2525
2526 size_t src_count = 0;
2527 size_t point_info_buffer_size = 0;
2528
2529 for (size_t i = 0; i < num_stencils; ++i) {
2530 size_t curr_src_count;
2531 struct remote_point * srcs;
2532
2533 switch (stencils[i]->type) {
2534 YAC_UNREACHABLE_DEFAULT("invalid stencil type")
2535 case (DIRECT):
2536 curr_src_count = 1;
2537 srcs = &(stencils[i]->data.direct.src);
2538 break;
2539 case (SUM):
2540 curr_src_count = stencils[i]->data.sum.srcs->count;
2541 srcs = stencils[i]->data.sum.srcs->data;
2542 break;
2543 };
2544 src_count += curr_src_count;
2545 for (size_t j = 0, curr_src_data_count; j < curr_src_count; ++j)
2546 if (((curr_src_data_count = srcs[j].data.count)) > 1)
2547 point_info_buffer_size += curr_src_data_count;
2548 }
2549
2550 struct remote_points * srcs =
2551 xmalloc(point_info_buffer_size * sizeof(struct remote_point_info) +
2552 sizeof(*srcs));
2553 srcs->data = xmalloc(src_count * sizeof(*(srcs->data)));
2554 srcs->count = src_count;
2555 struct remote_point_info * point_info_buffer = &(srcs->buffer[0]);
2556
2557 for (size_t i = 0, offset = 0; i < num_stencils; ++i) {
2558 size_t curr_src_count;
2559 struct remote_point * curr_srcs;
2560 switch (stencils[i]->type) {
2561 YAC_UNREACHABLE_DEFAULT("invalid stencil type");
2562 case (DIRECT):
2563 curr_src_count = 1;
2564 curr_srcs = &(stencils[i]->data.direct.src);
2565 break;
2566 case (SUM):
2567 curr_src_count = stencils[i]->data.sum.srcs->count;
2568 curr_srcs = stencils[i]->data.sum.srcs->data;
2569 break;
2570 };
2572 srcs->data + offset, curr_srcs, curr_src_count, &point_info_buffer);
2573 offset += curr_src_count;
2574 }
2575
2576 qsort(srcs->data, srcs->count, sizeof(*(srcs->data)), compare_remote_point);
2577
2578 struct interp_weight_stencil merge_stencil;
2579 merge_stencil.type = SUM;
2580 merge_stencil.data.sum.srcs = srcs;
2581
2582 return merge_stencil;
2583}
2584
2586 struct interp_weight_stencil ** stencils, double * w, size_t num_stencils,
2587 struct remote_point point) {
2588
2589 if (num_stencils == 1)
2590 return wcopy_interp_weight_stencil(*stencils, point, *w);
2591
2592 int fixed_count = 0;
2593 int direct_count = 0;
2594 int sum_count = 0;
2595 int wsum_count = 0;
2596 double fixed_value = 0.0;
2597
2598 for (size_t i = 0; i < num_stencils; ++i) {
2599 YAC_ASSERT(
2600 (stencils[i]->type != DIRECT_MF) &&
2601 (stencils[i]->type != SUM_MF) &&
2602 (stencils[i]->type != WEIGHT_SUM_MF),
2603 "multiple source fields not yet supported")
2604 switch (stencils[i]->type) {
2605 YAC_UNREACHABLE_DEFAULT("unsupported stencil type");
2606 case (FIXED):
2607 YAC_ASSERT(
2608 !isnan(stencils[i]->data.fixed.value),
2609 "fixed_value == NaN is not yet supported by this routine "
2610 "(please contact the developers of YAC if you see this message");
2611 fixed_value += stencils[i]->data.fixed.value * w[i];
2612 fixed_count++;
2613 break;
2614 case (DIRECT):
2615 direct_count++;
2616 break;
2617 case (SUM):
2618 sum_count++;
2619 break;
2620 case (WEIGHT_SUM):
2621 wsum_count++;
2622 break;
2623 };
2624 }
2625
2626 struct interp_weight_stencil merge_stencil;
2627
2628 YAC_ASSERT(
2629 (fixed_count > 0) || (wsum_count > 0) ||
2630 (sum_count > 0) || (direct_count > 0), "unknown error")
2631 if (fixed_count > 0) {
2632
2633 YAC_ASSERT(
2634 (direct_count + sum_count + wsum_count) <= 0,
2635 "invalid stencil combination")
2636
2637 merge_stencil = **stencils;
2638 merge_stencil.data.fixed.value = fixed_value;
2639 } else if (wsum_count > 0)
2640 merge_stencil =
2641 stencils_merge_wsum(stencils, w, num_stencils);
2642 else if ((sum_count > 0) || (direct_count > 0))
2643 merge_stencil =
2644 stencils_merge_sum(stencils, w, num_stencils);
2645
2646 merge_stencil.tgt = copy_remote_point(point);
2647
2648 return merge_stencil;
2649}
2650
2652 struct interp_weight_stencil * stencils, size_t count, size_t * pack_order,
2653 int * pack_sizes, MPI_Datatype point_info_dt, MPI_Comm comm) {
2654
2655 int pack_size_type;
2656 yac_mpi_call(MPI_Pack_size(1, MPI_INT, comm, &pack_size_type), comm);
2657
2658 for (size_t i = 0; i < count; ++i) {
2659
2660 struct interp_weight_stencil * curr_stencil = stencils + pack_order[i];
2661 int (*func_pack_size)(
2662 struct interp_weight_stencil * stencil, MPI_Datatype point_info_dt,
2663 MPI_Comm comm);
2664 YAC_ASSERT(
2665 (curr_stencil->type == FIXED) ||
2666 (curr_stencil->type == DIRECT) ||
2667 (curr_stencil->type == SUM) ||
2668 (curr_stencil->type == WEIGHT_SUM) ||
2669 (curr_stencil->type == DIRECT_MF) ||
2670 (curr_stencil->type == SUM_MF) ||
2671 (curr_stencil->type == WEIGHT_SUM_MF), "invalid stencil type")
2672 switch (curr_stencil->type) {
2673 case(FIXED):
2674 func_pack_size = get_stencil_pack_size_fixed;
2675 break;
2676 case(DIRECT):
2677 func_pack_size = get_stencil_pack_size_direct;
2678 break;
2679 case(SUM):
2680 func_pack_size = get_stencil_pack_size_sum;
2681 break;
2682 default:
2683 case(WEIGHT_SUM):
2684 func_pack_size = get_stencil_pack_size_wsum;
2685 break;
2686 case(DIRECT_MF):
2687 func_pack_size = get_stencil_pack_size_direct_mf;
2688 break;
2689 case(SUM_MF):
2690 func_pack_size = get_stencil_pack_size_sum_mf;
2691 break;
2692 case(WEIGHT_SUM_MF):
2693 func_pack_size = get_stencil_pack_size_wsum_mf;
2694 break;
2695 };
2696 pack_sizes[i] = pack_size_type +
2698 &(curr_stencil->tgt), point_info_dt, comm) +
2699 func_pack_size(curr_stencil, point_info_dt, comm);
2700 }
2701}
2702
2704 struct interp_weight_stencil * stencil, void * buffer, int buffer_size,
2705 int * position, MPI_Datatype point_info_dt, MPI_Comm comm) {
2706
2707 UNUSED(point_info_dt);
2708
2709 // fixed value
2711 MPI_Pack(&(stencil->data.fixed.value), 1, MPI_DOUBLE, buffer, buffer_size,
2712 position, comm), comm);
2713}
2714
2716 struct interp_weight_stencil * stencil, void * buffer, int buffer_size,
2717 int * position, MPI_Datatype point_info_dt, MPI_Comm comm) {
2718
2719 // src
2721 &(stencil->data.direct.src), buffer, buffer_size, position, point_info_dt,
2722 comm);
2723}
2724
2726 struct interp_weight_stencil * stencil, void * buffer, int buffer_size,
2727 int * position, MPI_Datatype point_info_dt, MPI_Comm comm) {
2728
2729 // srcs
2731 stencil->data.sum.srcs, buffer, buffer_size, position, point_info_dt, comm);
2732}
2733
2735 struct interp_weight_stencil * stencil, void * buffer, int buffer_size,
2736 int * position, MPI_Datatype point_info_dt, MPI_Comm comm) {
2737
2738 // srcs
2740 stencil->data.weight_sum.srcs, buffer, buffer_size, position,
2741 point_info_dt, comm);
2742 // weights
2744 MPI_Pack(stencil->data.weight_sum.weights,
2745 (int)(stencil->data.weight_sum.srcs->count), MPI_DOUBLE,
2746 buffer, buffer_size, position, comm), comm);
2747}
2748
2750 struct interp_weight_stencil * stencil, void * buffer, int buffer_size,
2751 int * position, MPI_Datatype point_info_dt, MPI_Comm comm) {
2752
2753 // src
2755 &(stencil->data.direct_mf.src), buffer, buffer_size, position,
2756 point_info_dt, comm);
2757
2758 // field_idx
2759 size_t temp_field_idx = stencil->data.direct_mf.field_idx;
2761 MPI_Pack(&temp_field_idx, 1, YAC_MPI_SIZE_T,
2762 buffer, buffer_size, position, comm), comm);
2763}
2764
2766 struct interp_weight_stencil * stencil, void * buffer, int buffer_size,
2767 int * position, MPI_Datatype point_info_dt, MPI_Comm comm) {
2768
2769 // srcs
2771 stencil->data.sum_mf.srcs, buffer, buffer_size, position,
2772 point_info_dt, comm);
2773
2774 size_t count = stencil->data.sum_mf.srcs->count;
2775 // field_indices
2776 size_t * temp_field_indices = xmalloc(count * sizeof(*temp_field_indices));
2777 for (size_t i = 0; i < count; ++i)
2778 temp_field_indices[i] = stencil->data.sum_mf.field_indices[i];
2780 MPI_Pack(temp_field_indices, (int)count, YAC_MPI_SIZE_T,
2781 buffer, buffer_size, position, comm), comm);
2782 free(temp_field_indices);
2783}
2784
2786 struct interp_weight_stencil * stencil, void * buffer, int buffer_size,
2787 int * position, MPI_Datatype point_info_dt, MPI_Comm comm) {
2788
2789 // srcs
2791 stencil->data.weight_sum_mf.srcs, buffer, buffer_size, position,
2792 point_info_dt, comm);
2793
2794 size_t count = stencil->data.weight_sum_mf.srcs->count;
2795 // weights
2797 MPI_Pack(stencil->data.weight_sum_mf.weights, (int)count, MPI_DOUBLE,
2798 buffer, buffer_size, position, comm), comm);
2799 // field_indices
2800 size_t * temp_field_indices = xmalloc(count * sizeof(*temp_field_indices));
2801 for (size_t i = 0; i < count; ++i)
2802 temp_field_indices[i] = stencil->data.weight_sum_mf.field_indices[i];
2804 MPI_Pack(temp_field_indices, (int)count, YAC_MPI_SIZE_T,
2805 buffer, buffer_size, position, comm), comm);
2806 free(temp_field_indices);
2807}
2808
2809static void pack_stencils(
2810 struct interp_weight_stencil * stencils, size_t count, size_t * pack_order,
2811 void ** pack_data, int * pack_sizes, MPI_Datatype point_info_dt,
2812 MPI_Comm comm) {
2813
2815 stencils, count, pack_order, pack_sizes, point_info_dt, comm);
2816
2817 size_t pack_buffer_size = 0;
2818 for (size_t i = 0; i < count; ++i)
2819 pack_buffer_size += (size_t)(pack_sizes[i]);
2820
2821 void * pack_data_ = xmalloc(pack_buffer_size);
2822 size_t total_pack_size = 0;
2823
2824 for (size_t i = 0; i < count; ++i) {
2825
2826 struct interp_weight_stencil * curr_stencil = stencils + pack_order[i];
2827 void (*func_pack)(
2828 struct interp_weight_stencil * stencil, void * buffer, int buffer_size,
2829 int * position, MPI_Datatype point_info_dt, MPI_Comm comm);
2830
2831 YAC_ASSERT(
2832 (curr_stencil->type == FIXED) ||
2833 (curr_stencil->type == DIRECT) ||
2834 (curr_stencil->type == SUM) ||
2835 (curr_stencil->type == WEIGHT_SUM) ||
2836 (curr_stencil->type == DIRECT_MF) ||
2837 (curr_stencil->type == SUM_MF) ||
2838 (curr_stencil->type == WEIGHT_SUM_MF), "invalid stencil type")
2839 switch (curr_stencil->type) {
2840 default:
2841 case(FIXED):
2842 func_pack = pack_stencil_fixed;
2843 break;
2844 case(DIRECT):
2845 func_pack = pack_stencil_direct;
2846 break;
2847 case(SUM):
2848 func_pack = pack_stencil_sum;
2849 break;
2850 case(WEIGHT_SUM):
2851 func_pack = pack_stencil_wsum;
2852 break;
2853 case(DIRECT_MF):
2854 func_pack = pack_stencil_direct_mf;
2855 break;
2856 case(SUM_MF):
2857 func_pack = pack_stencil_sum_mf;
2858 break;
2859 case(WEIGHT_SUM_MF):
2860 func_pack = pack_stencil_wsum_mf;
2861 break;
2862 };
2863
2864 int position = 0;
2865 int type = (int)curr_stencil->type;
2866 void * buffer = (void*)((char*)pack_data_ + total_pack_size);
2867 int buffer_size = pack_sizes[i];
2868
2869 // type
2871 MPI_Pack(&type, 1, MPI_INT, buffer, buffer_size, &position, comm), comm);
2872 // tgt
2873 yac_remote_point_pack(&(curr_stencil->tgt), buffer, buffer_size,
2874 &position, point_info_dt, comm);
2875 // stencil data
2876 func_pack(curr_stencil, buffer, buffer_size, &position, point_info_dt, comm);
2877
2879 pack_sizes[i] >= position,
2880 "actual pack size is bigger then computed one (%d > %d)",
2881 position, pack_sizes[i]);
2882
2883 pack_sizes[i] = position;
2884 total_pack_size += (size_t)position;
2885 }
2886
2887 *pack_data = xrealloc(pack_data_, total_pack_size);
2888}
2889
2891 struct interp_weight_stencil * stencil, void * buffer, int buffer_size,
2892 int * position, MPI_Datatype point_info_dt, MPI_Comm comm) {
2893
2894 UNUSED(point_info_dt);
2895
2896 // fixed value
2898 MPI_Unpack(buffer, buffer_size, position, &(stencil->data.fixed.value), 1,
2899 MPI_DOUBLE, comm), comm);
2900}
2901
2903 struct interp_weight_stencil * stencil, void * buffer, int buffer_size,
2904 int * position, MPI_Datatype point_info_dt, MPI_Comm comm) {
2905
2906 // src
2908 buffer, buffer_size, position, &stencil->data.direct.src,
2909 point_info_dt, comm);
2910}
2911
2913 struct interp_weight_stencil * stencil, void * buffer, int buffer_size,
2914 int * position, MPI_Datatype point_info_dt, MPI_Comm comm) {
2915
2916 // srcs
2917 stencil->data.weight_sum.weights = NULL;
2919 buffer, buffer_size, position, &(stencil->data.sum.srcs), point_info_dt,
2920 comm);
2921}
2922
2924 struct interp_weight_stencil * stencil, void * buffer, int buffer_size,
2925 int * position, MPI_Datatype point_info_dt, MPI_Comm comm) {
2926
2927 // srcs
2929 buffer, buffer_size, position, &(stencil->data.weight_sum.srcs),
2930 point_info_dt, comm);
2931
2932 size_t count = stencil->data.weight_sum.srcs->count;
2933
2934 stencil->data.weight_sum.weights =
2935 xmalloc(count * sizeof(*(stencil->data.weight_sum.weights)));
2936
2937 // weights
2939 MPI_Unpack(buffer, buffer_size, position, stencil->data.weight_sum.weights,
2940 (int)count, MPI_DOUBLE, comm), comm);
2941}
2942
2944 struct interp_weight_stencil * stencil, void * buffer, int buffer_size,
2945 int * position, MPI_Datatype point_info_dt, MPI_Comm comm) {
2946
2947 // src
2949 buffer, buffer_size, position, &stencil->data.direct_mf.src,
2950 point_info_dt, comm);
2951
2952 // field_idx
2953 size_t temp_field_idx;
2955 MPI_Unpack(
2956 buffer, buffer_size, position, &temp_field_idx,
2957 1, YAC_MPI_SIZE_T, comm), comm);
2958 stencil->data.direct_mf.field_idx = (size_t)temp_field_idx;
2959}
2960
2962 struct interp_weight_stencil * stencil, void * buffer, int buffer_size,
2963 int * position, MPI_Datatype point_info_dt, MPI_Comm comm) {
2964
2965 // srcs
2967 buffer, buffer_size, position, &(stencil->data.sum_mf.srcs),
2968 point_info_dt, comm);
2969
2970 size_t count = stencil->data.sum_mf.srcs->count;
2971
2972 size_t * temp_field_indices = xmalloc(count * sizeof(*temp_field_indices));
2973 stencil->data.sum_mf.field_indices =
2974 xmalloc(count * sizeof(*(stencil->data.sum_mf.field_indices)));
2975
2976 // field_indices
2978 MPI_Unpack(
2979 buffer, buffer_size, position, temp_field_indices,
2980 (int)count, YAC_MPI_SIZE_T, comm), comm);
2981 for (size_t i = 0; i < count; ++i)
2982 stencil->data.sum_mf.field_indices[i] = (size_t)(temp_field_indices[i]);
2983 free(temp_field_indices);
2984}
2985
2987 struct interp_weight_stencil * stencil, void * buffer, int buffer_size,
2988 int * position, MPI_Datatype point_info_dt, MPI_Comm comm) {
2989
2990 // srcs
2992 buffer, buffer_size, position, &(stencil->data.weight_sum_mf.srcs),
2993 point_info_dt, comm);
2994
2995 size_t count = stencil->data.weight_sum_mf.srcs->count;
2996
2997 stencil->data.weight_sum_mf.weights =
2998 xmalloc(count * sizeof(*(stencil->data.weight_sum_mf.weights)));
2999
3000 // weights
3002 MPI_Unpack(
3003 buffer, buffer_size, position, stencil->data.weight_sum_mf.weights,
3004 (int)count, MPI_DOUBLE, comm), comm);
3005
3006 size_t * temp_field_indices = xmalloc(count * sizeof(*temp_field_indices));
3008 xmalloc(count * sizeof(*(stencil->data.weight_sum_mf.field_indices)));
3009
3010 // field_indices
3012 MPI_Unpack(
3013 buffer, buffer_size, position, temp_field_indices,
3014 (int)count, YAC_MPI_SIZE_T, comm), comm);
3015 for (size_t i = 0; i < count; ++i)
3016 stencil->data.weight_sum_mf.field_indices[i] =
3017 (size_t)(temp_field_indices[i]);
3018 free(temp_field_indices);
3019}
3020
3022 struct interp_weight_stencil * stencils, size_t count,
3023 void * packed_data, size_t packed_data_size,
3024 MPI_Datatype point_info_dt, MPI_Comm comm) {
3025
3026 for (size_t i = 0, offset = 0; i < count; ++i) {
3027
3028 YAC_ASSERT(packed_data_size >= offset, "invalid offset");
3029
3030 int position = 0;
3031 void * curr_buffer = (void*)((unsigned char*)packed_data + offset);
3032 int buffer_size = (int)(MIN(packed_data_size - offset, INT_MAX));
3033 struct interp_weight_stencil * curr_stencil = stencils + i;
3034
3035 int type;
3037 MPI_Unpack(
3038 curr_buffer, buffer_size, &position, &type, 1, MPI_INT, comm), comm);
3039
3040 void (*func_unpack)(
3041 struct interp_weight_stencil * stencil, void * buffer, int buffer_size,
3042 int * position, MPI_Datatype point_info_dt, MPI_Comm comm);
3043
3044 YAC_ASSERT(
3045 (type == FIXED) ||
3046 (type == DIRECT) || (type == SUM) || (type == WEIGHT_SUM) ||
3047 (type == DIRECT_MF) || (type == SUM_MF) || (type == WEIGHT_SUM_MF),
3048 "invalid stencil type")
3049 switch (type) {
3050 case(FIXED):
3051 func_unpack = unpack_stencil_fixed;
3052 break;
3053 case(DIRECT):
3054 func_unpack = unpack_stencil_direct;
3055 break;
3056 case(SUM):
3057 func_unpack = unpack_stencil_sum;
3058 break;
3059 default:
3060 case(WEIGHT_SUM):
3061 func_unpack = unpack_stencil_wsum;
3062 break;
3063 case(DIRECT_MF):
3064 func_unpack = unpack_stencil_direct_mf;
3065 break;
3066 case(SUM_MF):
3067 func_unpack = unpack_stencil_sum_mf;
3068 break;
3069 case(WEIGHT_SUM_MF):
3070 func_unpack = unpack_stencil_wsum_mf;
3071 break;
3072 };
3073
3074 curr_stencil->type =
3077 curr_buffer, buffer_size, &position, &(curr_stencil->tgt),
3078 point_info_dt, comm);
3079 func_unpack(
3080 curr_stencil, curr_buffer, buffer_size, &position, point_info_dt, comm);
3081 offset += (size_t)position;
3082 }
3083}
3084
3086 MPI_Comm comm, struct interp_weight_stencil * stencils,
3087 size_t * stencil_indices,
3088 size_t * stencil_sendcounts, size_t * stencil_recvcounts) {
3089
3090 int comm_rank, comm_size;
3091 yac_mpi_call(MPI_Comm_rank(comm, &comm_rank), comm);
3092 yac_mpi_call(MPI_Comm_size(comm, &comm_size), comm);
3093
3094 YAC_ASSERT(
3095 stencil_sendcounts[comm_rank] == stencil_recvcounts[comm_rank],
3096 "error in arguments")
3097
3098 size_t send_count = 0, recv_count = 0;
3099 size_t local_send_offset = 0;
3100 size_t local_recv_offset = 0;
3101 size_t local_count = (size_t)(stencil_sendcounts[comm_rank]);
3102 for (int i = 0; i < comm_rank; ++i) {
3103 send_count += stencil_sendcounts[i];
3104 recv_count += stencil_recvcounts[i];
3105 local_send_offset += stencil_sendcounts[i];
3106 local_recv_offset += stencil_recvcounts[i];
3107 }
3108 local_send_offset = send_count;
3109 local_recv_offset = recv_count;
3110 stencil_sendcounts[comm_rank] = 0;
3111 stencil_recvcounts[comm_rank] = 0;
3112 for (int i = comm_rank + 1; i < comm_size; ++i) {
3113 send_count += stencil_sendcounts[i];
3114 recv_count += stencil_recvcounts[i];
3115 }
3116
3117 struct interp_weight_stencil * new_stencils =
3118 xmalloc((recv_count + local_count) * sizeof(*new_stencils));
3119 size_t * local_stencil_indices =
3120 xmalloc(local_count * sizeof(*local_stencil_indices));
3121 memcpy(local_stencil_indices, stencil_indices + local_send_offset,
3122 local_count * sizeof(*local_stencil_indices));
3123
3124 // remove the local stencil indices
3125 memmove(
3126 stencil_indices + local_send_offset,
3127 stencil_indices + local_send_offset + local_count,
3128 (send_count - local_send_offset) * sizeof(*stencil_indices));
3129
3130 // pack the stencils that need to be send to other processes
3131 void * send_buffer;
3132 int * pack_sizes = xmalloc(send_count * sizeof(*pack_sizes));
3133 MPI_Datatype point_info_dt = yac_get_remote_point_info_mpi_datatype(comm);
3135 stencils, send_count, stencil_indices, &send_buffer, pack_sizes,
3136 point_info_dt, comm);
3137
3138 size_t * sendcounts, * recvcounts, * sdispls, *rdispls;
3140 1, &sendcounts, &recvcounts, &sdispls, &rdispls, comm);
3141
3142 send_count = 0;
3143 for (int rank = 0; rank < comm_size; ++rank) {
3144 size_t sendcount = 0;
3145 int curr_num_stencils = stencil_sendcounts[rank];
3146 for (int j = 0; j < curr_num_stencils; ++j, ++send_count)
3147 sendcount += (size_t)(pack_sizes[send_count]);
3148 sendcounts[rank] = sendcount;
3149 }
3150 free(pack_sizes);
3151
3153 1, sendcounts, recvcounts, sdispls, rdispls, comm);
3154
3155 size_t recv_size = recvcounts[comm_size - 1] + rdispls[comm_size - 1];
3156
3157 void * recv_buffer = xmalloc(recv_size);
3158
3159 // exchange stencils
3160 yac_alltoallv_packed_p2p(
3161 send_buffer, sendcounts, sdispls+1,
3162 recv_buffer, recvcounts, rdispls, comm, "exchange_stencils", __LINE__);
3163 yac_free_comm_buffers(sendcounts, recvcounts, sdispls, rdispls);
3164 free(send_buffer);
3165
3166 // unpack stencils
3168 new_stencils, recv_count,
3169 recv_buffer, recv_size, point_info_dt, comm);
3170 yac_mpi_call(MPI_Type_free(&point_info_dt), comm);
3171 free(recv_buffer);
3172
3173 memmove(new_stencils + local_recv_offset + local_count,
3174 new_stencils + local_recv_offset ,
3175 (recv_count - local_recv_offset ) * sizeof(*new_stencils));
3176 for (size_t i = 0; i < local_count; ++i, ++local_recv_offset )
3177 new_stencils[local_recv_offset] =
3179 stencils + local_stencil_indices[i],
3180 stencils[local_stencil_indices[i]].tgt);
3181 free(local_stencil_indices);
3182
3183 return new_stencils;
3184}
3185
3187 struct yac_interp_weights * weights, size_t * stencil_indices,
3188 int * stencil_ranks, size_t count) {
3189
3190 char const * routine = "yac_interp_weights_get_stencils";
3191
3192 MPI_Comm comm = weights->comm;
3193 int comm_size;
3194 yac_mpi_call(MPI_Comm_size(comm, &comm_size), comm);
3195
3196 YAC_ASSERT(count <= INT_MAX, "count exceeds INT_MAX");
3197
3198 size_t * reorder_idx = xmalloc(count * sizeof(*reorder_idx));
3199 for (size_t i = 0; i < count; ++i) reorder_idx[i] = i;
3200
3202 stencil_ranks, count, stencil_indices, reorder_idx);
3203
3204 // exchange requested stencils indices
3205 size_t * sendcounts, * recvcounts, * sdispls, *rdispls;
3207 1, &sendcounts, &recvcounts, &sdispls, &rdispls, comm);
3208 for (size_t i = 0; i < count; ++i) sendcounts[stencil_ranks[i]]++;
3210 1, sendcounts, recvcounts, sdispls, rdispls, comm);
3211 size_t recv_count =
3212 rdispls[comm_size - 1] + recvcounts[comm_size - 1];
3213 size_t * size_t_buffer =
3214 xmalloc((count + recv_count) * sizeof(*size_t_buffer));
3215 size_t * send_stencil_indices = size_t_buffer;
3216 size_t * recv_stencil_indices = size_t_buffer + count;
3217 for (size_t i = 0; i < count; ++i)
3218 send_stencil_indices[i] = stencil_indices[i];
3219 yac_alltoallv_size_t_p2p(
3220 send_stencil_indices, sendcounts, sdispls+1,
3221 recv_stencil_indices, recvcounts, rdispls, comm, routine, __LINE__);
3222
3223 // exchange stencils
3224 size_t * exchange_stencil_indices =
3225 xmalloc(recv_count * sizeof(*exchange_stencil_indices));
3226 for (size_t i = 0; i < recv_count; ++i) {
3227 YAC_ASSERT(
3228 (size_t)(recv_stencil_indices[i]) < weights->stencils_size,
3229 "invalid stencil index");
3230 exchange_stencil_indices[i] = (size_t)(recv_stencil_indices[i]);
3231 }
3232 free(size_t_buffer);
3233 struct interp_weight_stencil * stencils =
3234 exchange_stencils(comm, weights->stencils, exchange_stencil_indices,
3235 recvcounts, sendcounts);
3236 free(exchange_stencil_indices);
3237 yac_free_comm_buffers(sendcounts, recvcounts, sdispls, rdispls);
3238
3239 // sort received stencils into original order
3240 struct interp_weight_stencil * sorted_stencils =
3241 xmalloc(count * sizeof(*sorted_stencils));
3242 for (size_t i = 0; i < count; ++i)
3243 sorted_stencils[reorder_idx[i]] = stencils[i];
3244 free(stencils);
3245 free(reorder_idx);
3246
3247 return sorted_stencils;
3248}
3249
3251 struct interp_weight_stencil * stencils, size_t count);
3252
3254 struct yac_interp_weights * weights, struct remote_points * tgts,
3255 size_t * num_stencils_per_tgt, size_t * stencil_indices,
3256 int * stencil_ranks, double * w) {
3257
3258 size_t count = (tgts != NULL)?tgts->count:0;
3259 MPI_Comm comm = weights->comm;
3260 int comm_rank, comm_size;
3261 yac_mpi_call(MPI_Comm_rank(comm, &comm_rank), comm);
3262 yac_mpi_call(MPI_Comm_size(comm, &comm_size), comm);
3263
3264 // count the number of missing stencils
3265 size_t total_num_stencils = 0;
3266 size_t max_num_stencils_per_tgt = 0;
3267 for (size_t i = 0; i < count; ++i) {
3268 size_t curr_num_stencils_per_tgt = num_stencils_per_tgt[i];
3269 if (curr_num_stencils_per_tgt > max_num_stencils_per_tgt)
3270 max_num_stencils_per_tgt = curr_num_stencils_per_tgt;
3271 total_num_stencils += num_stencils_per_tgt[i];
3272 }
3273 size_t num_missing_stencils = 0;
3274 for (size_t i = 0; i < total_num_stencils; ++i)
3275 if (stencil_ranks[i] != comm_rank) num_missing_stencils++;
3276
3277 // get missing stencils
3278 size_t * missing_stencil_indices =
3279 xmalloc(num_missing_stencils * sizeof(*missing_stencil_indices));
3280 int * missing_stencil_ranks =
3281 xmalloc(num_missing_stencils * sizeof(*missing_stencil_ranks));
3282 for (size_t i = 0, j = 0; i < total_num_stencils; ++i) {
3283 if (stencil_ranks[i] != comm_rank) {
3284 missing_stencil_indices[j] = stencil_indices[i];
3285 missing_stencil_ranks[j] = stencil_ranks[i];
3286 ++j;
3287 }
3288 }
3289 struct interp_weight_stencil * missing_stencils =
3291 weights, missing_stencil_indices, missing_stencil_ranks,
3292 num_missing_stencils);
3293 free(missing_stencil_ranks);
3294 free(missing_stencil_indices);
3295
3296 // merge stencils to generate new ones
3297 {
3298 struct interp_weight_stencil * stencils = weights->stencils;
3299 size_t stencils_array_size = weights->stencils_array_size;
3300 size_t stencils_size = weights->stencils_size;
3301
3302 struct interp_weight_stencil ** stencils_buffer =
3303 xmalloc(max_num_stencils_per_tgt * sizeof(*stencils_buffer));
3304
3306 stencils, stencils_array_size, stencils_size + count);
3307
3308 for (size_t i = 0, j = 0; i < count;
3309 ++i, ++stencils_size) {
3310
3311 size_t curr_num_stencils = num_stencils_per_tgt[i];
3312 for (size_t k = 0; k < curr_num_stencils; ++k)
3313 stencils_buffer[k] =
3314 (stencil_ranks[k] == comm_rank)?
3315 (stencils + stencil_indices[k]):(missing_stencils + (j++));
3316
3317 stencils[stencils_size] =
3318 stencils_merge(stencils_buffer, w, curr_num_stencils, tgts->data[i]);
3319 w += curr_num_stencils;
3320 stencil_indices += curr_num_stencils;
3321 stencil_ranks += curr_num_stencils;
3322 }
3323
3324 weights->stencils = stencils;
3325 weights->stencils_array_size = stencils_array_size;
3326 weights->stencils_size = stencils_size;
3327
3328 free(stencils_buffer);
3329 }
3330
3331 yac_interp_weight_stencils_delete(missing_stencils, num_missing_stencils);
3332}
3333
3334static int compute_owner(int * ranks, size_t count) {
3335
3336 YAC_ASSERT(count != 0, "count == 0")
3337
3338 yac_quicksort_index(ranks, count, NULL);
3339
3340 int best_rank = -1;
3341 size_t best_rank_count = 0;
3342
3343 size_t curr_rank_count = 1;
3344 int prev_rank = ranks[0];
3345
3346 for (size_t i = 1; i < count; ++i, ++curr_rank_count) {
3347 int curr_rank = ranks[i];
3348 if (prev_rank != curr_rank) {
3349 if (curr_rank_count > best_rank_count) {
3350 best_rank = prev_rank;
3351 best_rank_count = curr_rank_count;
3352 }
3353 prev_rank = curr_rank;
3354 curr_rank_count = 0;
3355 }
3356 }
3357
3358 return (curr_rank_count > best_rank_count)?prev_rank:best_rank;
3359}
3360
3362 struct interp_weight_stencil * stencils, size_t count,
3363 enum yac_interp_weight_stencil_type stencil_type,
3364 int * rank_is_source, int * rank_is_target) {
3365
3366 // compute total number of links
3367 size_t total_num_links = 0;
3368
3369 size_t valid_count = 0;
3370 for (size_t i = 0; i < count; ++i) {
3371 if (remote_point_is_valid(__func__, stencils[i].tgt, rank_is_target)) {
3372 YAC_ASSERT(stencils[i].type == stencil_type, "wrong stencil type")
3373 // due to the data layout this works for "sum" and "weight_sum"
3374 total_num_links += stencils[i].data.weight_sum.srcs->count;
3375 ++valid_count;
3376 }
3377 }
3378
3380 xmalloc(sizeof(*temp) + total_num_links * sizeof(temp->buffer[0]));
3381 struct interp_weight_stencils_wsum_mf * wsum_stencils =
3382 (struct interp_weight_stencils_wsum_mf *)temp;
3383 wsum_stencils->data = xmalloc(valid_count * sizeof(*(wsum_stencils->data)));
3384 wsum_stencils->count = valid_count;
3385
3386 // extract data from stencils
3387 for (size_t i = 0, j = 0, k = 0; i < count; ++i) {
3388
3389 struct interp_weight_stencil * curr_stencil = stencils + i;
3390
3391 if (remote_point_is_valid(__func__, curr_stencil->tgt, rank_is_target)) {
3392
3393 struct interp_weight_stencil_wsum_mf * curr_wsum_stencil =
3394 wsum_stencils->data + j;
3395 struct interp_weight_stencil_wsum_mf_weight * curr_links =
3396 &(temp->buffer[k]);
3397 size_t curr_stencil_size = curr_stencil->data.weight_sum.srcs->count;
3398 struct remote_point * curr_srcs =
3399 curr_stencil->data.weight_sum.srcs->data;
3400 curr_wsum_stencil->tgt =
3401 copy_remote_point_masked(__func__, curr_stencil->tgt, rank_is_target);
3402 curr_wsum_stencil->count = curr_stencil_size;
3403 curr_wsum_stencil->data = curr_links;
3404 for (size_t l = 0; l < curr_stencil_size; ++l) {
3405 int curr_count = curr_srcs[l].data.count;
3406 YAC_ASSERT(curr_count >= 1, "global src id no found")
3407 curr_links[l].src =
3408 select_src(__func__, curr_srcs[l].data, rank_is_source);
3409
3410 switch(stencil_type) {
3411 YAC_UNREACHABLE_DEFAULT("unsupported stencil type");
3412 case(SUM):
3413 curr_links[l].weight = 1.0;
3414 curr_links[l].src_field_idx = 0;
3415 break;
3416 case(WEIGHT_SUM):
3417 curr_links[l].weight = curr_stencil->data.weight_sum.weights[l];
3418 curr_links[l].src_field_idx = 0;
3419 break;
3420 case(SUM_MF):
3421 curr_links[l].weight = 1.0;
3422 curr_links[l].src_field_idx =
3423 curr_stencil->data.sum_mf.field_indices[l];
3424 break;
3425 case(WEIGHT_SUM_MF):
3426 curr_links[l].weight = curr_stencil->data.weight_sum_mf.weights[l];
3427 curr_links[l].src_field_idx =
3428 curr_stencil->data.weight_sum_mf.field_indices[l];
3429 break;
3430 };
3431 }
3432 k += curr_stencil_size;
3433 ++j;
3434 }
3435 }
3436
3437 return wsum_stencils;
3438}
3439
3440static MPI_Datatype get_wsum_mf_weight_mpi_datatype(MPI_Comm comm) {
3441
3442 struct interp_weight_stencil_wsum_mf_weight dummy = {0};
3443 MPI_Datatype dt;
3444 enum {NUM_MEMBERS = 4};
3445 int array_of_blocklengths[NUM_MEMBERS] = {1, 1, 1, 1};
3446 MPI_Aint array_of_displacements[NUM_MEMBERS];
3447 {
3448 MPI_Aint base_addr;
3449 yac_mpi_call(MPI_Get_address(&dummy, &base_addr), comm);
3451 MPI_Get_address(
3452 &(dummy.src.rank), &array_of_displacements[0]), comm);
3453 array_of_displacements[0] -= base_addr;
3455 MPI_Get_address(
3456 &(dummy.src.orig_pos), &array_of_displacements[1]), comm);
3457 array_of_displacements[1] -= base_addr;
3459 MPI_Get_address(
3460 &(dummy.src_field_idx), &array_of_displacements[2]), comm);
3461 array_of_displacements[2] -= base_addr;
3463 MPI_Get_address(
3464 &(dummy.weight), &array_of_displacements[3]), comm);
3465 array_of_displacements[3] -= base_addr;
3466 }
3467 const MPI_Datatype array_of_types[NUM_MEMBERS] =
3468 {MPI_INT, YAC_MPI_SIZE_T, YAC_MPI_SIZE_T, MPI_DOUBLE};
3470 MPI_Type_create_struct(
3471 NUM_MEMBERS, array_of_blocklengths, array_of_displacements,
3472 array_of_types, &dt), comm);
3473 return yac_create_resized(dt, sizeof(dummy), comm);
3474}
3475
3477 struct interp_weight_stencil_wsum_mf * stencil,
3478 MPI_Datatype wsum_mf_weight_dt, MPI_Datatype point_info_dt, MPI_Comm comm) {
3479
3480 int pack_size_count,
3481 pack_size_weights,
3482 pack_size_tgt;
3483
3484 yac_mpi_call(MPI_Pack_size(1, MPI_INT, comm, &pack_size_count), comm);
3486 MPI_Pack_size(
3487 (int)(stencil->count), wsum_mf_weight_dt, comm, &pack_size_weights), comm);
3488 pack_size_tgt =
3489 yac_remote_point_get_pack_size(&(stencil->tgt), point_info_dt, comm);
3490
3491 return pack_size_count + pack_size_weights + pack_size_tgt;
3492}
3493
3495 struct interp_weight_stencil_wsum_mf * wsum_stencils, size_t count,
3496 size_t * pack_order, void ** pack_data, int * pack_sizes,
3497 int * weight_counts, MPI_Comm comm) {
3498
3499 MPI_Datatype wsum_mf_weight_dt = get_wsum_mf_weight_mpi_datatype(comm);
3500 MPI_Datatype point_info_dt = yac_get_remote_point_info_mpi_datatype(comm);
3501
3502 // get the pack sizes and the upper bound for the pack buffer size
3503 size_t temp_total_pack_size = 0;
3504 for (size_t i = 0; i < count; ++i) {
3505 temp_total_pack_size +=
3506 (pack_sizes[i] =
3508 wsum_stencils + pack_order[i],
3509 wsum_mf_weight_dt, point_info_dt, comm));
3510 }
3511
3512 void * pack_data_ = xmalloc(temp_total_pack_size);
3513 size_t total_pack_size = 0;
3514
3515 // pack the stencils
3516 for (size_t i = 0; i < count; ++i) {
3517
3518 size_t idx = pack_order[i];
3519
3520 int position = 0;
3521 void * buffer = (void*)((unsigned char*)pack_data_ + total_pack_size);
3522 int buffer_size = pack_sizes[i];
3523 int curr_count = wsum_stencils[idx].count;
3524
3525 // tgt
3527 &(wsum_stencils[idx].tgt), buffer, buffer_size, &position,
3528 point_info_dt, comm);
3529 // weight count
3531 MPI_Pack(&curr_count, 1, MPI_INT, buffer, buffer_size, &position, comm), comm);
3532 // weights
3534 MPI_Pack(wsum_stencils[idx].data, curr_count, wsum_mf_weight_dt,
3535 buffer, buffer_size, &position, comm), comm);
3536
3537 pack_sizes[i] = position;
3538 weight_counts[i] = curr_count;
3539 total_pack_size += (size_t)position;
3540 }
3541
3542 yac_mpi_call(MPI_Type_free(&point_info_dt), comm);
3543 yac_mpi_call(MPI_Type_free(&wsum_mf_weight_dt), comm);
3544
3545 *pack_data = xrealloc(pack_data_, total_pack_size);
3546}
3547
3549 struct interp_weight_stencil_wsum_mf * wsum_stencils,
3550 struct interp_weight_stencil_wsum_mf_weight * weight_buffer, size_t count,
3551 void * packed_data, size_t packed_data_size, MPI_Comm comm) {
3552
3553 MPI_Datatype wsum_mf_weight_dt = get_wsum_mf_weight_mpi_datatype(comm);
3554 MPI_Datatype point_info_dt = yac_get_remote_point_info_mpi_datatype(comm);
3555
3556 size_t weight_offset = 0;
3557 for (size_t i = 0, offset = 0; i < count; ++i) {
3558
3559 int position = 0;
3560 void * curr_buffer = (void*)((char*)packed_data + offset);
3561 int buffer_size = (int)(packed_data_size - offset);
3562 struct interp_weight_stencil_wsum_mf * curr_wsum_stencil =
3563 wsum_stencils + i;
3564
3565 struct remote_point tgt;
3566 struct interp_weight_stencil_wsum_mf_weight * curr_weights =
3567 weight_buffer + weight_offset;
3568 int weight_count;
3570 curr_buffer, buffer_size, &position, &tgt, point_info_dt, comm);
3572 MPI_Unpack(curr_buffer, buffer_size, &position,
3573 &weight_count, 1, MPI_INT, comm),
3574 comm);
3576 MPI_Unpack(curr_buffer, buffer_size, &position,
3577 curr_weights, weight_count, wsum_mf_weight_dt, comm), comm);
3578
3579 curr_wsum_stencil->tgt = tgt;
3580 curr_wsum_stencil->data = curr_weights;
3581 curr_wsum_stencil->count = (size_t)weight_count;
3582
3583 weight_offset += (size_t)weight_count;
3584 offset += (size_t)position;
3585 }
3586
3587 yac_mpi_call(MPI_Type_free(&point_info_dt), comm);
3588 yac_mpi_call(MPI_Type_free(&wsum_mf_weight_dt), comm);
3589
3590 return weight_offset;
3591}
3592
3594 MPI_Comm comm, struct interp_weight_stencils_wsum_mf * wsum_stencils_data,
3595 int * stencil_owner, size_t * reorder_idx, size_t num_owners) {
3596
3597 struct interp_weight_stencil_wsum_mf * wsum_stencils =
3598 wsum_stencils_data->data;
3599
3600 int comm_rank, comm_size;
3601 yac_mpi_call(MPI_Comm_rank(comm, &comm_rank), comm);
3602 yac_mpi_call(MPI_Comm_size(comm, &comm_size), comm);
3603
3604 size_t local_weight_count = 0;
3605 size_t local_count = 0;
3606 for (size_t i = 0; i < num_owners; ++i) {
3607 if (stencil_owner[i] == comm_rank) {
3608 local_weight_count += wsum_stencils[reorder_idx[i]].count;
3609 stencil_owner[i] = INT_MAX;
3610 ++local_count;
3611 }
3612 }
3613 yac_quicksort_index_int_size_t(stencil_owner, num_owners, reorder_idx);
3614
3615 size_t send_count = num_owners - local_count;
3616
3617 // pack the stencils that need to be send to other processes
3618 void * send_buffer;
3619 int * pack_sizes = xmalloc(2 * send_count * sizeof(*pack_sizes));
3620 int * weight_counts = pack_sizes + send_count;
3621 pack_stencils_wsum_mf(wsum_stencils, send_count, reorder_idx, &send_buffer,
3622 pack_sizes, weight_counts, comm);
3623
3624 size_t * sendcounts, * recvcounts, * sdispls, *rdispls;
3626 3, &sendcounts, &recvcounts, &sdispls, &rdispls, comm);
3627
3628 for (size_t i = 0; i < send_count; ++i) {
3629 int curr_rank = stencil_owner[i];
3630 sendcounts[3 * curr_rank + 0]++;
3631 sendcounts[3 * curr_rank + 1] += (size_t)(pack_sizes[i]);
3632 sendcounts[3 * curr_rank + 2] += (size_t)(weight_counts[i]);
3633 }
3634 free(pack_sizes);
3635
3636 // exchange the number of stencils to be exchanged and the total pack sizes
3637 yac_mpi_call(MPI_Alltoall(sendcounts, 3, YAC_MPI_SIZE_T,
3638 recvcounts, 3, YAC_MPI_SIZE_T, comm), comm);
3639
3640 size_t recv_count = 0;
3641 size_t recv_size = 0;
3642 size_t recv_weight_count = 0;
3643 size_t saccu = 0, raccu = 0;
3644 for (int i = 0; i < comm_size; ++i) {
3645 sdispls[i] = saccu;
3646 rdispls[i] = raccu;
3647 recv_count += recvcounts[3 * i + 0];
3648 recv_size += recvcounts[3 * i + 1];
3649 recv_weight_count += recvcounts[3 * i + 2];
3650 saccu += sendcounts[3 * i + 1];
3651 raccu += recvcounts[3 * i + 1];
3652 sendcounts[i] = sendcounts[3 * i + 1];
3653 recvcounts[i] = recvcounts[3 * i + 1];
3654 }
3655
3656 void * recv_buffer = xmalloc(recv_size);
3657
3658 // exchange stencils
3659 yac_alltoallv_packed_p2p(
3660 send_buffer, sendcounts, sdispls, recv_buffer, recvcounts, rdispls, comm,
3661 "redist_wsum_mf_stencils", __LINE__);
3662 yac_free_comm_buffers(sendcounts, recvcounts, sdispls, rdispls);
3663 free(send_buffer);
3664
3666 xmalloc(sizeof(*temp) +
3667 (local_weight_count + recv_weight_count) * sizeof(temp->buffer[0]));
3668 struct interp_weight_stencils_wsum_mf * new_wsum_stencils_data =
3669 (struct interp_weight_stencils_wsum_mf *)temp;
3670 struct interp_weight_stencil_wsum_mf * new_wsum_stencils =
3671 ((new_wsum_stencils_data->data =
3672 xmalloc((local_count + recv_count) *
3673 sizeof(*(new_wsum_stencils_data->data)))));
3674 new_wsum_stencils_data->count = local_count + recv_count;
3675
3676 // unpack stencils
3677 size_t weight_offset =
3679 new_wsum_stencils, &(temp->buffer[0]), recv_count,
3680 recv_buffer, recv_size, comm);
3681 free(recv_buffer);
3682 new_wsum_stencils += recv_count;
3683 struct interp_weight_stencil_wsum_mf_weight * weight_buffer =
3684 &(temp->buffer[weight_offset]);
3685
3686 // copy the stencils that stay locally into the new stencil array
3687 yac_quicksort_index_size_t_size_t(reorder_idx + send_count, local_count, NULL);
3688 for (size_t i = 0, weight_offset = 0; i < local_count; ++i) {
3689 struct interp_weight_stencil_wsum_mf * curr_wsum_stencil =
3690 wsum_stencils + reorder_idx[i + send_count];
3691 struct interp_weight_stencil_wsum_mf * curr_new_wsum_stencil =
3692 new_wsum_stencils + i;
3693 struct interp_weight_stencil_wsum_mf_weight * curr_new_weights =
3694 weight_buffer + weight_offset;
3695 size_t curr_stencil_size = curr_wsum_stencil->count;
3696 curr_new_wsum_stencil->tgt = copy_remote_point(curr_wsum_stencil->tgt);
3697 curr_new_wsum_stencil->count = curr_stencil_size;
3698 curr_new_wsum_stencil->data = curr_new_weights;
3699 memcpy(curr_new_weights, curr_wsum_stencil->data,
3700 curr_stencil_size * sizeof(*curr_new_weights));
3701 weight_offset += curr_stencil_size;
3702 }
3703
3704 return new_wsum_stencils_data;
3705}
3706
3708 MPI_Comm comm, struct interp_weight_stencils_wsum_mf * wsum_stencils_data) {
3709
3710 struct interp_weight_stencil_wsum_mf * wsum_stencils =
3711 wsum_stencils_data->data;
3712 size_t count = wsum_stencils_data->count;
3713
3714 // determine maximum stencil size
3715 size_t max_stencil_size = 0;
3716 for (size_t i = 0; i < count; ++i) {
3717 size_t curr_stencil_size = wsum_stencils[i].count;
3718 if (curr_stencil_size > max_stencil_size)
3719 max_stencil_size = curr_stencil_size;
3720 }
3721
3722 // determine source process for each stencil
3723 int * rank_buffer =
3724 xmalloc((count + max_stencil_size) * sizeof(*rank_buffer));
3725 int * stencil_owner = rank_buffer;
3726 int * stencil_owners = rank_buffer + count;
3727 size_t * reorder_idx = xmalloc(count * sizeof(*reorder_idx));
3728 for (size_t i = 0; i < count; ++i) {
3729 size_t curr_stencil_size = wsum_stencils[i].count;
3730 struct interp_weight_stencil_wsum_mf_weight * curr_weights =
3731 wsum_stencils[i].data;
3732 for (size_t j = 0; j < curr_stencil_size; ++j)
3733 stencil_owners[j] = curr_weights[j].src.rank;
3734 stencil_owner[i] = compute_owner(stencil_owners, curr_stencil_size);
3735 reorder_idx[i] = i;
3736 }
3737
3738 struct interp_weight_stencils_wsum_mf * new_wsum_stencils_data =
3740 comm, wsum_stencils_data, stencil_owner, reorder_idx, count);
3741
3742 free(reorder_idx);
3743 free(rank_buffer);
3744
3745 return new_wsum_stencils_data;
3746}
3747
3748static int compare_remote_point_info(const void * a, const void * b) {
3749
3750 int ret = ((struct remote_point_info *)a)->rank -
3751 ((struct remote_point_info *)b)->rank;
3752
3753 if (ret) return ret;
3754
3755 return (((struct remote_point_info *)a)->orig_pos >
3756 ((struct remote_point_info *)b)->orig_pos) -
3757 (((struct remote_point_info *)a)->orig_pos <
3758 ((struct remote_point_info *)b)->orig_pos);
3759}
3760
3762 MPI_Comm comm, struct interp_weight_stencils_wsum_mf * wsum_stencils_data) {
3763
3764 struct interp_weight_stencil_wsum_mf * wsum_stencils =
3765 wsum_stencils_data->data;
3766 size_t count = wsum_stencils_data->count;
3767
3768 // determine total number of stencils to be sent to other processes
3769 // (a single stencil may be sent to multiple target processes)
3770 size_t total_owner_count = 0;
3771 for (size_t i = 0; i < count; ++i) {
3772 int stencil_size = wsum_stencils[i].tgt.data.count;
3773 if (stencil_size == 1) {
3774 total_owner_count++;
3775 } else {
3776 struct remote_point_info * tgt_point_infos =
3777 wsum_stencils[i].tgt.data.data.multi;
3778 qsort(
3779 tgt_point_infos, stencil_size, sizeof(*tgt_point_infos),
3781 int prev_rank = INT_MAX;
3782 for (int j = 0; j < stencil_size; ++j) {
3783 int curr_rank = tgt_point_infos[j].rank;
3784 if (curr_rank != prev_rank) {
3785 ++total_owner_count;
3786 prev_rank = curr_rank;
3787 }
3788 }
3789 }
3790 }
3791
3792 int * stencil_owner = xmalloc(total_owner_count * sizeof(*stencil_owner));
3793 size_t * reorder_idx = xmalloc(total_owner_count * sizeof(*reorder_idx));
3794 for (size_t i = 0, k = 0; i < count; ++i) {
3795 int stencil_size = wsum_stencils[i].tgt.data.count;
3796 if (stencil_size == 1) {
3797 stencil_owner[k] = wsum_stencils[i].tgt.data.data.single.rank;
3798 reorder_idx[k] = i;
3799 ++k;
3800 } else {
3801 struct remote_point_info * tgt_point_infos =
3802 wsum_stencils[i].tgt.data.data.multi;
3803 int prev_rank = INT_MAX;
3804 for (int j = 0; j < stencil_size; ++j) {
3805 int curr_rank = tgt_point_infos[j].rank;
3806 if (curr_rank != prev_rank) {
3807 stencil_owner[k] = tgt_point_infos[j].rank;
3808 reorder_idx[k] = i;
3809 ++k;
3810 prev_rank = curr_rank;
3811 }
3812 }
3813 }
3814 }
3815
3816 struct interp_weight_stencils_wsum_mf * new_wsum_stencils_data =
3818 comm, wsum_stencils_data, stencil_owner, reorder_idx, total_owner_count);
3819
3820 wsum_stencils = new_wsum_stencils_data->data;
3821 count = new_wsum_stencils_data->count;
3822
3823 free(reorder_idx);
3824 free(stencil_owner);
3825
3826 if (count == 0) return new_wsum_stencils_data;
3827
3828 int comm_rank;
3829 yac_mpi_call(MPI_Comm_rank(comm, &comm_rank), comm);
3830
3831 // count total number of local target locations
3832 size_t total_num_tgt_pos = 0;
3833 for (size_t i = 0; i < count; ++i) {
3834 size_t curr_count = wsum_stencils[i].tgt.data.count;
3835 if (curr_count == 1) {
3836 ++total_num_tgt_pos;
3837 } else {
3838 struct remote_point_info * curr_point_infos =
3839 wsum_stencils[i].tgt.data.data.multi;
3840 for (size_t j = 0; j < curr_count; ++j)
3841 if (curr_point_infos[j].rank == comm_rank)
3842 ++total_num_tgt_pos;
3843 }
3844 }
3845
3846 if (total_num_tgt_pos != count) {
3847 new_wsum_stencils_data->data =
3848 ((wsum_stencils =
3849 xrealloc(wsum_stencils, total_num_tgt_pos * sizeof(*wsum_stencils))));
3850 new_wsum_stencils_data->count = total_num_tgt_pos;
3851 }
3852
3853 // remove all non local target point information
3854 for (size_t i = 0, offset = count; i < count; ++i) {
3855 size_t curr_count = wsum_stencils[i].tgt.data.count;
3856 if (curr_count > 1) {
3857 struct remote_point_info * curr_point_infos =
3858 wsum_stencils[i].tgt.data.data.multi;
3859 // find first local target point
3860 size_t j;
3861 for (j = 0; j < curr_count; ++j) {
3862 if (curr_point_infos[j].rank == comm_rank) {
3863 wsum_stencils[i].tgt.data.count = 1;
3864 wsum_stencils[i].tgt.data.data.single.rank = comm_rank;
3865 wsum_stencils[i].tgt.data.data.single.orig_pos =
3866 curr_point_infos[j].orig_pos;
3867 break;
3868 }
3869 }
3870 // make a copy for the remaining local target positions
3871 for (j = j + 1; j < curr_count; ++j) {
3872 if (curr_point_infos[j].rank == comm_rank) {
3873 wsum_stencils[offset] = wsum_stencils[i];
3874 wsum_stencils[offset].tgt.data.data.single.orig_pos =
3875 curr_point_infos[j].orig_pos;
3876 ++offset;
3877 }
3878 }
3879 free(curr_point_infos);
3880 }
3881 }
3882
3883 return new_wsum_stencils_data;
3884}
3885
3887 struct remote_point_info_reorder * halo_points, size_t count,
3888 size_t num_src_fields, MPI_Comm comm, Xt_config redist_config) {
3889
3890 int comm_size;
3891 yac_mpi_call(MPI_Comm_size(comm, &comm_size), comm);
3892
3893 size_t * sendcounts, * recvcounts, * sdispls, *rdispls;
3895 num_src_fields, &sendcounts, &recvcounts, &sdispls, &rdispls, comm);
3896 size_t * size_t_buffer =
3897 xmalloc(4 * (size_t)comm_size * sizeof(*size_t_buffer));
3898 size_t * total_sendcounts = size_t_buffer + 0 * comm_size;
3899 size_t * total_recvcounts = size_t_buffer + 1 * comm_size;
3900 size_t * total_sdispls = size_t_buffer + 2 * comm_size;
3901 size_t * total_rdispls = size_t_buffer + 3 * comm_size;
3902
3903 for (size_t i = 0; i < count; ++i)
3904 sendcounts[halo_points[i].data.rank * num_src_fields +
3905 halo_points[i].field_idx]++;
3906
3908 num_src_fields, sendcounts, recvcounts, sdispls, rdispls, comm);
3909
3910 size_t saccu = 0, raccu = 0;
3911 for (int i = 0; i < comm_size; ++i) {
3912 total_sdispls[i] = saccu;
3913 total_rdispls[i] = raccu;
3914 total_sendcounts[i] = 0;
3915 total_recvcounts[i] = 0;
3916 for (size_t j = 0; j < num_src_fields; ++j) {
3917 total_sendcounts[i] += sendcounts[num_src_fields * i + j];
3918 total_recvcounts[i] += recvcounts[num_src_fields * i + j];
3919 }
3920 saccu += total_sendcounts[i];
3921 raccu += total_recvcounts[i];
3922 }
3923
3924 size_t recv_count = total_recvcounts[comm_size - 1] +
3925 total_rdispls[comm_size - 1];
3926
3927 int * exchange_buffer =
3928 xmalloc((2 * count + recv_count) * sizeof(*exchange_buffer));
3929 int * send_buffer = exchange_buffer;
3930 int * reorder_idx = exchange_buffer + count;
3931 int * recv_buffer = exchange_buffer + 2 * count;
3932
3933 // pack the original positions of the requested points
3934 size_t num_halo_per_src_field[num_src_fields];
3935 memset(
3936 num_halo_per_src_field, 0,
3937 num_src_fields * sizeof(num_halo_per_src_field[0]));
3938 for (size_t i = 0; i < count; ++i) {
3939 size_t curr_src_field_idx = (size_t)(halo_points[i].field_idx);
3940 size_t pos = sdispls[(size_t)(halo_points[i].data.rank) * num_src_fields +
3941 curr_src_field_idx + 1]++;
3942 size_t orig_pos = halo_points[i].data.orig_pos;
3943 YAC_ASSERT(orig_pos <= INT_MAX, "offset not supported by MPI")
3944 send_buffer[pos] = (int)orig_pos;
3945 reorder_idx[pos] = num_halo_per_src_field[curr_src_field_idx]++;
3946 }
3947
3948 // exchange original positions of the requested points
3949 yac_alltoallv_int_p2p(
3950 send_buffer, total_sendcounts, total_sdispls,
3951 recv_buffer, total_recvcounts, total_rdispls, comm,
3952 "generate_halo_redists", __LINE__);
3953
3954 free(size_t_buffer);
3955
3956 size_t nsend = 0, nsends[num_src_fields];
3957 size_t nrecv = 0, nrecvs[num_src_fields];
3958 memset(nsends, 0, num_src_fields * sizeof(nsends[0]));
3959 memset(nrecvs, 0, num_src_fields * sizeof(nrecvs[0]));
3960 for (int i = 0; i < comm_size; ++i) {
3961 for (size_t field_idx = 0; field_idx < num_src_fields; ++field_idx) {
3962 if (sendcounts[i * num_src_fields + field_idx] > 0) {
3963 nrecv++;
3964 nrecvs[field_idx]++;
3965 }
3966 if (recvcounts[i * num_src_fields + field_idx] > 0) {
3967 nsend++;
3968 nsends[field_idx]++;
3969 }
3970 }
3971 }
3972
3973 size_t total_num_msg = nsend + nrecv;
3974
3975 struct Xt_redist_msg * msgs_buffer =
3976 xmalloc(total_num_msg * sizeof(*msgs_buffer));
3977 struct Xt_redist_msg * send_msgs = msgs_buffer;
3978 struct Xt_redist_msg * recv_msgs = msgs_buffer + nsend;
3979
3980 for (size_t field_idx = 0, nsend = 0, nrecv = 0;
3981 field_idx < num_src_fields; ++field_idx) {
3982 for (int rank = 0; rank < comm_size; ++rank) {
3983 size_t idx = (size_t)rank * num_src_fields + field_idx;
3984 if (sendcounts[idx] > 0) {
3985 recv_msgs[nrecv].rank = rank;
3986 recv_msgs[nrecv].datatype =
3987 xt_mpi_generate_datatype(
3988 reorder_idx + sdispls[idx], sendcounts[idx], MPI_DOUBLE, comm);
3989 nrecv++;
3990 }
3991 if (recvcounts[idx] > 0) {
3992 send_msgs[nsend].rank = rank;
3993 send_msgs[nsend].datatype =
3994 xt_mpi_generate_datatype(
3995 recv_buffer + rdispls[idx], recvcounts[idx], MPI_DOUBLE, comm);
3996 nsend++;
3997 }
3998 }
3999 }
4000
4001 Xt_redist * redist;
4002 MPI_Comm halo_comm;
4003
4004 if (total_num_msg > 0) {
4005
4006 yac_mpi_call(MPI_Comm_split(comm, 1, 0, &halo_comm), comm);
4007
4008 int * rank_buffer = xmalloc(2 * total_num_msg * sizeof(*rank_buffer));
4009 int * orig_ranks = rank_buffer;
4010 int * split_ranks = rank_buffer + total_num_msg;
4011
4012 for (size_t i = 0; i < total_num_msg; ++i)
4013 orig_ranks[i] = msgs_buffer[i].rank;
4014
4015 MPI_Group orig_group, split_group;
4016 yac_mpi_call(MPI_Comm_group(comm, &orig_group), comm);
4017 yac_mpi_call(MPI_Comm_group(halo_comm, &split_group), comm);
4018
4020 MPI_Group_translate_ranks(orig_group, (int)total_num_msg, orig_ranks,
4021 split_group, split_ranks), halo_comm);
4022
4023 for (size_t i = 0; i < total_num_msg; ++i)
4024 msgs_buffer[i].rank = split_ranks[i];
4025
4026 free(rank_buffer);
4027
4028 yac_mpi_call(MPI_Group_free(&split_group), comm);
4029 yac_mpi_call(MPI_Group_free(&orig_group), comm);
4030
4031 // generate redist
4032 redist = xmalloc(num_src_fields * sizeof(*redist));
4033 if (num_src_fields == 1) {
4034 *redist =
4035 xt_redist_single_array_base_custom_new(
4036 nsend, nrecv, send_msgs, recv_msgs, halo_comm,
4037 redist_config);
4038 } else {
4039 for (size_t field_idx = 0; field_idx < num_src_fields; ++field_idx) {
4040 redist[field_idx] =
4041 xt_redist_single_array_base_custom_new(
4042 nsends[field_idx], nrecvs[field_idx],
4043 send_msgs, recv_msgs, halo_comm,
4044 redist_config);
4045 send_msgs += nsends[field_idx];
4046 recv_msgs += nrecvs[field_idx];
4047 }
4048 }
4049
4050 } else {
4051 yac_mpi_call(MPI_Comm_split(comm, 0, 0, &halo_comm), comm);
4052 redist = NULL;
4053 }
4054
4055 yac_mpi_call(MPI_Comm_free(&halo_comm), comm);
4056 free(exchange_buffer);
4057 yac_free_comm_buffers(sendcounts, recvcounts, sdispls, rdispls);
4058
4059 xt_redist_msg_free(msgs_buffer, total_num_msg, comm);
4060
4061 return redist;
4062}
4063
4064static int compare_rank_pos_reorder_field_idx(const void * a, const void * b) {
4065
4066 int ret = (((struct remote_point_info_reorder *)a)->field_idx >
4067 ((struct remote_point_info_reorder *)b)->field_idx) -
4068 (((struct remote_point_info_reorder *)a)->field_idx <
4069 ((struct remote_point_info_reorder *)b)->field_idx);
4070
4071 if (ret) return ret;
4072
4073 ret = ((struct remote_point_info_reorder *)a)->data.rank -
4074 ((struct remote_point_info_reorder *)b)->data.rank;
4075
4076 if (ret) return ret;
4077
4078 return (((struct remote_point_info_reorder *)a)->data.orig_pos >
4079 ((struct remote_point_info_reorder *)b)->data.orig_pos) -
4080 (((struct remote_point_info_reorder *)a)->data.orig_pos <
4081 ((struct remote_point_info_reorder *)b)->data.orig_pos);
4082}
4083
4085 const void * a, const void * b) {
4086
4087 struct interp_weight_stencil_wsum_mf * a_ =
4089 struct interp_weight_stencil_wsum_mf * b_ =
4091
4092 size_t count = MIN(a_->count, b_->count);
4093
4094 for (size_t i = 0; i < count; ++i) {
4095 int ret = (a_->data[i].src_field_idx > b_->data[i].src_field_idx) -
4096 (a_->data[i].src_field_idx < b_->data[i].src_field_idx);
4097 if (ret) return ret;
4098 ret = (a_->data[i].src.orig_pos > b_->data[i].src.orig_pos) -
4099 (a_->data[i].src.orig_pos < b_->data[i].src.orig_pos);
4100 if (ret) return ret;
4101 }
4102 return 0;
4103}
4104
4106 const void * a, const void * b) {
4107
4108 struct interp_weight_stencil_wsum_mf * a_ =
4110 struct interp_weight_stencil_wsum_mf * b_ =
4112
4113 YAC_ASSERT(
4114 (a_->tgt.data.count == 1) && (b_->tgt.data.count == 1), "invalid data")
4115
4116 size_t a_orig_pos = a_->tgt.data.data.single.orig_pos;
4117 size_t b_orig_pos = b_->tgt.data.data.single.orig_pos;
4118
4119 return (a_orig_pos > b_orig_pos) - (a_orig_pos < b_orig_pos);
4120}
4121
4122static void free_remote_point(struct remote_point point) {
4123
4124 if (point.data.count > 1) free(point.data.data.multi);
4125}
4126
4128 struct remote_point_infos * point_infos, size_t count, MPI_Comm comm,
4129 Xt_config redist_config) {
4130
4131 int comm_size;
4132 yac_mpi_call(MPI_Comm_size(comm, &comm_size), comm);
4133
4134 size_t * sendcounts, * recvcounts, * sdispls, * rdispls;
4136 1, &sendcounts, &recvcounts, &sdispls, &rdispls, comm);
4137
4138 for (size_t i = 0; i < count; ++i) {
4139 int curr_count = point_infos[i].count;
4140 struct remote_point_info * curr_point_infos =
4141 (curr_count == 1)?
4142 (&(point_infos[i].data.single)):(point_infos[i].data.multi);
4143 YAC_ASSERT(curr_count >= 1, "no owner found for global id")
4144 for (int j = 0; j < curr_count; ++j)
4145 sendcounts[curr_point_infos[j].rank]++;
4146 }
4147
4149 1, sendcounts, recvcounts, sdispls, rdispls, comm);
4150
4151 size_t send_count =
4152 sdispls[comm_size] + sendcounts[comm_size - 1];
4153 size_t recv_count =
4154 rdispls[comm_size - 1] + recvcounts[comm_size - 1];
4155
4156 int * exchange_buffer =
4157 xmalloc((2 * send_count + recv_count) * sizeof(*exchange_buffer));
4158 int * send_buffer = exchange_buffer;
4159 int * reorder_idx = exchange_buffer + send_count;
4160 int * recv_buffer = exchange_buffer + 2 * send_count;
4161
4162 // pack the original positions of the points that have to updated
4163 for (size_t i = 0; i < count; ++i) {
4164 int curr_count = point_infos[i].count;
4165 struct remote_point_info * curr_point_infos =
4166 (curr_count == 1)?
4167 (&(point_infos[i].data.single)):(point_infos[i].data.multi);
4168 for (int j = 0; j < curr_count; ++j) {
4169 size_t pos = sdispls[curr_point_infos[j].rank + 1]++;
4170 size_t orig_pos = curr_point_infos[j].orig_pos;
4171 YAC_ASSERT(orig_pos <= INT_MAX, "offset not supported by MPI")
4172 send_buffer[pos] = (int)orig_pos;
4173 reorder_idx[pos] = i;
4174 }
4175 }
4176
4177 // exchange original positions of the points that have to updated
4178 yac_alltoallv_int_p2p(
4179 send_buffer, sendcounts, sdispls, recv_buffer, recvcounts, rdispls, comm,
4180 __func__, __LINE__);
4181
4182 size_t nsend = 0;
4183 size_t nrecv = 0;
4184 for (int i = 0; i < comm_size; ++i) {
4185 if (sendcounts[i] > 0) nsend++;
4186 if (recvcounts[i] > 0) nrecv++;
4187 }
4188
4189 struct Xt_redist_msg * send_msgs = xmalloc(nsend * sizeof(*send_msgs));
4190 struct Xt_redist_msg * recv_msgs = xmalloc(nrecv * sizeof(*send_msgs));
4191
4192 for (int i = 0, nsend = 0, nrecv = 0; i < comm_size; ++i) {
4193 if (sendcounts[i] > 0) {
4194 send_msgs[nsend].rank = i;
4195 send_msgs[nsend].datatype =
4196 xt_mpi_generate_datatype(
4197 reorder_idx + sdispls[i], sendcounts[i], MPI_DOUBLE, comm);
4198 nsend++;
4199 }
4200 if (recvcounts[i] > 0) {
4201 recv_msgs[nrecv].rank = i;
4202 recv_msgs[nrecv].datatype =
4203 xt_mpi_generate_datatype(
4204 recv_buffer + rdispls[i], recvcounts[i], MPI_DOUBLE, comm);
4205 nrecv++;
4206 }
4207 }
4208
4209 // generate redist
4210 Xt_redist redist =
4211 xt_redist_single_array_base_custom_new(
4212 nsend, nrecv, send_msgs, recv_msgs, comm, redist_config);
4213
4214 free(exchange_buffer);
4215 yac_free_comm_buffers(sendcounts, recvcounts, sdispls, rdispls);
4216
4217 xt_redist_msg_free(recv_msgs, nrecv, comm);
4218 xt_redist_msg_free(send_msgs, nsend, comm);
4219
4220 return redist;
4221}
4222
4224 struct remote_point_info_reorder * remote_src_points, size_t halo_size,
4225 size_t num_src_fields, size_t tgt_count,
4226 struct interp_weight_stencil_wsum_mf * tgt_stencils, size_t * num_src_per_tgt,
4227 double * weights, size_t * src_idx, size_t * src_field_idx, MPI_Comm comm,
4229 struct yac_interpolation * interp,
4230 void (*interp_add_wsum_mf_at_src)(
4231 struct yac_interpolation *, Xt_redist *, size_t, size_t *, double *,
4232 size_t *, size_t *, size_t, Xt_redist),
4233 void (*interp_add_wsum_mf_at_tgt)(
4234 struct yac_interpolation *, Xt_redist *, size_t *, size_t, size_t *, double *,
4235 size_t *, size_t *, size_t), Xt_config redist_config) {
4236
4237 // generate halo redists (one per source field)
4238 Xt_redist * halo_redists =
4240 remote_src_points, halo_size, num_src_fields, comm, redist_config);
4241
4242 // add weights to interpolation
4243 if (reorder == YAC_MAPPING_ON_SRC) {
4244
4245 // generate result redist
4246 struct remote_point_infos * tgt_infos =
4247 xmalloc(tgt_count * sizeof(*tgt_infos));
4248 for (size_t i = 0; i < tgt_count; ++i)
4249 tgt_infos[i] = tgt_stencils[i].tgt.data;
4250 Xt_redist result_redist =
4252 tgt_infos, tgt_count, comm, redist_config);
4253 free(tgt_infos);
4254
4255 interp_add_wsum_mf_at_src(
4256 interp, halo_redists, tgt_count, num_src_per_tgt, weights,
4257 src_field_idx, src_idx, num_src_fields, result_redist);
4258
4259 if (result_redist != NULL) xt_redist_delete(result_redist);
4260
4261 } else {
4262
4263 size_t * tgt_orig_pos = xmalloc(tgt_count * sizeof(*tgt_orig_pos));
4264 for (size_t i = 0; i < tgt_count; ++i) {
4265 YAC_ASSERT(
4266 tgt_stencils[i].tgt.data.count == 1,
4267 "currently unsupported target point distribution")
4268 tgt_orig_pos[i] =
4269 (size_t)(tgt_stencils[i].tgt.data.data.single.orig_pos);
4270 }
4271
4272 interp_add_wsum_mf_at_tgt(
4273 interp, halo_redists, tgt_orig_pos, tgt_count,
4274 num_src_per_tgt, weights, src_field_idx, src_idx, num_src_fields);
4275 free(tgt_orig_pos);
4276
4277 }
4278
4279 if (halo_redists != NULL) {
4280 for (size_t i = 0; i < num_src_fields; ++i)
4281 xt_redist_delete(halo_redists[i]);
4282 free(halo_redists);
4283 }
4284}
4285
4287 struct yac_interpolation * interp, Xt_redist * halo_redists,
4288 size_t tgt_count, size_t * num_src_per_tgt, double * weights,
4289 size_t * src_field_idx, size_t * src_idx,
4290 size_t num_src_fields, Xt_redist result_redist) {
4291
4292 UNUSED(weights);
4293
4295 interp, halo_redists, tgt_count, num_src_per_tgt, src_field_idx,
4296 src_idx, num_src_fields, result_redist);
4297}
4298
4300 struct yac_interpolation * interp, Xt_redist * src_redists,
4301 size_t * tgt_pos, size_t tgt_count, size_t * num_src_per_tgt,
4302 double * weights, size_t * src_field_idx, size_t * src_idx,
4303 size_t num_src_fields) {
4304
4305 UNUSED(weights);
4306
4308 interp, src_redists, tgt_pos, tgt_count, num_src_per_tgt,
4309 src_field_idx, src_idx, num_src_fields);
4310}
4311
4313 struct remote_point_info_reorder * remote_src_points, size_t halo_size,
4314 size_t num_src_fields, size_t tgt_count,
4315 struct interp_weight_stencil_wsum_mf * tgt_stencils, size_t * num_src_per_tgt,
4316 double * weights, size_t * src_idx, size_t * src_field_idx, MPI_Comm comm,
4317 enum yac_interp_weights_reorder_type reorder, void * interp,
4318 Xt_config redist_config) {
4319
4321 remote_src_points, halo_size, num_src_fields, tgt_count, tgt_stencils,
4322 num_src_per_tgt, weights, src_idx, src_field_idx, comm, reorder,
4323 (struct yac_interpolation *) interp,
4325 redist_config);
4326}
4327
4329 struct remote_point_info_reorder * remote_src_points, size_t halo_size,
4330 size_t num_src_fields, size_t tgt_count,
4331 struct interp_weight_stencil_wsum_mf * tgt_stencils, size_t * num_src_per_tgt,
4332 double * weights, size_t * src_idx, size_t * src_field_idx, MPI_Comm comm,
4333 enum yac_interp_weights_reorder_type reorder, void * interp,
4334 Xt_config redist_config) {
4335
4336 UNUSED(num_src_fields);
4337
4339 remote_src_points, halo_size, 1, tgt_count, tgt_stencils, num_src_per_tgt,
4340 weights, src_idx, src_field_idx, comm, reorder, interp, redist_config);
4341}
4342
4344 struct remote_point_info_reorder * remote_src_points, size_t halo_size,
4345 size_t num_src_fields, size_t tgt_count,
4346 struct interp_weight_stencil_wsum_mf * tgt_stencils, size_t * num_src_per_tgt,
4347 double * weights, size_t * src_idx, size_t * src_field_idx, MPI_Comm comm,
4348 enum yac_interp_weights_reorder_type reorder, void * interp,
4349 Xt_config redist_config) {
4350
4352 remote_src_points, halo_size, num_src_fields, tgt_count, tgt_stencils,
4353 num_src_per_tgt, weights, src_idx, src_field_idx, comm, reorder,
4354 (struct yac_interpolation *) interp,
4357}
4358
4360 struct remote_point_info_reorder * remote_src_points, size_t halo_size,
4361 size_t num_src_fields, size_t tgt_count,
4362 struct interp_weight_stencil_wsum_mf * tgt_stencils, size_t * num_src_per_tgt,
4363 double * weights, size_t * src_idx, size_t * src_field_idx, MPI_Comm comm,
4364 enum yac_interp_weights_reorder_type reorder, void * interp,
4365 Xt_config redist_config) {
4366
4367 UNUSED(num_src_fields);
4368
4370 remote_src_points, halo_size, 1, tgt_count, tgt_stencils, num_src_per_tgt,
4371 weights, src_idx, src_field_idx, comm, reorder, interp, redist_config);
4372}
4373
4375 MPI_Comm comm, struct interp_weight_stencils_wsum_mf * wsum_mf_stencils_data,
4376 struct yac_interpolation * interp,
4378 void (*interp_add_w_sum_mf)(
4379 struct remote_point_info_reorder *, size_t, size_t, size_t,
4380 struct interp_weight_stencil_wsum_mf *, size_t *, double *, size_t *,
4381 size_t *, MPI_Comm, enum yac_interp_weights_reorder_type, void *,
4382 Xt_config), Xt_config redist_config) {
4383
4384 int comm_rank;
4385 yac_mpi_call(MPI_Comm_rank(comm, &comm_rank), comm);
4386
4387 // redistribute stencils to respective owners
4388 struct interp_weight_stencils_wsum_mf * (*redist_wsum_mf_stencils)(
4389 MPI_Comm comm, struct interp_weight_stencils_wsum_mf * wsum_mf_stencils_data);
4390 YAC_ASSERT(
4391 (reorder == YAC_MAPPING_ON_SRC) || (reorder == YAC_MAPPING_ON_TGT),
4392 "invalid reorder type")
4394 (reorder == YAC_MAPPING_ON_SRC)?
4396 struct interp_weight_stencils_wsum_mf * new_wsum_mf_stencils_data =
4397 redist_wsum_mf_stencils(comm, wsum_mf_stencils_data);
4398
4399 size_t wsum_mf_count = new_wsum_mf_stencils_data->count;
4400 struct interp_weight_stencil_wsum_mf * wsum_mf_stencils =
4401 new_wsum_mf_stencils_data->data;
4402
4403 // compute the total number of links
4404 size_t total_num_links = 0, total_num_remote_weights = 0;
4405 for (size_t i = 0; i < wsum_mf_count; ++i) {
4406 size_t curr_stencil_size = wsum_mf_stencils[i].count;
4407 total_num_links += curr_stencil_size;
4408 for (size_t j = 0; j < curr_stencil_size; ++j)
4409 if (wsum_mf_stencils[i].data[j].src.rank != comm_rank)
4410 ++total_num_remote_weights;
4411 }
4412
4413 // gather all remote source points and determine number of source fields
4414 struct remote_point_info_reorder * remote_src_points =
4415 xmalloc(total_num_remote_weights * sizeof(*remote_src_points));
4416 size_t num_src_fields = 0;
4417 for (size_t i = 0, k = 0; i < wsum_mf_count; ++i) {
4418 size_t curr_stencil_size = wsum_mf_stencils[i].count;
4419 struct interp_weight_stencil_wsum_mf_weight * curr_weights =
4420 wsum_mf_stencils[i].data;
4421 for (size_t j = 0; j < curr_stencil_size; ++j) {
4422 size_t curr_src_field_idx = curr_weights[j].src_field_idx;
4423 if (curr_src_field_idx >= num_src_fields)
4424 num_src_fields = curr_src_field_idx + 1;
4425 if (curr_weights[j].src.rank != comm_rank) {
4426 remote_src_points[k].data = curr_weights[j].src;
4427 remote_src_points[k].field_idx = curr_src_field_idx;
4428 remote_src_points[k].reorder_idx = i;
4429 ++k;
4430 }
4431 }
4432 }
4434 MPI_Allreduce(
4435 MPI_IN_PLACE, &num_src_fields, 1, YAC_MPI_SIZE_T, MPI_MAX, comm), comm);
4436
4437 // sort remote points first by field_idx, second by rank, and
4438 // then by orig_pos
4439 qsort(remote_src_points, total_num_remote_weights, sizeof(*remote_src_points),
4441
4442 // update stencils: set owner to -1; set orig_pos to position of respecitve
4443 // point in halo data
4444 // remove duplicated remote points
4445 struct remote_point_info * prev_remote_src_point;
4446 size_t prev_field_idx;
4447 size_t halo_size;
4448 if (total_num_remote_weights > 0) {
4449 prev_remote_src_point = &(remote_src_points[0].data);
4450 prev_field_idx = remote_src_points[0].field_idx;
4451 halo_size = 1;
4452 } else {
4453 prev_field_idx = SIZE_MAX;
4454 halo_size = 0;
4455 }
4456 for (size_t i = 0; i < total_num_remote_weights; ++i) {
4457 struct remote_point_info * curr_remote_src_point =
4458 &(remote_src_points[i].data);
4459 size_t curr_field_idx = remote_src_points[i].field_idx;
4461 prev_remote_src_point, curr_remote_src_point) ||
4462 (prev_field_idx != curr_field_idx)) {
4463 prev_remote_src_point = curr_remote_src_point;
4464 prev_field_idx = curr_field_idx;
4465 remote_src_points[halo_size].data = *curr_remote_src_point;
4466 remote_src_points[halo_size].field_idx = curr_field_idx;
4467 ++halo_size;
4468 }
4469 struct interp_weight_stencil_wsum_mf * curr_stencil =
4470 wsum_mf_stencils + remote_src_points[i].reorder_idx;
4471 size_t curr_stencil_size = curr_stencil->count;
4472 for (size_t j = 0; j < curr_stencil_size; ++j) {
4474 &(curr_stencil->data[j].src), curr_remote_src_point)) &&
4475 (curr_stencil->data[j].src_field_idx == curr_field_idx)) {
4476 curr_stencil->data[j].src.rank = -1;
4477 curr_stencil->data[j].src.orig_pos = halo_size - 1;
4478 curr_stencil->data[j].src_field_idx = SIZE_MAX;
4479 }
4480 }
4481 }
4482
4483 // sort stencils by their memory access pattern on the local process
4484 qsort(wsum_mf_stencils, wsum_mf_count, sizeof(*wsum_mf_stencils),
4485 (reorder == YAC_MAPPING_ON_SRC)?
4488
4489 size_t * num_src_per_tgt = xmalloc(wsum_mf_count * sizeof(*num_src_per_tgt));
4490 double * weights = xmalloc(total_num_links * sizeof(*weights));
4491 size_t * src_idx = xmalloc(total_num_links * sizeof(*src_idx));
4492 size_t * src_field_idx = xmalloc(total_num_links * sizeof(*src_field_idx));
4493
4494 // extract data from stencil
4495 for (size_t i = 0, k = 0; i < wsum_mf_count; ++i) {
4496 size_t curr_stencil_size = wsum_mf_stencils[i].count;
4497 struct interp_weight_stencil_wsum_mf_weight * curr_weights =
4498 wsum_mf_stencils[i].data;
4499 num_src_per_tgt[i] = curr_stencil_size;
4500 for (size_t j = 0; j < curr_stencil_size; ++j, ++k){
4501 weights[k] = curr_weights[j].weight;
4502 src_idx[k] = curr_weights[j].src.orig_pos;
4503 src_field_idx[k] = curr_weights[j].src_field_idx;
4504 }
4505 }
4506
4507 // add data to interpolation
4508 interp_add_w_sum_mf(
4509 remote_src_points, halo_size, num_src_fields, wsum_mf_count,
4510 wsum_mf_stencils, num_src_per_tgt, weights, src_idx, src_field_idx,
4511 comm, reorder, interp, redist_config);
4512
4513 for (size_t i = 0; i < new_wsum_mf_stencils_data->count; ++i)
4514 free_remote_point(new_wsum_mf_stencils_data->data[i].tgt);
4515 free(new_wsum_mf_stencils_data->data);
4516 free(new_wsum_mf_stencils_data);
4517
4518 free(remote_src_points);
4519 free(src_field_idx);
4520 free(src_idx);
4521 free(weights);
4522 free(num_src_per_tgt);
4523}
4524
4526 MPI_Comm comm, struct interp_weight_stencils_wsum_mf * wsum_mf_stencils_data,
4527 struct yac_interpolation * interp,
4528 void (*interp_add_w_sum_mf)(
4529 struct remote_point_info_reorder *, size_t, size_t, size_t,
4530 struct interp_weight_stencil_wsum_mf *, size_t *, double *, size_t *,
4531 size_t *, MPI_Comm, void *,
4532 Xt_config), Xt_config redist_config) {
4533
4534 int comm_rank;
4535 yac_mpi_call(MPI_Comm_rank(comm, &comm_rank), comm);
4536
4537 // redistribute stencils to respective owners
4538 struct interp_weight_stencils_wsum_mf * new_wsum_mf_stencils_data =
4539 redist_wsum_mf_stencils_tgt(comm, wsum_mf_stencils_data);
4540
4541 size_t wsum_mf_count = new_wsum_mf_stencils_data->count;
4542 struct interp_weight_stencil_wsum_mf * wsum_mf_stencils =
4543 new_wsum_mf_stencils_data->data;
4544
4545 // compute the total number of links
4546 size_t total_num_links = 0;
4547 for (size_t i = 0; i < wsum_mf_count; ++i)
4548 total_num_links += wsum_mf_stencils[i].count;
4549
4550 // gather all source points and determine number of source fields
4551 struct remote_point_info_reorder * src_points =
4552 xmalloc(total_num_links * sizeof(*src_points));
4553 size_t num_src_fields = 0;
4554 for (size_t i = 0, k = 0; i < wsum_mf_count; ++i) {
4555 size_t curr_stencil_size = wsum_mf_stencils[i].count;
4556 struct interp_weight_stencil_wsum_mf_weight * curr_weights =
4557 wsum_mf_stencils[i].data;
4558 for (size_t j = 0; j < curr_stencil_size; ++j, ++k) {
4559 size_t curr_src_field_idx = curr_weights[j].src_field_idx;
4560 if (curr_src_field_idx >= num_src_fields)
4561 num_src_fields = curr_src_field_idx + 1;
4562 src_points[k].data = curr_weights[j].src;
4563 src_points[k].field_idx = curr_src_field_idx;
4564 src_points[k].reorder_idx = i;
4565 }
4566 }
4568 MPI_Allreduce(
4569 MPI_IN_PLACE, &num_src_fields, 1, YAC_MPI_SIZE_T, MPI_MAX, comm), comm);
4570
4571 // sort remote points first by field_idx, second by rank, and
4572 // then by orig_pos
4573 qsort(src_points, total_num_links, sizeof(*src_points),
4575
4576 // update stencils: set owner to -1; set orig_pos to position of respecitve
4577 // point in source field buffer
4578 // remove duplicated remote points
4579 struct remote_point_info * prev_src_point;
4580 size_t prev_field_idx;
4581 size_t num_src_points = 0;
4582 size_t src_field_buffer_size[num_src_fields];
4583 memset(
4584 src_field_buffer_size, 0,
4585 num_src_fields * sizeof(src_field_buffer_size[0]));
4586
4587 if (total_num_links > 0) {
4588 prev_src_point = &(src_points[0].data);
4589 prev_field_idx = src_points[0].field_idx;
4590 src_field_buffer_size[src_points[0].field_idx] = 1;
4591 num_src_points = 1;
4592 }
4593 for (size_t i = 0; i < total_num_links; ++i) {
4594 struct remote_point_info * curr_src_point = &(src_points[i].data);
4595 size_t curr_field_idx = src_points[i].field_idx;
4596 if (compare_remote_point_info(prev_src_point, curr_src_point) ||
4597 (prev_field_idx != curr_field_idx)) {
4598 prev_src_point = curr_src_point;
4599 prev_field_idx = curr_field_idx;
4600 if (num_src_points != i) {
4601 src_points[num_src_points].data = *curr_src_point;
4602 src_points[num_src_points].field_idx = curr_field_idx;
4603 }
4604 src_field_buffer_size[curr_field_idx]++;
4605 num_src_points++;
4606 }
4607 struct interp_weight_stencil_wsum_mf * curr_stencil =
4608 wsum_mf_stencils + src_points[i].reorder_idx;
4609 size_t curr_stencil_size = curr_stencil->count;
4610 for (size_t j = 0; j < curr_stencil_size; ++j) {
4612 &(curr_stencil->data[j].src), curr_src_point)) &&
4613 (curr_stencil->data[j].src_field_idx == curr_field_idx)) {
4614 curr_stencil->data[j].src.rank = -1;
4615 curr_stencil->data[j].src.orig_pos =
4616 src_field_buffer_size[curr_field_idx] - 1;
4617 }
4618 }
4619 }
4620
4621 // sort stencils by their memory access pattern on the local process
4622 qsort(wsum_mf_stencils, wsum_mf_count, sizeof(*wsum_mf_stencils),
4624
4625 size_t * num_src_per_tgt = xmalloc(wsum_mf_count * sizeof(*num_src_per_tgt));
4626 double * weights = xmalloc(total_num_links * sizeof(*weights));
4627 size_t * src_idx = xmalloc(total_num_links * sizeof(*src_idx));
4628 size_t * src_field_idx = xmalloc(total_num_links * sizeof(*src_field_idx));
4629
4630 // extract data from stencil
4631 for (size_t i = 0, k = 0; i < wsum_mf_count; ++i) {
4632 size_t curr_stencil_size = wsum_mf_stencils[i].count;
4633 struct interp_weight_stencil_wsum_mf_weight * curr_weights =
4634 wsum_mf_stencils[i].data;
4635 num_src_per_tgt[i] = curr_stencil_size;
4636 for (size_t j = 0; j < curr_stencil_size; ++j, ++k){
4637 weights[k] = curr_weights[j].weight;
4638 src_idx[k] = curr_weights[j].src.orig_pos;
4639 src_field_idx[k] = curr_weights[j].src_field_idx;
4640 }
4641 }
4642
4643 // add data to interpolation
4644 interp_add_w_sum_mf(
4645 src_points, num_src_points, num_src_fields, wsum_mf_count,
4646 wsum_mf_stencils, num_src_per_tgt, weights, src_idx, src_field_idx,
4647 comm, interp, redist_config);
4648
4649 for (size_t i = 0; i < new_wsum_mf_stencils_data->count; ++i)
4650 free_remote_point(new_wsum_mf_stencils_data->data[i].tgt);
4651 free(new_wsum_mf_stencils_data->data);
4652 free(new_wsum_mf_stencils_data);
4653
4654 free(src_points);
4655 free(src_field_idx);
4656 free(src_idx);
4657 free(weights);
4658 free(num_src_per_tgt);
4659}
4660
4661static int compare_stencils(const void * a, const void * b) {
4662
4663 return (int)(((struct interp_weight_stencil *)a)->type) -
4664 (int)(((struct interp_weight_stencil *)b)->type);
4665}
4666
4667static Xt_config get_redist_config(
4668 char const * yaxt_exchanger_name, MPI_Comm comm) {
4669
4670 Xt_config redist_config = xt_config_new();
4671
4672 // if no exchanger has been defined yet -> check environment
4673 char * env_exchanger_name = NULL;
4674 if (yaxt_exchanger_name == NULL) {
4675
4676 int rank;
4677 yac_mpi_call(MPI_Comm_rank(comm, &rank), comm);
4678
4679 // environment is only checked on rank 0, results are broadcasted
4680 // to other processes
4681 size_t exchanger_name_len = 0;
4682 if (rank == 0) {
4683
4684 // check if the user provided an exchanger name in the environment
4685 env_exchanger_name = getenv(YAC_YAXT_EXCHANGER_STR);
4686 exchanger_name_len =
4687 ((env_exchanger_name != NULL) && (env_exchanger_name[0] != '\0'))?
4688 strlen(env_exchanger_name):0;
4689 }
4690
4691 // broadcast the length of the exchanger name provided by the user
4692 // through the environment
4694 MPI_Bcast(&exchanger_name_len, 1, YAC_MPI_SIZE_T, 0, comm), comm);
4695
4696 if (exchanger_name_len > 0) {
4697
4698 if (rank == 0)
4699 env_exchanger_name = xstrdup(env_exchanger_name);
4700 else
4701 env_exchanger_name =
4702 xmalloc((exchanger_name_len + 1) * sizeof(*env_exchanger_name));
4703
4704 // broadcast name of the exchanger
4706 MPI_Bcast(
4707 env_exchanger_name, (int)(exchanger_name_len + 1), MPI_CHAR, 0, comm),
4708 comm);
4709
4710 yaxt_exchanger_name = env_exchanger_name;
4711 }
4712 }
4713
4714 if (yaxt_exchanger_name != NULL) {
4715
4716 // set exchanger
4717 int exchanger_id = xt_exchanger_id_by_name(yaxt_exchanger_name);
4719 exchanger_id >= 0, "invalid yaxt exchanger name \"%s\"",
4720 yaxt_exchanger_name);
4721 xt_config_set_exchange_method(redist_config, exchanger_id);
4722 }
4723
4724 free(env_exchanger_name);
4725
4726 return redist_config;
4727}
4728
4730 struct yac_interp_weights const * weights,
4734 double scaling_factor, double scaling_summand,
4735 char const * yaxt_exchanger_name, int is_source, int is_target) {
4736
4737 struct yac_interpolation * interp =
4740 scaling_factor, scaling_summand);
4741
4742 MPI_Comm comm = weights->comm;
4743 int comm_size;
4744 yac_mpi_call(MPI_Comm_size(comm, &comm_size), comm);
4745 int * flag_buffer = xmalloc(2 * (size_t)comm_size * sizeof(*flag_buffer));
4746 int * rank_is_source = flag_buffer;
4747 int * rank_is_target = flag_buffer + comm_size;
4749 MPI_Allgather(&is_source, 1, MPI_INT, rank_is_source, 1, MPI_INT, comm),
4750 comm);
4752 MPI_Allgather(&is_target, 1, MPI_INT, rank_is_target, 1, MPI_INT, comm),
4753 comm);
4754
4755 Xt_config redist_config = get_redist_config(yaxt_exchanger_name, comm);
4756
4757 // sort stencils by type
4758 qsort(weights->stencils, weights->stencils_size, sizeof(*(weights->stencils)),
4760
4761 size_t local_stencil_counts[WEIGHT_STENCIL_TYPE_SIZE];
4762 size_t stencils_offsets[WEIGHT_STENCIL_TYPE_SIZE];
4763
4764 // count local number of stencils per type
4765 memset(&(local_stencil_counts[0]), 0, sizeof(local_stencil_counts));
4766 for (size_t i = 0; i < weights->stencils_size; ++i)
4767 local_stencil_counts[(int)(weights->stencils[i].type)]++;
4768
4769 for (size_t i = 0, accu = 0; i < (size_t)WEIGHT_STENCIL_TYPE_SIZE; ++i) {
4770 stencils_offsets[i] = accu;
4771 accu += local_stencil_counts[i];
4772 }
4773
4774 size_t global_stencil_counts[WEIGHT_STENCIL_TYPE_SIZE];
4775
4776 // determine global number of stencils per type
4778 MPI_Allreduce(
4779 local_stencil_counts, global_stencil_counts,
4780 (int)WEIGHT_STENCIL_TYPE_SIZE, YAC_MPI_SIZE_T, MPI_SUM, comm), comm);
4781
4782 { // check whether the collection_size is consistant across all processes
4783 size_t local_collection_size =
4785 size_t max_collection_size;
4787 MPI_Allreduce(
4788 &local_collection_size, &max_collection_size, 1, YAC_MPI_SIZE_T,
4789 MPI_MAX, comm), comm);
4790 YAC_ASSERT(
4791 (size_t)max_collection_size == local_collection_size,
4792 "mismatching collection sizes")
4793 }
4794
4795 if (global_stencil_counts[FIXED] > 0)
4797 weights->comm, local_stencil_counts[FIXED],
4798 weights->stencils + stencils_offsets[FIXED],
4799 (void*)interp, interp_add_fixed, rank_is_target);
4800
4801 if (global_stencil_counts[DIRECT] > 0)
4803 weights->comm, local_stencil_counts[DIRECT],
4804 weights->stencils + stencils_offsets[DIRECT], interp, interp_add_direct,
4805 redist_config, rank_is_source, rank_is_target);
4806
4807 if (global_stencil_counts[SUM] > 0) {
4808
4809 struct interp_weight_stencils_wsum_mf * wsum_stencils =
4811 weights->stencils + stencils_offsets[SUM],
4812 (size_t)(local_stencil_counts[SUM]), SUM,
4813 rank_is_source, rank_is_target);
4815 weights->comm, wsum_stencils, interp, reorder,
4816 interpolation_add_sum, redist_config);
4817 for (size_t i = 0; i < wsum_stencils->count; ++i)
4818 free_remote_point(wsum_stencils->data[i].tgt);
4819 free(wsum_stencils->data);
4820 free(wsum_stencils);
4821 }
4822
4823 if (global_stencil_counts[WEIGHT_SUM] > 0) {
4824
4825 struct interp_weight_stencils_wsum_mf * wsum_stencils =
4827 weights->stencils + stencils_offsets[WEIGHT_SUM],
4828 (size_t)(local_stencil_counts[WEIGHT_SUM]), WEIGHT_SUM,
4829 rank_is_source, rank_is_target);
4831 weights->comm, wsum_stencils, interp, reorder,
4832 interpolation_add_wsum, redist_config);
4833 for (size_t i = 0; i < wsum_stencils->count; ++i)
4834 free_remote_point(wsum_stencils->data[i].tgt);
4835 free(wsum_stencils->data);
4836 free(wsum_stencils);
4837 }
4838
4839 if (global_stencil_counts[DIRECT_MF] > 0)
4841 weights->comm, local_stencil_counts[DIRECT_MF],
4842 weights->stencils + stencils_offsets[DIRECT_MF],
4843 interp, interp_add_direct_mf, redist_config,
4844 rank_is_source, rank_is_target);
4845
4846 if (global_stencil_counts[SUM_MF] > 0) {
4847
4848 struct interp_weight_stencils_wsum_mf * sum_mf_stencils =
4850 weights->stencils + stencils_offsets[SUM_MF],
4851 (size_t)(local_stencil_counts[SUM_MF]), SUM_MF,
4852 rank_is_source, rank_is_target);
4854 weights->comm, sum_mf_stencils, interp, reorder,
4855 interpolation_add_sum_mf, redist_config);
4856 for (size_t i = 0; i < sum_mf_stencils->count; ++i)
4857 free_remote_point(sum_mf_stencils->data[i].tgt);
4858 free(sum_mf_stencils->data);
4859 free(sum_mf_stencils);
4860 }
4861
4862 if (global_stencil_counts[WEIGHT_SUM_MF] > 0) {
4863
4864 struct interp_weight_stencils_wsum_mf * wsum_mf_stencils =
4866 weights->stencils + stencils_offsets[WEIGHT_SUM_MF],
4867 (size_t)(local_stencil_counts[WEIGHT_SUM_MF]), WEIGHT_SUM_MF,
4868 rank_is_source, rank_is_target);
4870 weights->comm, wsum_mf_stencils, interp, reorder,
4871 interpolation_add_wsum_mf, redist_config);
4872 for (size_t i = 0; i < wsum_mf_stencils->count; ++i)
4873 free_remote_point(wsum_mf_stencils->data[i].tgt);
4874 free(wsum_mf_stencils->data);
4875 free(wsum_mf_stencils);
4876 }
4877
4878 free(flag_buffer);
4879
4880 xt_config_delete(redist_config);
4881
4882 return interp;
4883}
4884
4886 struct yac_interp_weights * weights,
4889 double scaling_factor, double scaling_summand,
4890 char const * yaxt_exchanger_name, int is_source, int is_target) {
4891
4892 struct yac_collection_selection * collection_selection =
4894
4895 struct yac_interpolation * interpolation =
4898 scaling_factor, scaling_summand, yaxt_exchanger_name,
4900
4902
4903 return interpolation;
4904}
4905
4922
4924 struct yac_src_field_exchange_data * src_field_exchange_data,
4925 size_t num_src_fields, MPI_Comm comm,
4926 Xt_config redist_config) {
4927
4928 int comm_size;
4929 yac_mpi_call(MPI_Comm_size(comm, &comm_size), comm);
4930
4931 size_t nsends[num_src_fields], nrecvs[num_src_fields];
4932 int max_recv_buffer_size = 0;
4933 for (size_t i = 0; i < num_src_fields; ++i) {
4934 nsends[i] = src_field_exchange_data[i].send.num_msg;
4935 nrecvs[i] = src_field_exchange_data[i].recv.num_msg;
4936 for (size_t j = 0; j < src_field_exchange_data[i].recv.num_msg; ++j) {
4937 if (max_recv_buffer_size < src_field_exchange_data[i].recv.msg[j].count)
4938 max_recv_buffer_size = src_field_exchange_data[i].recv.msg[j].count;
4939 }
4940 }
4941
4942 size_t nsend = 0, nrecv = 0;
4943 size_t send_offsets[num_src_fields];
4944 size_t recv_offsets[num_src_fields];
4945 for (size_t i = 0; i < num_src_fields; ++i) {
4946 send_offsets[i] = nsend;
4947 recv_offsets[i] = nrecv;
4948 nsend += nsends[i];
4949 nrecv += nrecvs[i];
4950 }
4951
4952 size_t total_num_msg = nsend + nrecv;
4953
4954 struct Xt_redist_msg * msgs_buffer =
4955 xmalloc(total_num_msg * sizeof(*msgs_buffer));
4956 struct Xt_redist_msg * send_msgs = msgs_buffer;
4957 struct Xt_redist_msg * recv_msgs = msgs_buffer + nsend;
4958
4959 int * pos_buffer =
4960 xmalloc((size_t)max_recv_buffer_size * sizeof(*pos_buffer));
4961
4962 // generate yaxt send and receive messages
4963 for (size_t src_field_idx = 0; src_field_idx < num_src_fields;
4964 ++src_field_idx) {
4965
4966 for (size_t send_idx = 0;
4967 send_idx < src_field_exchange_data[src_field_idx].send.num_msg;
4968 ++send_idx) {
4969 send_msgs[send_offsets[src_field_idx]].rank =
4970 src_field_exchange_data[src_field_idx].send.msg[send_idx].rank;
4971 send_msgs[send_offsets[src_field_idx]].datatype =
4972 xt_mpi_generate_datatype(
4973 src_field_exchange_data[src_field_idx].send.msg[send_idx].pos,
4974 src_field_exchange_data[src_field_idx].send.msg[send_idx].count,
4975 MPI_DOUBLE, comm);
4976 send_offsets[src_field_idx]++;
4977 }
4978
4979 for (size_t recv_idx = 0;
4980 recv_idx < src_field_exchange_data[src_field_idx].recv.num_msg;
4981 ++recv_idx) {
4982 int count = 0;
4983 for (int i = 0;
4984 i < src_field_exchange_data[src_field_idx].recv.msg[recv_idx].count;
4985 ++i, ++count)
4986 pos_buffer[count] =
4987 src_field_exchange_data[src_field_idx].recv.msg[recv_idx].pos[i];
4988
4989 recv_msgs[recv_offsets[src_field_idx]].rank =
4990 src_field_exchange_data[src_field_idx].recv.msg[recv_idx].rank;
4991 recv_msgs[recv_offsets[src_field_idx]].datatype =
4992 xt_mpi_generate_datatype(pos_buffer, count, MPI_DOUBLE, comm);
4993 recv_offsets[src_field_idx]++;
4994 }
4995 }
4996
4997 free(pos_buffer);
4998
4999 Xt_redist * redists;
5000 MPI_Comm split_comm;
5001
5002 // only processes that have to sent/receive data are included in the redist,
5003 // the others receive a dummy redist
5004 if (total_num_msg > 0) {
5005
5006 // generate MPI communicator containing all ranks taking part in the
5007 // exchange
5008 yac_mpi_call(MPI_Comm_split(comm, 1, 0, &split_comm), comm);
5009
5010 int * rank_buffer =
5011 xmalloc(2 * total_num_msg * sizeof(*rank_buffer));
5012 int * orig_ranks = rank_buffer;
5013 int * split_ranks = rank_buffer + total_num_msg;
5014
5015 for (size_t i = 0; i < total_num_msg; ++i)
5016 orig_ranks[i] = msgs_buffer[i].rank;
5017
5018 MPI_Group orig_group, split_group;
5019 yac_mpi_call(MPI_Comm_group(comm, &orig_group), comm);
5020 yac_mpi_call(MPI_Comm_group(split_comm, &split_group), comm);
5021
5022 // translate the ranks in the sent/receive messages to ones in the
5023 // split comm
5025 MPI_Group_translate_ranks(orig_group, total_num_msg, orig_ranks,
5026 split_group, split_ranks), split_comm);
5027
5028 for (size_t i = 0; i < total_num_msg; ++i)
5029 msgs_buffer[i].rank = split_ranks[i];
5030
5031 free(rank_buffer);
5032
5033 yac_mpi_call(MPI_Group_free(&split_group), comm);
5034 yac_mpi_call(MPI_Group_free(&orig_group), comm);
5035
5036 // generate redists
5037 redists = xmalloc(num_src_fields * sizeof(*redists));
5038 for (size_t src_field_idx = 0; src_field_idx < num_src_fields;
5039 ++src_field_idx) {
5040 redists[src_field_idx] =
5041 xt_redist_single_array_base_custom_new(
5042 nsends[src_field_idx], nrecvs[src_field_idx],
5043 send_msgs, recv_msgs, split_comm, redist_config);
5044 send_msgs += nsends[src_field_idx];
5045 recv_msgs += nrecvs[src_field_idx];
5046 }
5047
5048 } else {
5049 yac_mpi_call(MPI_Comm_split(comm, 0, 0, &split_comm), comm);
5050 redists = NULL;
5051 }
5052
5053 yac_mpi_call(MPI_Comm_free(&split_comm), comm);
5054 xt_redist_msg_free(msgs_buffer, total_num_msg, comm);
5055
5056 return redists;
5057}
5058
5060 double frac_mask_fallback_value, double scaling_factor,
5061 double scaling_summand,
5063
5064 interp_weights_data->frac_mask_fallback_value = frac_mask_fallback_value;
5065 interp_weights_data->scaling_factor = scaling_factor;
5066 interp_weights_data->scaling_summand = scaling_summand;
5067
5072
5080 interp_weights_data->src_field_buffer_size = NULL;
5081}
5082
5084 struct yac_src_field_exchange_data * src_field_exchange_data,
5085 size_t num_src_fields) {
5086
5087 for (size_t i = 0; i < num_src_fields; ++i) {
5088 for (size_t j = 0; j < src_field_exchange_data[i].send.num_msg; ++j)
5089 free(src_field_exchange_data[i].send.msg[j].pos);
5090 free(src_field_exchange_data[i].send.msg);
5091 for (size_t j = 0; j < src_field_exchange_data[i].recv.num_msg; ++j)
5092 free(src_field_exchange_data[i].recv.msg[j].pos);
5093 free(src_field_exchange_data[i].recv.msg);
5094 }
5095
5096 free(src_field_exchange_data);
5097}
5098
5100 struct remote_point_info_reorder * remote_src_points, size_t num_src_points,
5101 size_t num_src_fields, size_t tgt_count,
5102 struct interp_weight_stencil_wsum_mf * tgt_stencils, size_t * num_src_per_tgt,
5103 double * weights, size_t * src_idx, size_t * src_field_idx, MPI_Comm comm,
5104 struct yac_interpolation_raw * interp_raw, Xt_config redist_config) {
5105
5106 UNUSED(redist_config);
5107
5108 int comm_size;
5109 yac_mpi_call(MPI_Comm_size(comm, &comm_size), comm);
5110
5111 yac_src_field_exchange_data_realloc(interp_raw, num_src_fields);
5112
5113 // generate exchange information from remote_src_points
5114
5115 size_t * sendcounts, * recvcounts, * sdispls, *rdispls;
5117 num_src_fields, &sendcounts, &recvcounts, &sdispls, &rdispls, comm);
5118 size_t * size_t_buffer =
5119 xmalloc(4 * (size_t)comm_size * sizeof(*size_t_buffer));
5120 size_t * total_sendcounts = size_t_buffer + 0 * comm_size;
5121 size_t * total_recvcounts = size_t_buffer + 1 * comm_size;
5122 size_t * total_sdispls = size_t_buffer + 2 * comm_size;
5123 size_t * total_rdispls = size_t_buffer + 3 * comm_size;
5124
5125 for (size_t i = 0; i < num_src_points; ++i)
5126 sendcounts[remote_src_points[i].data.rank * num_src_fields +
5127 remote_src_points[i].field_idx]++;
5128
5130 num_src_fields, sendcounts, recvcounts, sdispls, rdispls, comm);
5131
5132 size_t total_sendcount = 0, total_recvcount = 0;
5133 for (int i = 0; i < comm_size; ++i) {
5134 total_sdispls[i] = total_sendcount;
5135 total_rdispls[i] = total_recvcount;
5136 total_sendcounts[i] = 0;
5137 total_recvcounts[i] = 0;
5138 for (size_t j = 0; j < num_src_fields; ++j) {
5139 total_sendcounts[i] += sendcounts[num_src_fields * i + j];
5140 total_recvcounts[i] += recvcounts[num_src_fields * i + j];
5141 }
5142 total_sendcount += total_sendcounts[i];
5143 total_recvcount += total_recvcounts[i];
5144 }
5145
5146 size_t recv_count = total_recvcounts[comm_size - 1] +
5147 total_rdispls[comm_size - 1];
5148
5149 size_t * exchange_buffer =
5150 xmalloc((2 * num_src_points + recv_count) * sizeof(*exchange_buffer));
5151 size_t * send_buffer = exchange_buffer;
5152 size_t * reorder_idx = exchange_buffer + num_src_points;
5153 size_t * recv_buffer = exchange_buffer + 2 * num_src_points;
5154
5155 // pack the original positions of the requested points
5156 size_t src_field_buffer_size[num_src_fields];
5157 memset(
5158 src_field_buffer_size, 0,
5159 num_src_fields * sizeof(src_field_buffer_size[0]));
5160 for (size_t i = 0; i < num_src_points; ++i) {
5161 size_t curr_src_field_idx = (size_t)(remote_src_points[i].field_idx);
5162 size_t pos = sdispls[(size_t)(remote_src_points[i].data.rank) * num_src_fields +
5163 curr_src_field_idx + 1]++;
5164 send_buffer[pos] = (size_t)remote_src_points[i].data.orig_pos;
5165 reorder_idx[pos] = src_field_buffer_size[curr_src_field_idx]++;
5166 }
5167
5168 // exchange original positions of the requested points
5169 yac_alltoallv_size_t_p2p(
5170 send_buffer, total_sendcounts, total_sdispls,
5171 recv_buffer, total_recvcounts, total_rdispls, comm,
5172 "interpolation_raw_add_w_sum_mf", __LINE__);
5173
5174 free(size_t_buffer);
5175
5177 interp_raw->src_field_exchange_data, num_src_fields, comm,
5178 recvcounts, recv_buffer, sendcounts, reorder_idx,
5180
5181 yac_free_comm_buffers(sendcounts, recvcounts, sdispls, rdispls);
5182 free(exchange_buffer);
5183
5184 size_t * tgt_idx = xmalloc(tgt_count * sizeof(*tgt_idx));
5185
5186 for (size_t i = 0; i < tgt_count; ++i) {
5187 YAC_ASSERT(
5188 tgt_stencils[i].tgt.data.count == 1,
5189 "currently unsupported target point distribution")
5190 tgt_idx[i] = (size_t)(tgt_stencils[i].tgt.data.data.single.orig_pos);
5191 }
5192
5194 &(interp_raw->interp_weights_data), num_src_fields, tgt_count,
5195 tgt_idx, num_src_per_tgt, weights, src_field_idx, src_idx,
5196 src_field_buffer_size);
5197
5198 free(tgt_idx);
5199}
5200
5202 struct remote_point_info_reorder * src_points, size_t num_src_points,
5203 size_t num_src_fields, size_t tgt_count,
5204 struct interp_weight_stencil_wsum_mf * tgt_stencils, size_t * num_src_per_tgt,
5205 double * weights, size_t * src_idx, size_t * src_field_idx, MPI_Comm comm,
5206 void * interp_raw, Xt_config redist_config) {
5207
5209 src_points, num_src_points, num_src_fields, tgt_count, tgt_stencils,
5210 num_src_per_tgt, weights, src_idx, src_field_idx, comm,
5211 (struct yac_interpolation_raw *)interp_raw, redist_config);
5212}
5213
5215 struct remote_point_info_reorder * src_points, size_t num_src_points,
5216 size_t num_src_fields, size_t tgt_count,
5217 struct interp_weight_stencil_wsum_mf * tgt_stencils, size_t * num_src_per_tgt,
5218 double * weights, size_t * src_idx, size_t * src_field_idx, MPI_Comm comm,
5219 void * interp_raw, Xt_config redist_config) {
5220
5221 UNUSED(weights);
5222
5224 src_points, num_src_points, num_src_fields, tgt_count, tgt_stencils,
5225 num_src_per_tgt, NULL, src_idx, src_field_idx, comm,
5226 (struct yac_interpolation_raw *)interp_raw, redist_config);
5227}
5228
5230 struct remote_point_info_reorder * src_points, size_t num_src_points,
5231 size_t num_src_fields, size_t tgt_count,
5232 struct interp_weight_stencil_wsum_mf * tgt_stencils, size_t * num_src_per_tgt,
5233 double * weights, size_t * src_idx, size_t * src_field_idx, MPI_Comm comm,
5234 void * interp_raw, Xt_config redist_config) {
5235
5236 UNUSED(src_field_idx);
5237
5239 src_points, num_src_points, num_src_fields, tgt_count, tgt_stencils,
5240 num_src_per_tgt, weights, src_idx, NULL, comm,
5241 (struct yac_interpolation_raw *)interp_raw, redist_config);
5242}
5243
5245 struct remote_point_info_reorder * src_points, size_t num_src_points,
5246 size_t num_src_fields, size_t tgt_count,
5247 struct interp_weight_stencil_wsum_mf * tgt_stencils, size_t * num_src_per_tgt,
5248 double * weights, size_t * src_idx, size_t * src_field_idx, MPI_Comm comm,
5249 void * interp_raw, Xt_config redist_config) {
5250
5251 UNUSED(weights);
5252 UNUSED(src_field_idx);
5253
5255 src_points, num_src_points, num_src_fields, tgt_count, tgt_stencils,
5256 num_src_per_tgt, NULL, src_idx, NULL, comm,
5257 (struct yac_interpolation_raw *)interp_raw, redist_config);
5258}
5259
5261 struct yac_interp_weights const * weights,
5262 struct yac_collection_selection const * collection_selection,
5263 double frac_mask_fallback_value,
5264 double scaling_factor, double scaling_summand,
5265 char const * yaxt_exchanger_name,
5266 struct yac_interpolation_exchange ** interpolation_exchange,
5268 int is_source, int is_target) {
5269
5270 YAC_ASSERT(
5271 yac_collection_selection_is_contiguous(collection_selection),
5272 "non-contiguous selections are not supported for raw interpolation");
5273
5274 struct yac_interpolation_raw interpolation_raw;
5275
5276 interpolation_raw.src_field_exchange_data = NULL;
5278 frac_mask_fallback_value, scaling_factor, scaling_summand,
5279 &interpolation_raw.interp_weights_data);
5280
5281 MPI_Comm comm = weights->comm;
5282 int comm_size;
5283 yac_mpi_call(MPI_Comm_size(comm, &comm_size), comm);
5284 int * flag_buffer = xmalloc(2 * (size_t)comm_size * sizeof(*flag_buffer));
5285 int * rank_is_source = flag_buffer;
5286 int * rank_is_target = flag_buffer + comm_size;
5288 MPI_Allgather(&is_source, 1, MPI_INT, rank_is_source, 1, MPI_INT, comm),
5289 comm);
5291 MPI_Allgather(&is_target, 1, MPI_INT, rank_is_target, 1, MPI_INT, comm),
5292 comm);
5293
5294 Xt_config redist_config = get_redist_config(yaxt_exchanger_name, comm);
5295
5296 // sort stencils by type
5297 qsort(weights->stencils, weights->stencils_size, sizeof(*(weights->stencils)),
5299
5300 size_t local_stencil_counts[WEIGHT_STENCIL_TYPE_SIZE];
5301 size_t stencils_offsets[WEIGHT_STENCIL_TYPE_SIZE];
5302
5303 // count local number of stencils per type
5304 memset(&(local_stencil_counts[0]), 0, sizeof(local_stencil_counts));
5305 for (size_t i = 0; i < weights->stencils_size; ++i)
5306 local_stencil_counts[(int)(weights->stencils[i].type)]++;
5307
5308 for (size_t i = 0, accu = 0; i < (size_t)WEIGHT_STENCIL_TYPE_SIZE; ++i) {
5309 stencils_offsets[i] = accu;
5310 accu += local_stencil_counts[i];
5311 }
5312
5313 size_t global_stencil_counts[WEIGHT_STENCIL_TYPE_SIZE];
5314
5315 // determine global number of stencils per type
5317 MPI_Allreduce(
5318 local_stencil_counts, global_stencil_counts,
5319 (int)WEIGHT_STENCIL_TYPE_SIZE, YAC_MPI_SIZE_T, MPI_SUM, comm), comm);
5320
5321 { // check whether the collection_size is consistant across all processes
5322 size_t local_collection_size =
5324 size_t max_collection_size;
5326 MPI_Allreduce(
5327 &local_collection_size, &max_collection_size, 1, YAC_MPI_SIZE_T,
5328 MPI_MAX, comm), comm);
5329 YAC_ASSERT(
5330 (size_t)max_collection_size == local_collection_size,
5331 "mismatching collection sizes")
5332 }
5333
5334 if (global_stencil_counts[FIXED] > 0)
5336 weights->comm, local_stencil_counts[FIXED],
5337 weights->stencils + stencils_offsets[FIXED],
5338 (void*)&interpolation_raw, interp_raw_add_fixed, rank_is_target);
5339
5340 if (global_stencil_counts[DIRECT] > 0)
5342 weights->comm, local_stencil_counts[DIRECT],
5343 weights->stencils + stencils_offsets[DIRECT],
5344 (void*)&interpolation_raw, interp_add_direct_raw,
5345 redist_config, rank_is_source, rank_is_target);
5346
5347 if (global_stencil_counts[SUM] > 0) {
5348
5349 struct interp_weight_stencils_wsum_mf * wsum_stencils =
5351 weights->stencils + stencils_offsets[SUM],
5352 (size_t)(local_stencil_counts[SUM]), SUM,
5353 rank_is_source, rank_is_target);
5355 weights->comm, wsum_stencils, (void*)&interpolation_raw,
5356 interpolation_raw_add_sum, redist_config);
5357 for (size_t i = 0; i < wsum_stencils->count; ++i)
5358 free_remote_point(wsum_stencils->data[i].tgt);
5359 free(wsum_stencils->data);
5360 free(wsum_stencils);
5361 }
5362
5363 if (global_stencil_counts[WEIGHT_SUM] > 0) {
5364
5365 struct interp_weight_stencils_wsum_mf * wsum_stencils =
5367 weights->stencils + stencils_offsets[WEIGHT_SUM],
5368 (size_t)(local_stencil_counts[WEIGHT_SUM]), WEIGHT_SUM,
5369 rank_is_source, rank_is_target);
5371 weights->comm, wsum_stencils, (void*)&interpolation_raw,
5372 interpolation_raw_add_wsum, redist_config);
5373 for (size_t i = 0; i < wsum_stencils->count; ++i)
5374 free_remote_point(wsum_stencils->data[i].tgt);
5375 free(wsum_stencils->data);
5376 free(wsum_stencils);
5377 }
5378
5379 if (global_stencil_counts[DIRECT_MF] > 0)
5381 weights->comm, local_stencil_counts[DIRECT_MF],
5382 weights->stencils + stencils_offsets[DIRECT_MF],
5383 (void*)&interpolation_raw, interp_add_direct_mf_raw, redist_config,
5384 rank_is_source, rank_is_target);
5385
5386 if (global_stencil_counts[SUM_MF] > 0) {
5387
5388 struct interp_weight_stencils_wsum_mf * sum_mf_stencils =
5390 weights->stencils + stencils_offsets[SUM_MF],
5391 (size_t)(local_stencil_counts[SUM_MF]), SUM_MF,
5392 rank_is_source, rank_is_target);
5394 weights->comm, sum_mf_stencils, (void*)&interpolation_raw,
5395 interpolation_raw_add_sum_mf, redist_config);
5396 for (size_t i = 0; i < sum_mf_stencils->count; ++i)
5397 free_remote_point(sum_mf_stencils->data[i].tgt);
5398 free(sum_mf_stencils->data);
5399 free(sum_mf_stencils);
5400 }
5401
5402 if (global_stencil_counts[WEIGHT_SUM_MF] > 0) {
5403
5404 struct interp_weight_stencils_wsum_mf * wsum_mf_stencils =
5406 weights->stencils + stencils_offsets[WEIGHT_SUM_MF],
5407 (size_t)(local_stencil_counts[WEIGHT_SUM_MF]), WEIGHT_SUM_MF,
5408 rank_is_source, rank_is_target);
5410 weights->comm, wsum_mf_stencils, (void*)&interpolation_raw,
5411 interpolation_raw_add_wsum_mf, redist_config);
5412 for (size_t i = 0; i < wsum_mf_stencils->count; ++i)
5413 free_remote_point(wsum_mf_stencils->data[i].tgt);
5414 free(wsum_mf_stencils->data);
5415 free(wsum_mf_stencils);
5416 }
5417
5418 free(flag_buffer);
5419
5420 Xt_redist * redists =
5422 interpolation_raw.src_field_exchange_data,
5423 interpolation_raw.interp_weights_data.num_src_fields, comm,
5424 redist_config);
5425 int with_frac_mask = YAC_FRAC_MASK_VALUE_IS_VALID(frac_mask_fallback_value);
5426 *interpolation_exchange =
5428 redists, interpolation_raw.interp_weights_data.num_src_fields,
5430 with_frac_mask, "yac_interp_weights_get_interpolation_raw_");
5431 *interp_weights_data = interpolation_raw.interp_weights_data;
5432
5433 if (redists != NULL) {
5434 for (size_t i = 0; i < interpolation_raw.interp_weights_data.num_src_fields;
5435 ++i)
5436 xt_redist_delete(redists[i]);
5437 free(redists);
5438 }
5439
5441 interpolation_raw.src_field_exchange_data,
5442 interpolation_raw.interp_weights_data.num_src_fields);
5443
5444 xt_config_delete(redist_config);
5445}
5446
5448 struct yac_interp_weights * weights,
5449 size_t collection_size, double frac_mask_fallback_value,
5450 double scaling_factor, double scaling_summand,
5451 char const * yaxt_exchanger_name,
5452 struct yac_interpolation_exchange ** interpolation_exchange,
5454 int is_source, int is_target) {
5455
5456 struct yac_collection_selection * collection_selection =
5458
5460 weights, collection_selection, frac_mask_fallback_value,
5461 scaling_factor, scaling_summand, yaxt_exchanger_name,
5462 interpolation_exchange, interp_weights_data, is_source, is_target);
5463
5464 yac_collection_selection_delete(collection_selection);
5465}
5466
5483
5485 struct yac_interp_weights * weights, int reorder,
5487 double scaling_factor, double scaling_summand,
5488 char const * yaxt_exchanger_name, int is_source, int is_target) {
5489
5490 YAC_ASSERT(
5491 (reorder == YAC_MAPPING_ON_SRC) ||
5492 (reorder == YAC_MAPPING_ON_TGT),
5493 "reorder type must be of YAC_MAPPING_ON_SRC/YAC_MAPPING_ON_TGT");
5494
5495 return
5497 weights, (enum yac_interp_weights_reorder_type)reorder,
5499 scaling_factor, scaling_summand,
5500 ((yaxt_exchanger_name != NULL) && (yaxt_exchanger_name[0] != '\0'))?
5501 yaxt_exchanger_name:NULL, is_source, is_target);
5502}
5503
5504static void free_remote_points(struct remote_points * points) {
5505
5506 free(points->data);
5507 free(points);
5508}
5509
5511 struct interp_weight_stencil * stencils, size_t count) {
5512
5513 for (size_t i = 0 ; i < count; ++i) {
5514
5515 YAC_ASSERT(
5516 (stencils[i].type == DIRECT) ||
5517 (stencils[i].type == SUM) ||
5518 (stencils[i].type == WEIGHT_SUM) ||
5519 (stencils[i].type == DIRECT_MF) ||
5520 (stencils[i].type == SUM_MF) ||
5521 (stencils[i].type == WEIGHT_SUM_MF) ||
5522 (stencils[i].type == FIXED), "invalid stencil type")
5523 switch(stencils[i].type) {
5524
5525 case(DIRECT):
5526 free_remote_point(stencils[i].data.direct.src);
5527 break;
5528 case(SUM):
5529 free_remote_points(stencils[i].data.sum.srcs);
5530 break;
5531 case(WEIGHT_SUM):
5532 free_remote_points(stencils[i].data.weight_sum.srcs);
5533 free(stencils[i].data.weight_sum.weights);
5534 break;
5535 case(DIRECT_MF):
5536 free_remote_point(stencils[i].data.direct_mf.src);
5537 break;
5538 case(SUM_MF):
5539 free_remote_points(stencils[i].data.sum_mf.srcs);
5540 free(stencils[i].data.sum_mf.field_indices);
5541 break;
5542 case (WEIGHT_SUM_MF):
5543 free_remote_points(stencils[i].data.weight_sum_mf.srcs);
5544 free(stencils[i].data.weight_sum_mf.weights);
5545 free(stencils[i].data.weight_sum_mf.field_indices);
5546 break;
5547 default:
5548 case(FIXED):
5549 break;
5550 };
5551 free_remote_point(stencils[i].tgt);
5552 }
5553 free(stencils);
5554}
5555
5556#ifdef YAC_NETCDF_ENABLED
5557static int compare_double(void const * a, void const * b) {
5558
5559 double const * _a = (double const *)a;
5560 double const * _b = (double const *)b;
5561 if (isnan(*_a) || isnan(*_b))
5562 return isnan(*_a) - isnan(*_b);
5563 else
5564 return (*_a > *_b) - (*_a < *_b);
5565}
5566
5571 char const * filename, char const * src_grid_name, char const * tgt_grid_name,
5572 size_t num_fixed_values, double * fixed_values,
5573 size_t * num_tgt_per_fixed_value, size_t num_links,
5574 size_t num_weights_per_link, size_t num_src_fields,
5575 size_t * num_links_per_src_field,
5576 enum yac_location * src_locations, enum yac_location tgt_location,
5577 size_t src_grid_size, size_t tgt_grid_size) {
5578
5579 int ncid;
5580
5581 // create file
5582 yac_nc_create(filename, NC_CLOBBER | NC_64BIT_OFFSET, &ncid);
5583
5584 int dim_weight_id[8];
5585
5586 // define dimensions
5587 if (num_links > 0) {
5588 YAC_HANDLE_ERROR(nc_def_dim(ncid, "num_links", num_links, &dim_weight_id[0]));
5590 num_weights_per_link > 0,
5591 "number of links is %zu but number of weights per link is zero for "
5592 "weight file %s", num_links, filename)
5594 nc_def_dim(ncid, "num_wgts", num_weights_per_link, &dim_weight_id[1]));
5595 }
5597 num_src_fields > 0, "number of source fields is zero for weight file %s",
5598 filename)
5600 nc_def_dim(ncid, "num_src_fields", num_src_fields, &dim_weight_id[2]));
5602 nc_def_dim(
5603 ncid, "max_loc_str_len", YAC_MAX_LOC_STR_LEN, &dim_weight_id[3]));
5604
5605 if (num_fixed_values > 0) {
5607 nc_def_dim(
5608 ncid, "num_fixed_values", num_fixed_values, &dim_weight_id[4]));
5609 size_t num_fixed_dst = 0;
5610 for (size_t i = 0; i < num_fixed_values; ++i)
5611 num_fixed_dst += num_tgt_per_fixed_value[i];
5613 num_fixed_dst > 0, "number of fixed values is %zu but number "
5614 "of fixed destination points is zero for weight file %s",
5615 num_fixed_values, filename)
5617 nc_def_dim(ncid, "num_fixed_dst", num_fixed_dst, &dim_weight_id[5]));
5618 }
5619
5620 if (src_grid_size > 0)
5622 nc_def_dim(ncid, "src_grid_size", src_grid_size, &dim_weight_id[6]));
5623
5624 if (tgt_grid_size > 0)
5626 nc_def_dim(ncid, "dst_grid_size", tgt_grid_size, &dim_weight_id[7]));
5627
5628 int var_src_add_id, var_dst_add_id, var_weight_id, var_num_links_id,
5629 src_var_locs_id, tgt_var_loc_id, var_fixed_values_id,
5630 var_num_dst_per_fixed_value_id, var_dst_add_fixed_id;
5631
5632 // define variables
5633 if (num_links > 0) {
5635 nc_def_var(
5636 ncid, "src_address", NC_INT, 1, dim_weight_id, &var_src_add_id));
5638 nc_def_var(
5639 ncid, "dst_address", NC_INT, 1, dim_weight_id, &var_dst_add_id));
5641 nc_def_var(
5642 ncid, "remap_matrix", NC_DOUBLE, 2, dim_weight_id, &var_weight_id));
5644 nc_def_var(ncid, "num_links_per_src_field", NC_INT, 1,
5645 &dim_weight_id[2], &var_num_links_id));
5646 }
5648 nc_def_var(
5649 ncid, "src_locations", NC_CHAR, 2, &dim_weight_id[2], &src_var_locs_id));
5651 nc_def_var(
5652 ncid, "dst_location", NC_CHAR, 1, &dim_weight_id[3], &tgt_var_loc_id));
5653 if (num_fixed_values > 0) {
5655 nc_def_var(ncid, "fixed_values", NC_DOUBLE, 1, &dim_weight_id[4],
5656 &var_fixed_values_id));
5658 nc_def_var(ncid, "num_dst_per_fixed_value", NC_INT, 1, &dim_weight_id[4],
5659 &var_num_dst_per_fixed_value_id));
5661 nc_def_var(ncid, "dst_address_fixed", NC_INT, 1, &dim_weight_id[5],
5662 &var_dst_add_fixed_id));
5663 }
5664
5665 // put attributes
5667 nc_put_att_text(ncid, NC_GLOBAL, "version",
5671 nc_put_att_text(ncid, NC_GLOBAL, "src_grid_name",
5672 strlen(src_grid_name), src_grid_name));
5674 nc_put_att_text(ncid, NC_GLOBAL, "dst_grid_name",
5675 strlen(tgt_grid_name), tgt_grid_name));
5676 {
5677 char const * str_logical[2] = {"FALSE", "TRUE"};
5678 YAC_HANDLE_ERROR(nc_put_att_text(ncid, NC_GLOBAL, "contains_links",
5679 strlen(str_logical[num_links > 0]),
5680 str_logical[num_links > 0]));
5681 YAC_HANDLE_ERROR(nc_put_att_text(ncid, NC_GLOBAL, "contains_fixed_dst",
5682 strlen(str_logical[num_fixed_values > 0]),
5683 str_logical[num_fixed_values > 0]));
5684 }
5685
5686 // end definition
5687 YAC_HANDLE_ERROR(nc_enddef(ncid));
5688
5689 // write some basic data
5690
5691 if (num_links > 0) {
5692 int * num_links_per_src_field_int =
5693 xmalloc(num_src_fields * sizeof(*num_links_per_src_field_int));
5694 for (size_t i = 0; i < num_src_fields; ++i) {
5695 YAC_ASSERT(
5696 num_links_per_src_field[i] <= INT_MAX,
5697 "number of links per source field too big (not yet supported)")
5698 num_links_per_src_field_int[i] = (int)num_links_per_src_field[i];
5699 }
5701 nc_put_var_int(ncid, var_num_links_id, num_links_per_src_field_int));
5702 free(num_links_per_src_field_int);
5703 }
5704
5705 for (size_t i = 0; i < num_src_fields; ++i) {
5706 char const * loc_str = yac_loc2str(src_locations[i]);
5707 size_t str_start[2] = {i, 0};
5708 size_t str_count[2] = {1, strlen(loc_str)};
5710 nc_put_vara_text(ncid, src_var_locs_id, str_start, str_count, loc_str));
5711 }
5712
5713 {
5714 char const * loc_str = yac_loc2str(tgt_location);
5715 size_t str_start[1] = {0};
5716 size_t str_count[1] = {strlen(loc_str)};
5718 nc_put_vara_text(ncid, tgt_var_loc_id, str_start, str_count, loc_str));
5719 }
5720 if (num_fixed_values > 0) {
5721
5722 int * num_tgt_per_fixed_value_int =
5723 xmalloc(num_fixed_values * sizeof(*num_tgt_per_fixed_value_int));
5724 for (unsigned i = 0; i < num_fixed_values; ++i) {
5725 YAC_ASSERT(
5726 num_tgt_per_fixed_value[i] <= INT_MAX,
5727 "number of targets per fixed value is too big (not yet supported)")
5728 num_tgt_per_fixed_value_int[i] = (int)num_tgt_per_fixed_value[i];
5729 }
5730 YAC_HANDLE_ERROR(nc_put_var_double(ncid, var_fixed_values_id, fixed_values));
5731 YAC_HANDLE_ERROR(nc_put_var_int(ncid, var_num_dst_per_fixed_value_id,
5732 num_tgt_per_fixed_value_int));
5733 free(num_tgt_per_fixed_value_int);
5734 }
5735
5736 // close file
5737 YAC_HANDLE_ERROR(nc_close(ncid));
5738}
5739
5740static int compare_interp_weight_stencil(const void * a, const void * b) {
5741
5742 int a_is_fixed = (((struct interp_weight_stencil *)a)->type == FIXED);
5743 int b_is_fixed = (((struct interp_weight_stencil *)b)->type == FIXED);
5744 int ret = b_is_fixed - a_is_fixed;
5745
5746 if (ret) return ret;
5747
5748 // if both are fixed stencils
5749 if (a_is_fixed) {
5750
5751 double fixed_value_a =
5752 ((struct interp_weight_stencil *)a)->data.fixed.value;
5753 double fixed_value_b =
5754 ((struct interp_weight_stencil *)b)->data.fixed.value;
5755 // use memcmp for correct handling of NaNs
5756 ret = memcmp(&fixed_value_a, &fixed_value_b, sizeof(fixed_value_a));
5757
5758 if (ret) return ret;
5759 }
5760
5761 return (((struct interp_weight_stencil *)a)->tgt.global_id >
5762 ((struct interp_weight_stencil *)b)->tgt.global_id) -
5763 (((struct interp_weight_stencil *)a)->tgt.global_id <
5764 ((struct interp_weight_stencil *)b)->tgt.global_id);
5765}
5766
5768 struct interp_weight_stencil * stencils, size_t stencils_size,
5769 yac_int * min_tgt_global_id, yac_int * max_tgt_global_id, MPI_Comm comm) {
5770
5771 yac_int min_max[2] = {YAC_INT_MAX, YAC_INT_MIN};
5772
5773 for (size_t i = 0; i < stencils_size; ++i) {
5774
5775 yac_int curr_id = stencils[i].tgt.global_id;
5776 if (curr_id < min_max[0]) min_max[0] = curr_id;
5777 if (curr_id > min_max[1]) min_max[1] = curr_id;
5778 }
5779
5780 min_max[0] = YAC_INT_MAX - min_max[0];
5781
5783 MPI_Allreduce(
5784 MPI_IN_PLACE, min_max, 2, yac_int_dt, MPI_MAX, comm), comm);
5785
5786 *min_tgt_global_id = YAC_INT_MAX - min_max[0];
5787 *max_tgt_global_id = min_max[1];
5788}
5789
5791 struct interp_weight_stencil * stencils, size_t stencils_size,
5792 yac_int min_tgt_global_id, yac_int max_tgt_global_id,
5793 int num_io_procs_int, int * io_owner) {
5794
5795 long long num_io_procs = (long long)num_io_procs_int;
5796 long long id_range =
5797 MAX((long long)(max_tgt_global_id - min_tgt_global_id),1);
5798
5799 for (size_t i = 0; i < stencils_size; ++i)
5800 io_owner[i] =
5801 ((int)(MIN(((long long)(stencils[i].tgt.global_id - min_tgt_global_id) *
5802 num_io_procs) / id_range, num_io_procs - 1)));
5803}
5804
5806 struct interp_weight_stencil * stencils, size_t stencil_count,
5807 double ** fixed_values, size_t * num_fixed_values, MPI_Comm comm) {
5808
5809 int comm_size;
5810 yac_mpi_call(MPI_Comm_size(comm, &comm_size), comm);
5811
5812 double * local_fixed_values =
5813 xmalloc(stencil_count * sizeof(*local_fixed_values));
5814
5815 int * int_buffer = xmalloc(2 * (size_t)comm_size * sizeof(*int_buffer));
5816 int * recvcounts = int_buffer + 0 * comm_size;
5817 int * rdispls = int_buffer + 1 * comm_size;
5818
5819 size_t local_num_fixed = 0;
5820
5821 // get all local fixed values
5822 for (size_t i = 0; i < stencil_count;
5823 ++i, ++local_num_fixed) {
5824 if (stencils[i].type != FIXED) break;
5825 local_fixed_values[i] = stencils[i].data.fixed.value;
5826 }
5827 qsort(local_fixed_values, local_num_fixed, sizeof(*local_fixed_values),
5829 yac_remove_duplicates_double(local_fixed_values, &local_num_fixed);
5830
5831 // get number of fixed values per rank
5832 int local_num_fixed_int = (int)(local_num_fixed);
5834 MPI_Allgather(
5835 &local_num_fixed_int, 1, MPI_INT, recvcounts, 1,MPI_INT, comm), comm);
5836 for (int i = 0, accu = 0; i < comm_size; ++i) {
5837 rdispls[i] = accu;
5838 accu += recvcounts[i];
5839 }
5840
5841 size_t num_all_fixed_values = 0;
5842 for (int i = 0; i < comm_size; ++i)
5843 num_all_fixed_values += (size_t)(recvcounts[i]);
5844
5845 double * all_fixed_values =
5846 xmalloc(num_all_fixed_values * sizeof(*all_fixed_values));
5847
5848 // gather all fixed values
5850 MPI_Allgatherv(
5851 local_fixed_values, local_num_fixed_int, MPI_DOUBLE,
5852 all_fixed_values, recvcounts, rdispls, MPI_DOUBLE, comm), comm);
5853 free(int_buffer);
5854 free(local_fixed_values);
5855
5856 qsort(all_fixed_values, num_all_fixed_values, sizeof(*all_fixed_values),
5858 yac_remove_duplicates_double(all_fixed_values, &num_all_fixed_values);
5859 *fixed_values = xrealloc(all_fixed_values,
5860 num_all_fixed_values * sizeof(*all_fixed_values));
5861 *num_fixed_values = num_all_fixed_values;
5862}
5863
5864static size_t get_num_weights_per_link(struct interp_weight_stencil * stencil) {
5865
5866 YAC_ASSERT(
5867 (stencil->type == FIXED) ||
5868 (stencil->type == DIRECT) ||
5869 (stencil->type == SUM) ||
5870 (stencil->type == WEIGHT_SUM) ||
5871 (stencil->type == DIRECT_MF) ||
5872 (stencil->type == SUM_MF) ||
5873 (stencil->type == WEIGHT_SUM_MF), "invalid stencil type")
5874
5875 return (stencil->type == FIXED)?0:1;
5876}
5877
5879 struct interp_weight_stencil * stencils, size_t stencil_count,
5880 MPI_Comm comm) {
5881
5882 size_t num_weights_per_link = 0;
5883 for (size_t i = 0; i < stencil_count; ++i)
5884 num_weights_per_link =
5885 MAX(num_weights_per_link, get_num_weights_per_link(stencils + i));
5886
5887 size_t num_weights_per_link_64_t = num_weights_per_link;
5889 MPI_Allreduce(
5890 MPI_IN_PLACE, &num_weights_per_link_64_t, 1, YAC_MPI_SIZE_T,
5891 MPI_MAX, comm), comm);
5892 num_weights_per_link = (size_t)num_weights_per_link_64_t;
5893
5894 return num_weights_per_link;
5895}
5896
5898 struct interp_weight_stencil * stencil, size_t src_field_idx) {;
5899
5900 YAC_ASSERT(
5901 stencil->type != FIXED, "stencil type FIXED not supported by this routine")
5902 YAC_ASSERT(
5903 (stencil->type == DIRECT) ||
5904 (stencil->type == SUM) ||
5905 (stencil->type == WEIGHT_SUM) ||
5906 (stencil->type == DIRECT_MF) ||
5907 (stencil->type == SUM_MF) ||
5908 (stencil->type == WEIGHT_SUM_MF), "invalid stencil type")
5909 switch (stencil->type) {
5910 default:
5911 case(DIRECT): return (src_field_idx == 0)?1:0;
5912 case(SUM): return (src_field_idx == 0)?stencil->data.sum.srcs->count:0;
5913 case(WEIGHT_SUM):
5914 return (src_field_idx == 0)?stencil->data.weight_sum.srcs->count:0;
5915 case(DIRECT_MF): return stencil->data.direct_mf.field_idx == src_field_idx;
5916 case(SUM_MF): {
5917 size_t count = 0;
5918 size_t stencil_size = stencil->data.sum_mf.srcs->count;
5919 size_t * field_indices = stencil->data.sum_mf.field_indices;
5920 for (size_t i = 0; i < stencil_size; ++i)
5921 if (field_indices[i] == src_field_idx) ++count;
5922 return count;
5923 }
5924 case(WEIGHT_SUM_MF): {
5925 size_t count = 0;
5926 size_t stencil_size = stencil->data.weight_sum_mf.srcs->count;
5927 size_t * field_indices = stencil->data.weight_sum_mf.field_indices;
5928 for (size_t i = 0; i < stencil_size; ++i)
5929 if (field_indices[i] == src_field_idx) ++count;
5930 return count;
5931 }
5932 };
5933}
5934
5936 struct interp_weight_stencil * stencils, size_t stencil_count,
5937 size_t num_fixed_values, double * fixed_values,
5938 size_t * num_tgt_per_fixed_value,
5939 size_t * num_fixed_tgt, size_t num_src_fields,
5940 size_t * num_links_per_src_field, size_t * num_links) {
5941
5942 *num_fixed_tgt = 0;
5943 *num_links = 0;
5944 for (size_t i = 0; i < num_fixed_values; ++i) num_tgt_per_fixed_value[i] = 0;
5945 for (size_t i = 0; i < num_src_fields; ++i) num_links_per_src_field[i] = 0;
5946
5947 for (size_t i = 0; i < stencil_count; ++i) {
5948 if (stencils[i].type == FIXED) {
5949 double curr_fixed_value = stencils[i].data.fixed.value;
5950 for (size_t j = 0; j < num_fixed_values; ++j) {
5951 // use memcmp to handle NaNs
5952 if (!memcmp(&curr_fixed_value, &fixed_values[j], sizeof(curr_fixed_value))) {
5953 num_tgt_per_fixed_value[j]++;
5954 break;
5955 }
5956 }
5957 ++*num_fixed_tgt;
5958 } else {
5959 for (size_t j = 0; j < num_src_fields; ++j) {
5960 num_links_per_src_field[j] +=
5961 get_num_links_per_src_field(stencils + i, j);
5962 }
5963 }
5964 }
5965 for (size_t i = 0; i < num_src_fields; ++i)
5966 *num_links += num_links_per_src_field[i];
5967}
5968
5970 size_t num_fixed_values, size_t * num_tgt_per_fixed_value,
5971 size_t num_src_fields, size_t * num_links_per_src_field,
5972 size_t * fixed_offsets, size_t * link_offsets, MPI_Comm comm) {
5973
5974 int comm_rank;
5975 yac_mpi_call(MPI_Comm_rank(comm, &comm_rank), comm);
5976
5977 size_t count = num_fixed_values + num_src_fields;
5978 size_t * size_t_buffer = xmalloc(3 * count * sizeof(*size_t_buffer));
5979 size_t * global_counts = size_t_buffer + 0 * count;
5980 size_t * local_counts = size_t_buffer + 1 * count;
5981 size_t * offsets = size_t_buffer + 2 * count;
5982
5983 for (size_t i = 0; i < num_fixed_values; ++i)
5984 local_counts[i] = num_tgt_per_fixed_value[i];
5985 for (size_t i = 0; i < num_src_fields; ++i)
5986 local_counts[num_fixed_values + i] = num_links_per_src_field[i];
5987
5989 MPI_Allreduce(local_counts, global_counts, (int)count, YAC_MPI_SIZE_T,
5990 MPI_SUM, comm), comm);
5992 MPI_Exscan(local_counts, offsets, (int)count, YAC_MPI_SIZE_T, MPI_SUM, comm),
5993 comm);
5994 if (comm_rank == 0) memset(offsets, 0, count * sizeof(*offsets));
5995
5996 for (size_t i = 0, accu = 0; i < num_fixed_values; ++i) {
5997 fixed_offsets[i] = (size_t)(offsets[i]) + accu;
5998 accu += (size_t)(global_counts[i]);
5999 }
6000 for (size_t i = 0, accu = 0; i < num_src_fields; ++i) {
6001 link_offsets[i] = (size_t)(offsets[i+num_fixed_values]) + accu;
6002 accu += (size_t)(global_counts[i+num_fixed_values]);
6003 }
6004 free(size_t_buffer);
6005}
6006
6007static int global_id_to_address(yac_int global_id) {
6008
6010 (global_id < INT_MAX) && (global_id != YAC_INT_MAX),
6011 "a global id (%" YAC_INT_FMT ") cannot be converted into a address; "
6012 "too big (> %d)", global_id, INT_MAX);
6013 return (int)global_id + 1;
6014}
6015
6017 struct interp_weight_stencil * stencils, size_t stencil_count,
6018 int * tgt_address) {
6019
6020 for (size_t i = 0; i < stencil_count; ++i)
6021 tgt_address[i] = global_id_to_address(stencils[i].tgt.global_id);
6022}
6023
6025 struct interp_weight_stencil * stencils, size_t stencil_count,
6026 size_t * num_links_per_src_field, size_t num_src_fields,
6027 int * src_address, int * tgt_address, double * weight) {
6028
6029 size_t * src_field_offsets =
6030 xmalloc(2 * num_src_fields * sizeof(*src_field_offsets));
6031 size_t * prev_src_field_offsets = src_field_offsets + num_src_fields;
6032 for (size_t i = 0, accu = 0; i < num_src_fields; ++i) {
6033 src_field_offsets[i] = accu;
6034 accu += num_links_per_src_field[i];
6035 }
6036
6037 struct interp_weight_stencil * curr_stencil = stencils;
6038 for (size_t i = 0; i < stencil_count; ++i, ++curr_stencil) {
6039
6040 memcpy(prev_src_field_offsets, src_field_offsets,
6041 num_src_fields * sizeof(*prev_src_field_offsets));
6042
6043 int curr_tgt_address = global_id_to_address(curr_stencil->tgt.global_id);
6044 YAC_ASSERT(
6045 curr_stencil->type != FIXED, "this call is invalid for FIXED stencils")
6046 YAC_ASSERT(
6047 (curr_stencil->type == DIRECT) ||
6048 (curr_stencil->type == SUM) ||
6049 (curr_stencil->type == WEIGHT_SUM) ||
6050 (curr_stencil->type == DIRECT_MF) ||
6051 (curr_stencil->type == SUM_MF) ||
6052 (curr_stencil->type == WEIGHT_SUM_MF), "invalid stencil type")
6053 size_t src_field_offset;
6054 switch (curr_stencil->type) {
6055 default:
6056 case(DIRECT):
6057 src_field_offset = src_field_offsets[0]++;
6058 src_address[src_field_offset] =
6060 tgt_address[src_field_offset] = curr_tgt_address;
6061 weight[src_field_offset] = 1.0;
6062 break;
6063 case(SUM): {
6064 size_t curr_count = curr_stencil->data.sum.srcs->count;
6065 struct remote_point * srcs = curr_stencil->data.sum.srcs->data;
6066 for (size_t k = 0; k < curr_count; ++k) {
6067 src_field_offset = src_field_offsets[0]++;
6068 src_address[src_field_offset] =
6070 tgt_address[src_field_offset] = curr_tgt_address;
6071 weight[src_field_offset] = 1.0;
6072 }
6073 break;
6074 }
6075 case(WEIGHT_SUM): {
6076 size_t curr_count = curr_stencil->data.weight_sum.srcs->count;
6077 struct remote_point * srcs = curr_stencil->data.weight_sum.srcs->data;
6078 double * weights = curr_stencil->data.weight_sum.weights;
6079 for (size_t k = 0; k < curr_count; ++k) {
6080 src_field_offset = src_field_offsets[0]++;
6081 src_address[src_field_offset] =
6083 tgt_address[src_field_offset] = curr_tgt_address;
6084 weight[src_field_offset] = weights[k];
6085 }
6086 break;
6087 }
6088 case(DIRECT_MF):
6089 src_field_offset =
6090 src_field_offsets[curr_stencil->data.direct_mf.field_idx]++;
6091 src_address[src_field_offset ] =
6093 tgt_address[src_field_offset ] = curr_tgt_address;
6094 weight[src_field_offset ] = 1.0;
6095 break;
6096 case(SUM_MF): {
6097 size_t curr_count = curr_stencil->data.sum_mf.srcs->count;
6098 struct remote_point * srcs =
6099 curr_stencil->data.sum_mf.srcs->data;
6100 size_t * field_indices = curr_stencil->data.sum_mf.field_indices;
6101 for (size_t k = 0; k < curr_count; ++k) {
6102 src_field_offset = src_field_offsets[field_indices[k]]++;
6103 src_address[src_field_offset] =
6105 tgt_address[src_field_offset] = curr_tgt_address;
6106 weight[src_field_offset] = 1.0;
6107 }
6108 break;
6109 }
6110 case(WEIGHT_SUM_MF): {
6111 size_t curr_count = curr_stencil->data.weight_sum_mf.srcs->count;
6112 struct remote_point * srcs =
6113 curr_stencil->data.weight_sum_mf.srcs->data;
6114 double * weights = curr_stencil->data.weight_sum_mf.weights;
6115 size_t * field_indices = curr_stencil->data.weight_sum_mf.field_indices;
6116 for (size_t k = 0; k < curr_count; ++k) {
6117 src_field_offset = src_field_offsets[field_indices[k]]++;
6118 src_address[src_field_offset] =
6120 tgt_address[src_field_offset] = curr_tgt_address;
6121 weight[src_field_offset] = weights[k];
6122 }
6123 break;
6124 }
6125 };
6126
6127 for (size_t j = 0; j < num_src_fields; ++j)
6129 src_address + prev_src_field_offsets[j],
6130 src_field_offsets[j] - prev_src_field_offsets[j],
6131 weight + prev_src_field_offsets[j]);
6132 }
6133 free(src_field_offsets);
6134}
6135
6137 MPI_Comm comm, size_t count, struct interp_weight_stencil * stencils,
6138 int * owner_ranks, size_t * new_count,
6139 struct interp_weight_stencil ** new_stencils) {
6140
6141 int comm_rank, comm_size;
6142 yac_mpi_call(MPI_Comm_rank(comm, &comm_rank), comm);
6143 yac_mpi_call(MPI_Comm_size(comm, &comm_size), comm);
6144
6145 size_t * sendcounts, * recvcounts, * sdispls, *rdispls;
6147 1, &sendcounts, &recvcounts, &sdispls, &rdispls, comm);
6148
6149 size_t * stencil_indices = xmalloc(count * sizeof(*stencil_indices));
6150 for (size_t i = 0; i < count; ++i) {
6151 stencil_indices[i] = i;
6152 sendcounts[owner_ranks[i]]++;
6153 }
6154
6156 1, sendcounts, recvcounts, sdispls, rdispls, comm);
6157
6158 // sort the stencil indices by owner rank
6159 yac_quicksort_index_int_size_t(owner_ranks, count, stencil_indices);
6160
6161 *new_count = recvcounts[comm_size - 1] + rdispls[comm_size - 1];
6162 *new_stencils =
6163 exchange_stencils(comm, stencils, stencil_indices, sendcounts, recvcounts);
6164 yac_free_comm_buffers(sendcounts, recvcounts, sdispls, rdispls);
6165 free(stencil_indices);
6166}
6167
6168#endif // YAC_NETCDF_ENABLED
6169
6171 struct yac_interp_weights * weights, char const * filename,
6172 char const * src_grid_name, char const * tgt_grid_name,
6173 size_t src_grid_size, size_t tgt_grid_size,
6174 enum yac_weight_file_on_existing on_existing) {
6175
6176#ifndef YAC_NETCDF_ENABLED
6177
6178 UNUSED(weights);
6179 UNUSED(filename);
6182 UNUSED(src_grid_size);
6183 UNUSED(tgt_grid_size);
6184
6185 die(
6186 "ERROR(yac_interp_weights_write_to_file): "
6187 "YAC is built without the NetCDF support");
6188#else
6189
6190 MPI_Comm comm = weights->comm;
6191 int comm_rank, comm_size;
6192 yac_mpi_call(MPI_Comm_rank(comm, &comm_rank), comm);
6193 yac_mpi_call(MPI_Comm_size(comm, &comm_size), comm);
6194
6195 // determine processes that will do output
6196 int io_flag;
6197 int * io_ranks;
6198 int num_io_ranks;
6199 yac_get_io_ranks(comm, &io_flag, &io_ranks, &num_io_ranks);
6200
6201 int io_root = io_ranks[0];
6202
6203 // check for existing weight file
6204 int weight_file_exists =
6205 (io_root == comm_rank)?yac_file_exists(filename):0;
6207 MPI_Bcast(&weight_file_exists, 1, MPI_INT, io_root, comm), comm);
6208
6209 // return if the weight file already exists and is supposed to be kept
6210 if ((on_existing == YAC_WEIGHT_FILE_KEEP) && weight_file_exists) {
6211 free(io_ranks);
6212 return;
6213 }
6214
6215 if ((on_existing == YAC_WEIGHT_FILE_ERROR) && weight_file_exists) {
6216 if (io_root == comm_rank) {
6217 char const msg_fmt[] =
6218 "ERROR(yac_interp_weights_write_to_file): "
6219 "weight file already exists (%s)";
6220 char msg[strlen(msg_fmt) + strlen(filename)];
6221 sprintf(msg, msg_fmt, filename);
6222 yac_abort(comm, msg, __FILE__, __LINE__);
6223 }
6224 free(io_ranks);
6225 return;
6226 }
6227
6228 // determine range of global ids
6229 yac_int min_tgt_global_id, max_tgt_global_id;
6231 weights->stencils, weights->stencils_size,
6232 &min_tgt_global_id, &max_tgt_global_id, comm);
6233
6234 // determine io owners for all stencils
6235 int * io_owner =
6236 xmalloc(weights->stencils_size * sizeof(*io_owner));
6238 weights->stencils, weights->stencils_size,
6239 min_tgt_global_id, max_tgt_global_id,
6240 num_io_ranks, io_owner);
6241 for (size_t i = 0; i < weights->stencils_size; ++i)
6242 io_owner[i] = io_ranks[io_owner[i]];
6243 free(io_ranks);
6244
6245 size_t io_stencil_count = 0;
6246 struct interp_weight_stencil * io_stencils = NULL;
6247
6248 // redistribute stencils into io decomposition
6250 comm, weights->stencils_size, weights->stencils, io_owner,
6251 &io_stencil_count, &io_stencils);
6252 free(io_owner);
6253
6254 // distribute global grid sizes
6255 size_t grid_sizes[2] = {src_grid_size, tgt_grid_size};
6257 MPI_Allreduce(
6258 MPI_IN_PLACE, grid_sizes, 2, YAC_MPI_SIZE_T, MPI_MAX, comm), comm);
6259 src_grid_size = (size_t)(grid_sizes[0]);
6260 tgt_grid_size = (size_t)(grid_sizes[1]);
6261
6262 MPI_Comm io_comm;
6263 yac_mpi_call(MPI_Comm_split(comm, io_flag, comm_rank, &io_comm), comm);
6264
6265 // all non-io processes exit here, the remaining ones work using their own
6266 // communicator
6267 if (!io_flag) {
6268 yac_mpi_call(MPI_Comm_free(&io_comm), comm);
6269 free(io_stencils);
6270 // ensure that the writing of the weight file is complete
6271 yac_mpi_call(MPI_Barrier(comm), comm);
6272 return;
6273 }
6274
6275 // sort the stencils first by type (fixed first; fixed stencils are sorted
6276 // by their fixed value) and second by tgt id
6277 qsort(io_stencils, io_stencil_count, sizeof(*io_stencils),
6279
6280 yac_mpi_call(MPI_Comm_rank(io_comm, &comm_rank), comm);
6281 yac_mpi_call(MPI_Comm_size(io_comm, &comm_size), comm);
6282
6283 double * fixed_values = NULL;
6284 size_t num_fixed_values = 0;
6286 io_stencils, io_stencil_count, &fixed_values, &num_fixed_values, io_comm);
6287 size_t num_src_fields = weights->num_src_fields;
6288 size_t num_weights_per_link =
6289 stencil_get_num_weights_per_tgt(io_stencils, io_stencil_count, io_comm);
6290
6291 size_t * size_t_buffer =
6292 xmalloc(2 * (num_fixed_values + num_src_fields) * sizeof(*size_t_buffer));
6293 size_t * num_tgt_per_fixed_value = size_t_buffer;
6294 size_t * num_links_per_src_field = size_t_buffer + num_fixed_values;
6295 size_t * fixed_offsets = size_t_buffer + num_fixed_values + num_src_fields;
6296 size_t * link_offsets = size_t_buffer + 2 * num_fixed_values + num_src_fields;
6297
6298 size_t num_fixed_tgt = 0;
6299 size_t num_links = 0;
6301 io_stencils, io_stencil_count, num_fixed_values, fixed_values,
6302 num_tgt_per_fixed_value, &num_fixed_tgt, num_src_fields,
6303 num_links_per_src_field, &num_links);
6304
6306 num_fixed_values, num_tgt_per_fixed_value,
6307 num_src_fields, num_links_per_src_field,
6308 fixed_offsets, link_offsets, io_comm);
6309
6310 if (comm_rank == comm_size - 1) {
6311
6312 size_t * total_num_tgt_per_fixed_value =
6313 xmalloc(num_fixed_values * sizeof(*total_num_tgt_per_fixed_value));
6314 for (size_t i = 0, accu = 0; i < num_fixed_values; ++i) {
6315 total_num_tgt_per_fixed_value[i] =
6316 fixed_offsets[i] + num_tgt_per_fixed_value[i] - accu;
6317 accu += total_num_tgt_per_fixed_value[i];
6318 }
6319 size_t total_num_links = link_offsets[num_src_fields-1] +
6320 num_links_per_src_field[num_src_fields-1];
6321
6322 size_t * total_num_links_per_src_field =
6323 xmalloc(num_src_fields * sizeof(*total_num_links_per_src_field));
6324 for (size_t i = 0, accu = 0; i < num_src_fields; ++i) {
6325 total_num_links_per_src_field[i] =
6326 link_offsets[i] + num_links_per_src_field[i] - accu;
6327 accu += total_num_links_per_src_field[i];
6328 }
6329
6331 filename, src_grid_name, tgt_grid_name,
6332 num_fixed_values, fixed_values, total_num_tgt_per_fixed_value,
6333 total_num_links, num_weights_per_link,
6334 num_src_fields, total_num_links_per_src_field,
6335 weights->src_locations, weights->tgt_location,
6336 src_grid_size, tgt_grid_size);
6337
6338 free(total_num_links_per_src_field);
6339 free(total_num_tgt_per_fixed_value);
6340 }
6341 free(fixed_values);
6342
6343 // ensure that the basic weight file has been written
6344 yac_mpi_call(MPI_Barrier(io_comm), comm);
6345 yac_mpi_call(MPI_Comm_free(&io_comm), comm);
6346
6347 int ncid;
6348
6349 // open weight file
6350 yac_nc_open(filename, NC_WRITE | NC_SHARE, &ncid);
6351
6352 if (num_fixed_tgt > 0) {
6353
6354 int * tgt_address_fixed =
6355 xmalloc(num_fixed_tgt * sizeof(*tgt_address_fixed));
6356 stencil_get_tgt_address(io_stencils, num_fixed_tgt, tgt_address_fixed);
6357
6358 // inquire variable ids
6359 int var_dst_add_fixed_id;
6360 yac_nc_inq_varid(ncid, "dst_address_fixed", &var_dst_add_fixed_id);
6361
6362 // target ids that receive a fixed value to file
6363 for (size_t i = 0, offset = 0; i < num_fixed_values; ++i) {
6364
6365 if (num_tgt_per_fixed_value[i] == 0) continue;
6366
6367 size_t start[1] = {fixed_offsets[i]};
6368 size_t count[1] = {num_tgt_per_fixed_value[i]};
6370 nc_put_vara_int(
6371 ncid, var_dst_add_fixed_id, start, count, tgt_address_fixed + offset));
6372 offset += num_tgt_per_fixed_value[i];
6373 }
6374
6375 free(tgt_address_fixed);
6376 }
6377
6378 if (num_links > 0) {
6379
6380 int * src_address_link = xmalloc(num_links * sizeof(*src_address_link));
6381 int * tgt_address_link = xmalloc(num_links * sizeof(*tgt_address_link));
6382 double * w = xmalloc(num_links * num_weights_per_link * sizeof(*w));
6384 io_stencils + num_fixed_tgt, io_stencil_count - num_fixed_tgt,
6385 num_links_per_src_field, num_src_fields,
6386 src_address_link, tgt_address_link, w);
6387
6388 int var_src_add_id, var_dst_add_id, var_weight_id;
6389 yac_nc_inq_varid(ncid, "src_address", &var_src_add_id);
6390 yac_nc_inq_varid(ncid, "dst_address", &var_dst_add_id);
6391 yac_nc_inq_varid(ncid, "remap_matrix", &var_weight_id);
6392
6393 for (size_t i = 0, offset = 0; i < num_src_fields; ++i) {
6394
6395 if (num_links_per_src_field[i] == 0) continue;
6396
6397 size_t start[2] = {link_offsets[i], 0};
6398 size_t count[2] = {num_links_per_src_field[i], num_weights_per_link};
6399
6401 nc_put_vara_int(
6402 ncid, var_src_add_id, start, count, src_address_link + offset));
6404 nc_put_vara_int(
6405 ncid, var_dst_add_id, start, count, tgt_address_link + offset));
6407 nc_put_vara_double(
6408 ncid, var_weight_id, start, count,
6409 w + num_weights_per_link * offset));
6410
6411 offset += num_links_per_src_field[i];
6412 }
6413
6414 free(w);
6415 free(tgt_address_link);
6416 free(src_address_link);
6417 }
6418
6419 // close weight file
6420 YAC_HANDLE_ERROR(nc_close(ncid));
6421
6422 // ensure that the writing of the weight file is complete
6423 yac_mpi_call(MPI_Barrier(comm), comm);
6424
6425 free(size_t_buffer);
6426 yac_interp_weight_stencils_delete(io_stencils, io_stencil_count);
6427#endif
6428}
6429
6431 struct yac_interp_weights * weights) {
6432
6433 return weights->stencils_size;
6434}
6435
6437 struct yac_interp_weights * weights) {
6438
6439 struct interp_weight_stencil * stencils = weights->stencils;
6440 size_t stencils_size = weights->stencils_size;
6441
6442 yac_int * global_ids = xmalloc(stencils_size * sizeof(*global_ids));
6443
6444 for (size_t i = 0; i < stencils_size; ++i)
6445 global_ids[i] = stencils[i].tgt.global_id;
6446
6447 return global_ids;
6448}
6449
6451 return weights->comm;
6452}
6453
6455
6456 if (weights == NULL) return;
6457
6458 yac_mpi_call(MPI_Comm_free(&weights->comm), weights->comm);
6459 yac_interp_weight_stencils_delete(weights->stencils, weights->stencils_size);
6460 free(weights->src_locations);
6461 free(weights);
6462}
6463
6470
6473
6474#define COPY_ARRAY(DATA, COUNT) \
6475{ \
6476 size_t size = COUNT * sizeof(*(interp_weights_data.DATA)); \
6477 interp_weights_data_copy.DATA = xmalloc(size); \
6478 memcpy(interp_weights_data_copy.DATA, interp_weights_data.DATA, size); \
6479}
6480
6481 struct yac_interp_weights_data interp_weights_data_copy;
6482
6483 interp_weights_data_copy.frac_mask_fallback_value =
6485 interp_weights_data_copy.scaling_factor =
6487 interp_weights_data_copy.scaling_summand =
6489
6490 size_t total_num_fixed_tgt = 0;
6491 for (size_t i = 0; i < interp_weights_data.num_fixed_values; ++i)
6492 total_num_fixed_tgt += interp_weights_data.num_tgt_per_fixed_value[i];
6493 interp_weights_data_copy.num_fixed_values =
6497 COPY_ARRAY(tgt_idx_fixed, total_num_fixed_tgt)
6498
6499 size_t num_weights = 0;
6500 for (size_t i = 0; i < interp_weights_data.num_wgt_tgt; ++i)
6501 num_weights += interp_weights_data.num_src_per_tgt[i];
6502 interp_weights_data_copy.num_wgt_tgt = interp_weights_data.num_wgt_tgt;
6505 COPY_ARRAY(weights, num_weights)
6506 COPY_ARRAY(src_field_idx, num_weights)
6507 COPY_ARRAY(src_idx, num_weights)
6508 interp_weights_data_copy.num_src_fields =
6511
6512#undef COPY_ARRAY
6513
6514 return interp_weights_data_copy;
6515}
6516
unsigned num_fields
#define YAC_ASSERT(exp, msg)
#define UNUSED(x)
Definition core.h:72
#define ENSURE_ARRAY_SIZE(arrayp, curr_array_size, req_size)
int yac_collection_selection_is_contiguous(struct yac_collection_selection const *collection_selection)
Query whether a selection is contiguous.
size_t yac_collection_selection_get_collection_size(struct yac_collection_selection const *collection_selection)
Get the size of the collection selection.
void yac_collection_selection_delete(struct yac_collection_selection *collection_selection)
Delete a collection selection object.
struct yac_collection_selection * yac_collection_selection_new(size_t collection_size, size_t const *selection_indices)
Create a new collection selection.
enum callback_type type
struct @23::@24 value
#define YAC_WEIGHT_FILE_VERSION_STRING
static Xt_redist * generate_src_field_exchange_redists(struct yac_src_field_exchange_data *src_field_exchange_data, size_t num_src_fields, MPI_Comm comm, Xt_config redist_config)
static struct yac_interpolation * yac_interp_weights_get_interpolation_(struct yac_interp_weights const *weights, enum yac_interp_weights_reorder_type reorder, struct yac_collection_selection const *collection_selection, double frac_mask_fallback_value, double scaling_factor, double scaling_summand, char const *yaxt_exchanger_name, int is_source, int is_target)
static void interpolation_raw_add_wsum_mf(struct remote_point_info_reorder *src_points, size_t num_src_points, size_t num_src_fields, size_t tgt_count, struct interp_weight_stencil_wsum_mf *tgt_stencils, size_t *num_src_per_tgt, double *weights, size_t *src_idx, size_t *src_field_idx, MPI_Comm comm, void *interp_raw, Xt_config redist_config)
static void interpolation_add_wsum(struct remote_point_info_reorder *remote_src_points, size_t halo_size, size_t num_src_fields, size_t tgt_count, struct interp_weight_stencil_wsum_mf *tgt_stencils, size_t *num_src_per_tgt, double *weights, size_t *src_idx, size_t *src_field_idx, MPI_Comm comm, enum yac_interp_weights_reorder_type reorder, void *interp, Xt_config redist_config)
static MPI_Datatype get_fixed_stencil_mpi_datatype(MPI_Comm comm)
static size_t get_num_links_per_src_field(struct interp_weight_stencil *stencil, size_t src_field_idx)
static int get_stencil_pack_size_direct_mf(struct interp_weight_stencil *stencil, MPI_Datatype point_info_dt, MPI_Comm comm)
static void interp_add_direct_raw(void *interp, size_t *src_orig_poses, size_t *sendcounts, struct interp_weight_stencil_direct *tgt_stencils, size_t *recvcounts, MPI_Comm comm, Xt_config redist_config)
static void interpolation_add_w_sum_mf(struct remote_point_info_reorder *remote_src_points, size_t halo_size, size_t num_src_fields, size_t tgt_count, struct interp_weight_stencil_wsum_mf *tgt_stencils, size_t *num_src_per_tgt, double *weights, size_t *src_idx, size_t *src_field_idx, MPI_Comm comm, enum yac_interp_weights_reorder_type reorder, struct yac_interpolation *interp, void(*interp_add_wsum_mf_at_src)(struct yac_interpolation *, Xt_redist *, size_t, size_t *, double *, size_t *, size_t *, size_t, Xt_redist), void(*interp_add_wsum_mf_at_tgt)(struct yac_interpolation *, Xt_redist *, size_t *, size_t, size_t *, double *, size_t *, size_t *, size_t), Xt_config redist_config)
static void interpolation_raw_add_sum(struct remote_point_info_reorder *src_points, size_t num_src_points, size_t num_src_fields, size_t tgt_count, struct interp_weight_stencil_wsum_mf *tgt_stencils, size_t *num_src_per_tgt, double *weights, size_t *src_idx, size_t *src_field_idx, MPI_Comm comm, void *interp_raw, Xt_config redist_config)
static void unpack_stencil_wsum_mf(struct interp_weight_stencil *stencil, void *buffer, int buffer_size, int *position, MPI_Datatype point_info_dt, MPI_Comm comm)
static MPI_Datatype get_direct_stencil_mpi_datatype(MPI_Comm comm)
static void stencil_determine_tgt_global_id_range(struct interp_weight_stencil *stencils, size_t stencils_size, yac_int *min_tgt_global_id, yac_int *max_tgt_global_id, MPI_Comm comm)
static void unpack_stencil_sum_mf(struct interp_weight_stencil *stencil, void *buffer, int buffer_size, int *position, MPI_Datatype point_info_dt, MPI_Comm comm)
void yac_interp_weights_add_fixed(struct yac_interp_weights *weights, struct remote_points *tgts, double fixed_value)
struct yac_interp_weights_data yac_interp_weights_data_copy(struct yac_interp_weights_data interp_weights_data)
struct yac_interpolation * yac_interp_weights_get_interpolation(struct yac_interp_weights *weights, enum yac_interp_weights_reorder_type reorder, size_t collection_size, double frac_mask_fallback_value, double scaling_factor, double scaling_summand, char const *yaxt_exchanger_name, int is_source, int is_target)
static int compare_stencils_direct_mf(const void *a, const void *b)
void yac_interp_weights_add_sum_mf(struct yac_interp_weights *weights, struct remote_points *tgts, size_t *num_src_per_field_per_tgt, struct remote_point **srcs_per_field, size_t num_src_fields)
static void yac_interp_weights_redist_direct_mf(MPI_Comm comm, size_t count, struct interp_weight_stencil *direct_mf_stencils, void *interp, void(*interp_add_direct_mf)(void *, size_t, size_t *, size_t *, struct interp_weight_stencil_direct_mf *, size_t *, MPI_Comm, Xt_config), Xt_config redist_config, int *rank_is_source, int *rank_is_target)
static struct remote_points * copy_remote_points_mf(struct remote_point **points, size_t *counts, size_t num_fields)
static struct interp_weight_stencils_wsum_mf * redist_wsum_mf_stencils_tgt(MPI_Comm comm, struct interp_weight_stencils_wsum_mf *wsum_stencils_data)
static int compare_remote_point_info(const void *a, const void *b)
static void yac_src_field_exchange_data_realloc(struct yac_interpolation_raw *interp_raw, size_t num_src_fields)
static int global_id_to_address(yac_int global_id)
static void yac_interp_weights_get_interpolation_raw_(struct yac_interp_weights const *weights, struct yac_collection_selection const *collection_selection, double frac_mask_fallback_value, double scaling_factor, double scaling_summand, char const *yaxt_exchanger_name, struct yac_interpolation_exchange **interpolation_exchange, struct yac_interp_weights_data *interp_weights_data, int is_source, int is_target)
static int get_stencil_pack_size_sum(struct interp_weight_stencil *stencil, MPI_Datatype point_info_dt, MPI_Comm comm)
void yac_interp_weights_data_init(struct yac_interp_weights_data *interp_weights_data)
#define COPY_ARRAY(DATA, COUNT)
static void pack_stencil_direct(struct interp_weight_stencil *stencil, void *buffer, int buffer_size, int *position, MPI_Datatype point_info_dt, MPI_Comm comm)
yac_interp_weight_stencil_type
@ DIRECT
@ WEIGHT_SUM_MF
@ DIRECT_MF
@ SUM_MF
@ SUM
@ FIXED
@ WEIGHT_SUM
@ WEIGHT_STENCIL_TYPE_SIZE
static void interpolation_add_sum_mf(struct remote_point_info_reorder *remote_src_points, size_t halo_size, size_t num_src_fields, size_t tgt_count, struct interp_weight_stencil_wsum_mf *tgt_stencils, size_t *num_src_per_tgt, double *weights, size_t *src_idx, size_t *src_field_idx, MPI_Comm comm, enum yac_interp_weights_reorder_type reorder, void *interp, Xt_config redist_config)
static void pack_stencil_wsum(struct interp_weight_stencil *stencil, void *buffer, int buffer_size, int *position, MPI_Datatype point_info_dt, MPI_Comm comm)
static void yac_src_field_exchange_data_msgs_add(struct yac_src_field_exchange_data_msgs *msgs, int rank, size_t count, size_t *pos, size_t offset)
static void free_remote_points(struct remote_points *points)
static void interpolation_add_wsum_mf(struct remote_point_info_reorder *remote_src_points, size_t halo_size, size_t num_src_fields, size_t tgt_count, struct interp_weight_stencil_wsum_mf *tgt_stencils, size_t *num_src_per_tgt, double *weights, size_t *src_idx, size_t *src_field_idx, MPI_Comm comm, enum yac_interp_weights_reorder_type reorder, void *interp, Xt_config redist_config)
static struct remote_point_info select_src(char const *routine, struct remote_point_infos src, int *rank_is_source)
static void yac_interp_weights_redist_fixed(MPI_Comm comm, size_t count, struct interp_weight_stencil *fixed_stencils, void *interp, void(*interp_add_fixed)(void *, double, size_t, size_t *), int *rank_is_target)
static struct remote_point copy_remote_point_masked(char const *routine, struct remote_point point, int *rank_is_target)
struct yac_interpolation * yac_interp_weights_get_interpolation_ext(struct yac_interp_weights const *weights, struct yac_interpolation_gen_config const *config, int is_source, int is_target)
static void interpolation_raw_add_w_sum_mf(struct remote_point_info_reorder *remote_src_points, size_t num_src_points, size_t num_src_fields, size_t tgt_count, struct interp_weight_stencil_wsum_mf *tgt_stencils, size_t *num_src_per_tgt, double *weights, size_t *src_idx, size_t *src_field_idx, MPI_Comm comm, struct yac_interpolation_raw *interp_raw, Xt_config redist_config)
static void yac_interp_weight_stencils_delete(struct interp_weight_stencil *stencils, size_t count)
static void interpolation_raw_add_sum_mf(struct remote_point_info_reorder *src_points, size_t num_src_points, size_t num_src_fields, size_t tgt_count, struct interp_weight_stencil_wsum_mf *tgt_stencils, size_t *num_src_per_tgt, double *weights, size_t *src_idx, size_t *src_field_idx, MPI_Comm comm, void *interp_raw, Xt_config redist_config)
static void interpolation_add_sum(struct remote_point_info_reorder *remote_src_points, size_t halo_size, size_t num_src_fields, size_t tgt_count, struct interp_weight_stencil_wsum_mf *tgt_stencils, size_t *num_src_per_tgt, double *weights, size_t *src_idx, size_t *src_field_idx, MPI_Comm comm, enum yac_interp_weights_reorder_type reorder, void *interp, Xt_config redist_config)
static int compare_stencils_fixed(const void *a, const void *b)
static void interp_add_direct_mf_raw(void *interp, size_t num_src_fields, size_t *src_orig_poses, size_t *sendcounts, struct interp_weight_stencil_direct_mf *tgt_stencils, size_t *recvcounts, MPI_Comm comm, Xt_config redist_config)
static struct interp_weight_stencil stencils_merge(struct interp_weight_stencil **stencils, double *w, size_t num_stencils, struct remote_point point)
static int get_stencil_wsum_mf_pack_size(struct interp_weight_stencil_wsum_mf *stencil, MPI_Datatype wsum_mf_weight_dt, MPI_Datatype point_info_dt, MPI_Comm comm)
void yac_interp_weights_add_wsum(struct yac_interp_weights *weights, struct remote_points *tgts, size_t *num_src_per_tgt, struct remote_point *srcs, double *w)
static struct interp_weight_stencil stencils_merge_sum(struct interp_weight_stencil **stencils, double *w, size_t num_stencils)
static int compare_w_global_id(const void *a, const void *b)
static void compact_srcs_w(struct remote_points *srcs, double **w)
void yac_interp_weights_delete(struct yac_interp_weights *weights)
void yac_interp_weights_get_interpolation_raw(struct yac_interp_weights *weights, size_t collection_size, double frac_mask_fallback_value, double scaling_factor, double scaling_summand, char const *yaxt_exchanger_name, struct yac_interpolation_exchange **interpolation_exchange, struct yac_interp_weights_data *interp_weights_data, int is_source, int is_target)
static size_t unpack_stencils_wsum_mf(struct interp_weight_stencil_wsum_mf *wsum_stencils, struct interp_weight_stencil_wsum_mf_weight *weight_buffer, size_t count, void *packed_data, size_t packed_data_size, MPI_Comm comm)
static void pack_stencil_sum(struct interp_weight_stencil *stencil, void *buffer, int buffer_size, int *position, MPI_Datatype point_info_dt, MPI_Comm comm)
static void determine_stencils_io_owner(struct interp_weight_stencil *stencils, size_t stencils_size, yac_int min_tgt_global_id, yac_int max_tgt_global_id, int num_io_procs_int, int *io_owner)
static Xt_redist * generate_direct_mf_redists(size_t *src_orig_poses, size_t *sendcounts, struct interp_weight_stencil_direct_mf *tgt_stencils, size_t *recvcounts, size_t num_src_fields, MPI_Comm comm, Xt_config redist_config)
static size_t get_num_weights_per_link(struct interp_weight_stencil *stencil)
static void free_remote_point(struct remote_point point)
static void yac_interp_weights_redist_stencils(MPI_Comm comm, size_t count, struct interp_weight_stencil *stencils, int *owner_ranks, size_t *new_count, struct interp_weight_stencil **new_stencils)
static struct yac_src_field_exchange_data_msg * yac_src_field_exchange_data_msgs_get_msg(struct yac_src_field_exchange_data_msgs *msgs, int rank)
void yac_interp_weights_data_free(struct yac_interp_weights_data interp_weights_data)
static void unpack_stencil_wsum(struct interp_weight_stencil *stencil, void *buffer, int buffer_size, int *position, MPI_Datatype point_info_dt, MPI_Comm comm)
void yac_interp_weights_wcopy_weights(struct yac_interp_weights *weights, struct remote_points *tgts, size_t *num_stencils_per_tgt, size_t *stencil_indices, int *stencil_ranks, double *w)
static int compare_interp_weight_stencil(const void *a, const void *b)
static Xt_config get_redist_config(char const *yaxt_exchanger_name, MPI_Comm comm)
static void yac_interp_weights_redist_w_sum_mf(MPI_Comm comm, struct interp_weight_stencils_wsum_mf *wsum_mf_stencils_data, struct yac_interpolation *interp, enum yac_interp_weights_reorder_type reorder, void(*interp_add_w_sum_mf)(struct remote_point_info_reorder *, size_t, size_t, size_t, struct interp_weight_stencil_wsum_mf *, size_t *, double *, size_t *, size_t *, MPI_Comm, enum yac_interp_weights_reorder_type, void *, Xt_config), Xt_config redist_config)
static void pack_stencil_wsum_mf(struct interp_weight_stencil *stencil, void *buffer, int buffer_size, int *position, MPI_Datatype point_info_dt, MPI_Comm comm)
void yac_interp_weights_add_wsum_mf(struct yac_interp_weights *weights, struct remote_points *tgts, size_t *num_src_per_field_per_tgt, struct remote_point **srcs_per_field, double *w, size_t num_src_fields)
static int compare_rank_pos_reorder_field_idx(const void *a, const void *b)
static int get_stencil_pack_size_wsum(struct interp_weight_stencil *stencil, MPI_Datatype point_info_dt, MPI_Comm comm)
static void pack_stencils(struct interp_weight_stencil *stencils, size_t count, size_t *pack_order, void **pack_data, int *pack_sizes, MPI_Datatype point_info_dt, MPI_Comm comm)
static void yac_src_field_exchange_data_init(struct yac_src_field_exchange_data *src_field_exchange_data)
static void interp_add_fixed(void *interp, double fixed_value, size_t count, size_t *tgt_pos)
static void get_stencils_pack_sizes(struct interp_weight_stencil *stencils, size_t count, size_t *pack_order, int *pack_sizes, MPI_Datatype point_info_dt, MPI_Comm comm)
yac_int * yac_interp_weights_get_interp_tgt(struct yac_interp_weights *weights)
static int get_stencil_pack_size_sum_mf(struct interp_weight_stencil *stencil, MPI_Datatype point_info_dt, MPI_Comm comm)
static void pack_stencil_fixed(struct interp_weight_stencil *stencil, void *buffer, int buffer_size, int *position, MPI_Datatype point_info_dt, MPI_Comm comm)
static void yac_src_field_exchange_data_add(struct yac_src_field_exchange_data *src_field_exchange_data, size_t num_src_fields, MPI_Comm comm, size_t *send_msg_sizes, size_t *send_pos, size_t *recv_msg_sizes, size_t *recv_pos, size_t *recv_offsets)
static int get_stencil_pack_size_wsum_mf(struct interp_weight_stencil *stencil, MPI_Datatype point_info_dt, MPI_Comm comm)
static struct interp_weight_stencil wcopy_interp_weight_stencil(struct interp_weight_stencil *stencil, struct remote_point point, double weight)
static Xt_redist generate_direct_redist(size_t *src_orig_poses, size_t *sendcounts, struct interp_weight_stencil_direct *tgt_stencils, size_t *recvcounts, MPI_Comm comm, Xt_config redist_config)
static struct interp_weight_stencil * yac_interp_weights_get_stencils(struct yac_interp_weights *weights, size_t *stencil_indices, int *stencil_ranks, size_t count)
static void unpack_stencil_direct_mf(struct interp_weight_stencil *stencil, void *buffer, int buffer_size, int *position, MPI_Datatype point_info_dt, MPI_Comm comm)
static int compare_stencils(const void *a, const void *b)
static void create_weight_file(char const *filename, char const *src_grid_name, char const *tgt_grid_name, size_t num_fixed_values, double *fixed_values, size_t *num_tgt_per_fixed_value, size_t num_links, size_t num_weights_per_link, size_t num_src_fields, size_t *num_links_per_src_field, enum yac_location *src_locations, enum yac_location tgt_location, size_t src_grid_size, size_t tgt_grid_size)
static int get_stencil_pack_size_direct(struct interp_weight_stencil *stencil, MPI_Datatype point_info_dt, MPI_Comm comm)
static void stencil_get_counts(struct interp_weight_stencil *stencils, size_t stencil_count, size_t num_fixed_values, double *fixed_values, size_t *num_tgt_per_fixed_value, size_t *num_fixed_tgt, size_t num_src_fields, size_t *num_links_per_src_field, size_t *num_links)
static void copy_remote_points_no_alloc(struct remote_point *points_to, struct remote_point *points_from, size_t count, struct remote_point_info **point_info_buffer_)
static void interpolation_raw_add_wsum(struct remote_point_info_reorder *src_points, size_t num_src_points, size_t num_src_fields, size_t tgt_count, struct interp_weight_stencil_wsum_mf *tgt_stencils, size_t *num_src_per_tgt, double *weights, size_t *src_idx, size_t *src_field_idx, MPI_Comm comm, void *interp_raw, Xt_config redist_config)
#define WEIGHT_TOL
static struct remote_points * copy_remote_points(struct remote_point *points, size_t count)
static void interpolation_add_sum_at_src(struct yac_interpolation *interp, Xt_redist *halo_redists, size_t tgt_count, size_t *num_src_per_tgt, double *weights, size_t *src_field_idx, size_t *src_idx, size_t num_src_fields, Xt_redist result_redist)
static Xt_redist generate_redist_put_double(struct remote_point_infos *point_infos, size_t count, MPI_Comm comm, Xt_config redist_config)
static int compare_remote_point(const void *a, const void *b)
static struct interp_weight_stencils_wsum_mf * generate_w_sum_mf_stencils(struct interp_weight_stencil *stencils, size_t count, enum yac_interp_weight_stencil_type stencil_type, int *rank_is_source, int *rank_is_target)
static MPI_Datatype get_direct_mf_stencil_mpi_datatype(MPI_Comm comm)
#define YAC_YAXT_EXCHANGER_STR
MPI_Comm yac_interp_weights_get_comm(struct yac_interp_weights *weights)
static MPI_Datatype get_wsum_mf_weight_mpi_datatype(MPI_Comm comm)
static struct interp_weight_stencil copy_interp_weight_stencil(struct interp_weight_stencil *stencil, struct remote_point point)
void yac_interp_weights_add_direct(struct yac_interp_weights *weights, struct remote_points *tgts, struct remote_point *srcs)
void yac_interp_weights_add_sum(struct yac_interp_weights *weights, struct remote_points *tgts, size_t *num_src_per_tgt, struct remote_point *srcs)
static void unpack_stencil_direct(struct interp_weight_stencil *stencil, void *buffer, int buffer_size, int *position, MPI_Datatype point_info_dt, MPI_Comm comm)
static int compare_interp_weight_stencil_wsum_mf_tgt_orig_pos(const void *a, const void *b)
static void interp_raw_add_fixed(void *interp, double fixed_value, size_t count, size_t *tgt_pos)
struct yac_interp_weights * yac_interp_weights_new(MPI_Comm comm, enum yac_location tgt_location, enum yac_location *src_locations, size_t num_src_fields)
static void unpack_stencil_sum(struct interp_weight_stencil *stencil, void *buffer, int buffer_size, int *position, MPI_Datatype point_info_dt, MPI_Comm comm)
static struct interp_weight_stencils_wsum_mf * redist_wsum_mf_stencils(MPI_Comm comm, struct interp_weight_stencils_wsum_mf *wsum_stencils_data, int *stencil_owner, size_t *reorder_idx, size_t num_owners)
static struct interp_weight_stencils_wsum_mf * redist_wsum_mf_stencils_src(MPI_Comm comm, struct interp_weight_stencils_wsum_mf *wsum_stencils_data)
static int compare_stencils_direct(const void *a, const void *b)
static void yac_interp_weights_data_init_(double frac_mask_fallback_value, double scaling_factor, double scaling_summand, struct yac_interp_weights_data *interp_weights_data)
static size_t stencil_get_num_weights_per_tgt(struct interp_weight_stencil *stencils, size_t stencil_count, MPI_Comm comm)
static void stencil_get_tgt_address(struct interp_weight_stencil *stencils, size_t stencil_count, int *tgt_address)
static int get_stencil_pack_size_fixed(struct interp_weight_stencil *stencil, MPI_Datatype point_info_dt, MPI_Comm comm)
static struct remote_point copy_remote_point(struct remote_point point)
static void stencil_get_link_data(struct interp_weight_stencil *stencils, size_t stencil_count, size_t *num_links_per_src_field, size_t num_src_fields, int *src_address, int *tgt_address, double *weight)
static void interp_add_direct(void *interp, size_t *src_orig_poses, size_t *sendcounts, struct interp_weight_stencil_direct *tgt_stencils, size_t *recvcounts, MPI_Comm comm, Xt_config redist_config)
size_t yac_interp_weights_get_interp_count(struct yac_interp_weights *weights)
static struct interp_weight_stencil stencils_merge_wsum(struct interp_weight_stencil **stencils, double *w, size_t num_stencils)
static void pack_stencil_sum_mf(struct interp_weight_stencil *stencil, void *buffer, int buffer_size, int *position, MPI_Datatype point_info_dt, MPI_Comm comm)
static Xt_redist * generate_halo_redists(struct remote_point_info_reorder *halo_points, size_t count, size_t num_src_fields, MPI_Comm comm, Xt_config redist_config)
static void pack_stencil_direct_mf(struct interp_weight_stencil *stencil, void *buffer, int buffer_size, int *position, MPI_Datatype point_info_dt, MPI_Comm comm)
static void pack_stencils_wsum_mf(struct interp_weight_stencil_wsum_mf *wsum_stencils, size_t count, size_t *pack_order, void **pack_data, int *pack_sizes, int *weight_counts, MPI_Comm comm)
struct yac_interpolation * yac_interp_weights_get_interpolation_f2c(struct yac_interp_weights *weights, int reorder, size_t collection_size, double frac_mask_fallback_value, double scaling_factor, double scaling_summand, char const *yaxt_exchanger_name, int is_source, int is_target)
static int compare_interp_weight_stencil_wsum_mf_src_orig_pos(const void *a, const void *b)
static struct interp_weight_stencil * exchange_stencils(MPI_Comm comm, struct interp_weight_stencil *stencils, size_t *stencil_indices, size_t *stencil_sendcounts, size_t *stencil_recvcounts)
static int remote_point_is_valid(char const *routine, struct remote_point point, int *rank_is_target)
static void unpack_stencil_fixed(struct interp_weight_stencil *stencil, void *buffer, int buffer_size, int *position, MPI_Datatype point_info_dt, MPI_Comm comm)
static int compare_double(void const *a, void const *b)
static void stencil_xscan_offsets(size_t num_fixed_values, size_t *num_tgt_per_fixed_value, size_t num_src_fields, size_t *num_links_per_src_field, size_t *fixed_offsets, size_t *link_offsets, MPI_Comm comm)
void yac_interp_weights_get_interpolation_raw_ext(struct yac_interp_weights const *weights, struct yac_interpolation_gen_config const *config, struct yac_interpolation_exchange **interpolation_exchange, struct yac_interp_weights_data *interp_weights_data, int is_source, int is_target)
static void interpolation_add_sum_at_tgt(struct yac_interpolation *interp, Xt_redist *src_redists, size_t *tgt_pos, size_t tgt_count, size_t *num_src_per_tgt, double *weights, size_t *src_field_idx, size_t *src_idx, size_t num_src_fields)
static void yac_interp_weights_redist_direct(MPI_Comm comm, size_t count, struct interp_weight_stencil *direct_stencils, void *interp, void(*interp_add_direct)(void *, size_t *, size_t *, struct interp_weight_stencil_direct *, size_t *, MPI_Comm, Xt_config), Xt_config redist_config, int *rank_is_source, int *rank_is_target)
static void interp_add_direct_mf(void *interp, size_t num_src_fields, size_t *src_orig_poses, size_t *sendcounts, struct interp_weight_stencil_direct_mf *tgt_stencils, size_t *recvcounts, MPI_Comm comm, Xt_config redist_config)
void yac_interp_weights_write_to_file(struct yac_interp_weights *weights, char const *filename, char const *src_grid_name, char const *tgt_grid_name, size_t src_grid_size, size_t tgt_grid_size, enum yac_weight_file_on_existing on_existing)
static void xt_redist_msg_free(struct Xt_redist_msg *msgs, size_t count, MPI_Comm comm)
void yac_interp_weights_add_direct_mf(struct yac_interp_weights *weights, struct remote_points *tgts, size_t *src_field_indices, struct remote_point **srcs_per_field, size_t num_src_fields)
static void unpack_stencils(struct interp_weight_stencil *stencils, size_t count, void *packed_data, size_t packed_data_size, MPI_Datatype point_info_dt, MPI_Comm comm)
static void yac_src_field_exchange_data_free(struct yac_src_field_exchange_data *src_field_exchange_data, size_t num_src_fields)
static int compute_owner(int *ranks, size_t count)
static void yac_interp_weights_redist_w_sum_mf_raw(MPI_Comm comm, struct interp_weight_stencils_wsum_mf *wsum_mf_stencils_data, struct yac_interpolation *interp, void(*interp_add_w_sum_mf)(struct remote_point_info_reorder *, size_t, size_t, size_t, struct interp_weight_stencil_wsum_mf *, size_t *, double *, size_t *, size_t *, MPI_Comm, void *, Xt_config), Xt_config redist_config)
static void stencil_get_fixed_values(struct interp_weight_stencil *stencils, size_t stencil_count, double **fixed_values, size_t *num_fixed_values, MPI_Comm comm)
static void yac_interp_weights_data_set_wgt_tgt(struct yac_interp_weights_data *interp_weights_data, size_t num_src_fields, size_t tgt_count, size_t *tgt_idx, size_t *num_src_per_tgt, double *weights, size_t *src_field_idx, size_t *src_idx, size_t *src_field_buffer_size)
yac_interp_weights_reorder_type
@ YAC_MAPPING_ON_TGT
weights will be applied at target processes
@ YAC_MAPPING_ON_SRC
weights will be applied at source processes
yac_weight_file_on_existing
@ YAC_WEIGHT_FILE_KEEP
keep existing weight file
@ YAC_WEIGHT_FILE_ERROR
error when weight file existis already
void yac_interpolation_add_sum_at_src(struct yac_interpolation *interp, Xt_redist *halo_redists, size_t tgt_count, size_t *num_src_per_tgt, size_t *src_field_idx, size_t *src_idx, size_t num_src_fields, Xt_redist result_redist)
Add a sum operator where accumulation occurs on source processes.
void yac_interpolation_add_weight_sum_mvp_at_tgt(struct yac_interpolation *interp, Xt_redist *src_redists, size_t *tgt_pos, size_t tgt_count, size_t *num_src_per_tgt, double *weights, size_t *src_field_idx, size_t *src_idx, size_t num_src_fields)
Add a weighted sum operator (distributed matrix-vector product), which computes the product at the ta...
void yac_interpolation_add_direct_mf(struct yac_interpolation *interp, Xt_redist *redists, size_t num_src_fields)
Add a direct redistribution operator for multiple source fields.
void yac_interpolation_add_sum_at_tgt(struct yac_interpolation *interp, Xt_redist *src_redists, size_t *tgt_pos, size_t tgt_count, size_t *num_src_per_tgt, size_t *src_field_idx, size_t *src_idx, size_t num_src_fields)
Add a sum operator where accumulation occurs on target processes.
void yac_interpolation_add_fixed(struct yac_interpolation *interp, double value, size_t count, size_t *pos)
Add a fixed-value operator to an interpolation.
double const YAC_FRAC_MASK_UNDEF
void yac_interpolation_add_direct(struct yac_interpolation *interp, Xt_redist redist)
Add a direct redistribution operator.
struct yac_interpolation * yac_interpolation_new(struct yac_collection_selection const *collection_selection, double frac_mask_fallback_value, double scale_factor, double scale_summand)
Create a new interpolation object.
void yac_interpolation_add_weight_sum_mvp_at_src(struct yac_interpolation *interp, Xt_redist *halo_redists, size_t tgt_count, size_t *num_src_per_tgt, double *weights, size_t *src_field_idx, size_t *src_idx, size_t num_src_fields, Xt_redist result_redist)
Add a weighted sum operator (distributed matrix-vector product), which computes the productes at the ...
struct Xt_redist_ * Xt_redist
struct yac_interpolation_exchange * yac_interpolation_exchange_new(Xt_redist *redists, size_t num_fields, size_t collection_size, int with_frac_mask, char const *name)
Create a new interpolation exchange object.
Interpolation exchange object for temporary buffers and MPI exchanges.
enum yac_interp_weights_reorder_type yac_interpolation_gen_config_get_reorder(struct yac_interpolation_gen_config const *config)
Get the configured reordering strategy.
double yac_interpolation_gen_config_get_frac_mask_fallback_value(struct yac_interpolation_gen_config const *config)
Get the configured fractional mask fallback value.
double yac_interpolation_gen_config_get_scaling_factor(struct yac_interpolation_gen_config const *config)
Get the configured scaling factor.
struct yac_collection_selection const * yac_interpolation_gen_config_get_collection_selection(struct yac_interpolation_gen_config const *config)
Get the configured collection selection.
const char * yac_interpolation_gen_config_get_yaxt_exchanger_name(struct yac_interpolation_gen_config const *config)
Get the configured Yaxt exchanger name.
double yac_interpolation_gen_config_get_scaling_summand(struct yac_interpolation_gen_config const *config)
Get the configured scaling summand.
#define YAC_FRAC_MASK_VALUE_IS_VALID(value)
Test whether a fractional mask value is valid.
void yac_get_io_ranks(MPI_Comm comm, int *local_is_io_, int **io_ranks_, int *num_io_ranks_)
Definition io_utils.c:271
void yac_nc_create(const char *path, int cmode, int *ncidp)
Definition io_utils.c:326
void yac_nc_inq_varid(int ncid, char const *name, int *varidp)
Definition io_utils.c:369
int yac_file_exists(const char *filename)
Check whether a file exists.
Definition io_utils.c:394
void yac_nc_open(const char *path, int omode, int *ncidp)
Definition io_utils.c:311
char const * yac_loc2str(enum yac_location location)
Definition location.c:33
yac_location
Definition location.h:12
#define YAC_MAX_LOC_STR_LEN
Definition location.h:10
Definition __init__.py:1
add versions of standard API functions not returning on error
#define xstrdup(s)
Definition ppm_xfuncs.h:84
#define xrealloc(ptr, size)
Definition ppm_xfuncs.h:67
#define xmalloc(size)
Definition ppm_xfuncs.h:66
void yac_remote_point_pack(struct remote_point *point, void *buffer, int buffer_size, int *position, MPI_Datatype point_info_dt, MPI_Comm comm)
void yac_remote_point_unpack(void *buffer, int buffer_size, int *position, struct remote_point *point, MPI_Datatype point_info_dt, MPI_Comm comm)
void yac_remote_points_pack(struct remote_points *points, void *buffer, int buffer_size, int *position, MPI_Datatype point_info_dt, MPI_Comm comm)
void yac_remote_points_unpack(void *buffer, int buffer_size, int *position, struct remote_points **points, MPI_Datatype point_info_dt, MPI_Comm comm)
int yac_remote_points_get_pack_size(struct remote_points *points, MPI_Datatype point_info_dt, MPI_Comm comm)
MPI_Datatype yac_get_remote_point_info_mpi_datatype(MPI_Comm comm)
int yac_remote_point_get_pack_size(struct remote_point *point, MPI_Datatype point_info_dt, MPI_Comm comm)
struct remote_point_info src
struct remote_point_info src
struct interp_weight_stencil_wsum_mf_weight * data
struct interp_weight_stencil::@14::@21 weight_sum_mf
struct remote_points * srcs
struct interp_weight_stencil::@14::@18 weight_sum
union interp_weight_stencil::@14 data
struct interp_weight_stencil::@14::@15 fixed
struct remote_point src
struct interp_weight_stencil::@14::@17 sum
enum yac_interp_weight_stencil_type type
struct remote_point tgt
struct interp_weight_stencil::@14::@20 sum_mf
struct interp_weight_stencil::@14::@19 direct_mf
struct interp_weight_stencil::@14::@16 direct
struct interp_weight_stencils_wsum_mf stencils
struct interp_weight_stencil_wsum_mf_weight buffer[]
struct interp_weight_stencil_wsum_mf * data
struct remote_point_info data
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_info buffer[]
struct remote_point * data
struct interp_weight_stencil * stencils
enum yac_location tgt_location
enum yac_location * src_locations
Configuration structure for interpolation generation.
struct yac_interpolation_raw::yac_src_field_exchange_data::yac_src_field_exchange_data_msgs::yac_src_field_exchange_data_msg * msg
struct yac_interpolation_raw::yac_src_field_exchange_data::yac_src_field_exchange_data_msgs send
struct yac_interpolation_raw::yac_src_field_exchange_data::yac_src_field_exchange_data_msgs recv
struct yac_interp_weights_data interp_weights_data
struct yac_interpolation_raw::yac_src_field_exchange_data * src_field_exchange_data
double frac_mask_fallback_value
struct yac_collection_selection * collection_selection
Selection of field collections to which this interpolation applies.
int collection_size
double * data
char * str_logical[2]
static struct yac_interp_method_config * config
char const src_grid_name[]
char const tgt_grid_name[]
static double const fixed_value
static MPI_Comm split_comm
#define MIN(a, b)
Definition toy_common.h:29
double * buffer
double * send_buffer
double * recv_buffer
#define YAC_HANDLE_ERROR(exp)
Definition toy_output.c:13
#define MAX(a, b)
void yac_quicksort_index_int_double(int *a, size_t n, double *idx)
void yac_quicksort_index_int_size_t(int *a, size_t n, size_t *idx)
void yac_quicksort_index_int_size_t_size_t(int *a, size_t n, size_t *b, size_t *c)
static void yac_remove_duplicates_double(double *array, size_t *n)
Definition utils_core.h:72
void yac_quicksort_index_size_t_size_t(size_t *a, size_t n, size_t *idx)
void yac_quicksort_index(int *a, size_t n, int *idx)
#define SUM
void yac_abort(MPI_Comm comm, const char *msg, const char *source, int line) __attribute__((noreturn))
#define YAC_ASSERT_F(exp, format,...)
Definition yac_assert.h:39
#define die(msg)
Definition yac_assert.h:14
#define YAC_ASSERT_F_FUNC(exp, func, format,...)
Definition yac_assert.h:42
#define YAC_UNREACHABLE_DEFAULT(msg)
Definition yac_assert.h:56
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:583
void yac_free_comm_buffers(size_t *sendcounts, size_t *recvcounts, size_t *sdispls, size_t *rdispls)
Definition yac_mpi.c:639
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:608
MPI_Datatype yac_create_resized(MPI_Datatype dt, size_t new_size, MPI_Comm comm)
Definition yac_mpi.c:562
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:129
#define yac_mpi_call(call, comm)
#define YAC_MPI_SIZE_T
YAC_INT yac_int
Definition yac_types.h:15
#define yac_int_dt
Definition yac_types.h:18