YAC 3.13.0
Yet Another Coupler
Loading...
Searching...
No Matches
test_interp_operator_direct_mf.c
Go to the documentation of this file.
1// Copyright (c) 2025 The YAC Authors
2//
3// SPDX-License-Identifier: BSD-3-Clause
4
5#include <stdlib.h>
6#include <stdio.h>
7#include <string.h>
8#include <unistd.h>
9
10#include <mpi.h>
11#include <yaxt.h>
12
13#include "tests.h"
15#include "yac_mpi.h"
16#include "test_common.h"
19
25static void utest_init_data(
26 struct yac_collection_selection * sel, double **** src_fields_collection,
27 double **** src_fields_frac_mask_collection, double *** tgt_field_collection);
28static void utest_free_data(
29 struct yac_collection_selection * sel, double *** src_fields_collection,
30 double *** src_fields_frac_mask_collection, double ** tgt_field_collection);
31static void utest_check_direct_mf(
32 Xt_redist * redists, size_t num_src_fields,
33 struct yac_collection_selection * sel,
34 double *** src_fields_collection, double ** tgt_field_collection);
35
36enum {
42};
43#define TGT_UNSET_VALUE (-1.0)
44
45int main(void) {
46
47 MPI_Init(NULL, NULL);
48 xt_initialize(MPI_COMM_WORLD);
49
50 int comm_rank, comm_size;
51 MPI_Comm_rank(MPI_COMM_WORLD, &comm_rank);
52 MPI_Comm_size(MPI_COMM_WORLD, &comm_size);
53
54 if (comm_size != NUM_PROCS) {
55 PUT_ERR("ERROR: test requires 2 processes");
56 xt_finalize();
57 MPI_Finalize();
58 return TEST_EXIT_CODE;
59 }
60
61 // collection selection configurations
62 struct {
63 size_t N;
64 size_t * indices;
65 } collection_selection_configs[] =
66 {{.N = 3, .indices = (size_t[]){0, 3, 2}},
67 {.N = 4, .indices = (size_t[]){0, 1, 2, 3}},
68 {.N = MAX_COLLECTION_SIZE, .indices = NULL}};
69 enum {
70 NUM_COLL_SEL_CONFIGS =
71 sizeof(collection_selection_configs) / sizeof(collection_selection_configs[0])
72 };
73
74 // generate yaxt index list containing global ids of all locally available
75 // source points (each source field contains the same global ids)
76 // each process holds the following global ids:
77 // i + comm_rank * NUM_SRC_POINTS
78 // with i in [0..NUM_SRC_POINTS]
79 Xt_int src_global_ids[NUM_SRC_POINTS];
80 for (size_t src_idx = 0; src_idx < NUM_SRC_POINTS; ++src_idx)
81 src_global_ids[src_idx] =
82 (Xt_int)(src_idx + comm_rank * NUM_SRC_POINTS);
83 Xt_idxlist src_idxlist =
84 xt_idxvec_new(src_global_ids, NUM_SRC_POINTS);
85
86 // loop over collection selections
87 for (size_t sel_idx = 0; sel_idx < NUM_COLL_SEL_CONFIGS; ++sel_idx) {
88
89 struct yac_collection_selection * sel =
91 collection_selection_configs[sel_idx].N,
92 collection_selection_configs[sel_idx].indices);
93
94 // interpolation configurations
95 // We assume that the global ids of the source source points of each field
96 // are:
97 // * for rank 0: [0, 1]
98 // * for rank 1: [2, 3]
99 struct {
100 struct {
101
102 //----------------------------------------------------------------------
103 // required source points
104 //----------------------------------------------------------------------
105 struct {
106 int num_indices; // number of source points to be received
107 Xt_int * indices; // global ids of required source points
108 } required_src_points[MAX_NUM_SRC_FIELDS];
109
110 //----------------------------------------------------------------------
111 // reference data
112 //----------------------------------------------------------------------
113 int is_source;
114 int is_target;
115 int num_indices;
116
117 } interp_data[NUM_PROCS];
118 } interp_configs[] =
119
120 // no redistribution
121 // (processes are neither source nor target)
122 {{.interp_data =
123 {{.required_src_points = {{.num_indices = 0},
124 {.num_indices = 0}},
125 .is_source = 0,
126 .is_target = 0},
127 {.required_src_points = {{.num_indices = 0},
128 {.num_indices = 0}},
129 .is_source = 0,
130 .is_target = 0}}},
131 // sending all data of rank 0 to rank 1
132 // (rank 0 is source and rank 1 is target)
133 {.interp_data =
134 {{.required_src_points = {{.num_indices = 0},
135 {.num_indices = 0}},
136 .is_source = 1,
137 .is_target = 0},
138 {.required_src_points = {{.num_indices = 2,
139 .indices = (Xt_int[]){0, 1}},
140 {.num_indices = 2,
141 .indices = (Xt_int[]){0, 1}}},
142 .is_source = 0,
143 .is_target = 1}}},
144 // target data on each rank consists of its local source data
145 // (all processes are both source and target)
146 {.interp_data =
147 {{.required_src_points = {{.num_indices = 2,
148 .indices = (Xt_int[]){0, 1}},
149 {.num_indices = 2,
150 .indices = (Xt_int[]){0, 1}}},
151 .is_source = 1,
152 .is_target = 1},
153 {.required_src_points = {{.num_indices = 2,
154 .indices = (Xt_int[]){2, 3}},
155 {.num_indices = 2,
156 .indices = (Xt_int[]){2, 3}}},
157 .is_source = 1,
158 .is_target = 1}}},
159 // target data on each rank consists of remote and local source data
160 // (all processes are both source and target)
161 {.interp_data =
162 {{.required_src_points = {{.num_indices = 2,
163 .indices = (Xt_int[]){0, 2}},
164 {.num_indices = 2,
165 .indices = (Xt_int[]){1, 3}}},
166 .is_source = 1,
167 .is_target = 1},
168 {.required_src_points = {{.num_indices = 2,
169 .indices = (Xt_int[]){0, 2}},
170 {.num_indices = 2,
171 .indices = (Xt_int[]){1, 3}}},
172 .is_source = 1,
173 .is_target = 1}}}};
174 enum {
175 NUM_INTERP_CONFIGS = sizeof(interp_configs) / sizeof(interp_configs[0])};
176
177 // loop over all interpolation configurations
178 for (size_t interp_config_idx = 0; interp_config_idx < NUM_INTERP_CONFIGS;
179 ++interp_config_idx) {
180
181 // create an array of redistributions for each source field
182 Xt_redist redists[MAX_NUM_SRC_FIELDS];
183 for (size_t f = 0; f < MAX_NUM_SRC_FIELDS; ++f) {
184
185 Xt_idxlist required_source_idxlist =
186 (interp_configs[interp_config_idx].
187 interp_data[comm_rank].required_src_points[f].num_indices > 0)?
188 xt_idxvec_new(
189 interp_configs[interp_config_idx].
190 interp_data[comm_rank].required_src_points[f].indices,
191 interp_configs[interp_config_idx].
192 interp_data[comm_rank].required_src_points[f].num_indices):
193 xt_idxempty_new();
194 Xt_xmap xmap =
195 xt_xmap_all2all_new(
196 src_idxlist, required_source_idxlist, MPI_COMM_WORLD);
197 redists[f] = xt_redist_p2p_new(xmap, MPI_DOUBLE);
198 xt_xmap_delete(xmap);
199 xt_idxlist_delete(required_source_idxlist);
200 }
201
202 struct yac_interp_operator * interp =
204
205 for (int use_copy = 0; use_copy <= 1; ++use_copy) {
206
207 if (use_copy) {
208 struct yac_interp_operator * interp_copy =
211 interp = interp_copy;
212 }
213
214 { // check is_source and is_target
215
216 if (yac_interp_operator_is_source(interp) !=
217 interp_configs[interp_config_idx].
218 interp_data[comm_rank].is_source)
219 PUT_ERR("ERROR in is_source");
220
221 if (yac_interp_operator_is_target(interp) !=
222 interp_configs[interp_config_idx].
223 interp_data[comm_rank].is_target)
224 PUT_ERR("ERROR in is_target");
225 }
226
227 {// test synchronous execute
228
229 // initialise source and target fields
230 double *** src_fields_collection;
231 double *** src_fields_frac_mask_collection;
232 double ** tgt_field_collection;
233 utest_init_data(
234 sel, &src_fields_collection, &src_fields_frac_mask_collection,
235 &tgt_field_collection);
236
238 interp, src_fields_collection,
239 src_fields_frac_mask_collection, tgt_field_collection,
240 YAC_FRAC_MASK_NO_VALUE, 1.0, 0.0);
241
242 // there should be no open put or get operation
245 PUT_ERR("ERROR in execute_put_test");
248 PUT_ERR("ERROR in execute_get_test");
249
250 // check data
251 utest_check_direct_mf(
252 redists, MAX_NUM_SRC_FIELDS, sel,
253 src_fields_collection, tgt_field_collection);
254
255 // free source and target fields
256 utest_free_data(
257 sel, src_fields_collection, src_fields_frac_mask_collection,
258 tgt_field_collection);
259 }
260
261 { // test independent put + get
262
263 // initialise source and target fields
264 double *** src_fields_collection;
265 double *** src_fields_frac_mask_collection;
266 double ** tgt_field_collection;
267 utest_init_data(
268 sel, &src_fields_collection, &src_fields_frac_mask_collection,
269 &tgt_field_collection);
270
272 interp, src_fields_collection,
273 src_fields_frac_mask_collection, 1,
274 YAC_FRAC_MASK_NO_VALUE, 1.0, 0.0);
276 interp, tgt_field_collection,
277 YAC_FRAC_MASK_NO_VALUE, 1.0, 0.0);
278
279 // there should be no open put or get operation
282 PUT_ERR("ERROR in execute_put_test");
285 PUT_ERR("ERROR in execute_get_test");
286
287 // check data
288 utest_check_direct_mf(
289 redists, MAX_NUM_SRC_FIELDS, sel,
290 src_fields_collection, tgt_field_collection);
291
292 // there should be no open put or get operation
295 PUT_ERR("ERROR in execute_put_test");
298 PUT_ERR("ERROR in execute_get_test");
299
300 // free source and target fields
301 utest_free_data(
302 sel, src_fields_collection, src_fields_frac_mask_collection,
303 tgt_field_collection);
304 }
305
306 { // test put + async get + wait
307
308 // initialise source and target fields
309 double *** src_fields_collection;
310 double *** src_fields_frac_mask_collection;
311 double ** tgt_field_collection;
312 utest_init_data(
313 sel, &src_fields_collection, &src_fields_frac_mask_collection,
314 &tgt_field_collection);
315
317 interp, src_fields_collection,
318 src_fields_frac_mask_collection, 1,
319 YAC_FRAC_MASK_NO_VALUE, 1.0, 0.0);
321 interp, tgt_field_collection,
322 YAC_FRAC_MASK_NO_VALUE, 1.0, 0.0);
324
325 // check data
326 utest_check_direct_mf(
327 redists, MAX_NUM_SRC_FIELDS, sel,
328 src_fields_collection, tgt_field_collection);
329
330 // free source and target fields
331 utest_free_data(
332 sel, src_fields_collection, src_fields_frac_mask_collection,
333 tgt_field_collection);
334 }
335
336 { // test put + async get + test_get-loop
337
338 // initialise source and target fields
339 double *** src_fields_collection;
340 double *** src_fields_frac_mask_collection;
341 double ** tgt_field_collection;
342 utest_init_data(
343 sel, &src_fields_collection, &src_fields_frac_mask_collection,
344 &tgt_field_collection);
345
347 interp, src_fields_collection,
348 src_fields_frac_mask_collection, 1,
349 YAC_FRAC_MASK_NO_VALUE, 1.0, 0.0);
351 interp, tgt_field_collection,
352 YAC_FRAC_MASK_NO_VALUE, 1.0, 0.0);
353 while(
356
357 // check data
358 utest_check_direct_mf(
359 redists, MAX_NUM_SRC_FIELDS, sel,
360 src_fields_collection, tgt_field_collection);
361
362 // free source and target fields
363 utest_free_data(
364 sel, src_fields_collection, src_fields_frac_mask_collection,
365 tgt_field_collection);
366 }
367
368 { // test async get + put + wait
369
370 // initialise source and target fields
371 double *** src_fields_collection;
372 double *** src_fields_frac_mask_collection;
373 double ** tgt_field_collection;
374 utest_init_data(
375 sel, &src_fields_collection, &src_fields_frac_mask_collection,
376 &tgt_field_collection);
377
379 interp, tgt_field_collection,
380 YAC_FRAC_MASK_NO_VALUE, 1.0, 0.0);
382 interp, src_fields_collection,
383 src_fields_frac_mask_collection, 1,
384 YAC_FRAC_MASK_NO_VALUE, 1.0, 0.0);
386
387 // check data
388 utest_check_direct_mf(
389 redists, MAX_NUM_SRC_FIELDS, sel,
390 src_fields_collection, tgt_field_collection);
391
392 // free source and target fields
393 utest_free_data(
394 sel, src_fields_collection, src_fields_frac_mask_collection,
395 tgt_field_collection);
396 }
397
398 } // use_copy
399
401
402 for (size_t f = 0; f < MAX_NUM_SRC_FIELDS; ++f)
403 xt_redist_delete(redists[f]);
404
405 } // NUM_INTERP_CONFIGS
406
408 } // NUM_COLL_SEL_CONFIGS
409
410 xt_idxlist_delete(src_idxlist);
411
412 xt_finalize();
413 MPI_Finalize();
414 return TEST_EXIT_CODE;
415}
416
417static void utest_init_data(
418 struct yac_collection_selection * sel, double **** src_fields_collection,
419 double **** src_fields_frac_mask_collection,
420 double *** tgt_field_collection) {
421
423
424 int rank;
425 MPI_Comm_rank(MPI_COMM_WORLD, &rank);
426
427 *src_fields_collection =
428 xmalloc(MAX_COLLECTION_SIZE * sizeof(**src_fields_collection));
429 *src_fields_frac_mask_collection =
430 xmalloc(MAX_COLLECTION_SIZE * sizeof(**src_fields_frac_mask_collection));
431
432 for (size_t c = 0; c < MAX_COLLECTION_SIZE; ++c) {
433
434 (*src_fields_collection)[c] =
435 xmalloc(MAX_NUM_SRC_FIELDS * sizeof(***src_fields_collection));
436 (*src_fields_frac_mask_collection)[c] =
437 xmalloc(MAX_NUM_SRC_FIELDS * sizeof(***src_fields_frac_mask_collection));
438
439 for (size_t f = 0; f < MAX_NUM_SRC_FIELDS; ++f) {
440
441 (*src_fields_collection)[c][f] =
442 xmalloc(NUM_SRC_POINTS * sizeof(***src_fields_collection));
443 (*src_fields_frac_mask_collection)[c][f] =
444 xmalloc(NUM_SRC_POINTS * sizeof(***src_fields_frac_mask_collection));
445
446 for (size_t i = 0; i < NUM_SRC_POINTS; ++i) {
447 (*src_fields_collection)[c][f][i] =
448 (double)(c*1000 + f*100 + rank*10 + i);
449 (*src_fields_frac_mask_collection)[c][f][i] = 1.0;
450 }
451 }
452 }
453
454 *tgt_field_collection =
455 xmalloc(collection_size * sizeof(**tgt_field_collection));
456
457 for (size_t c = 0; c < collection_size; ++c) {
458
459 (*tgt_field_collection)[c] =
460 xmalloc(NUM_TGT_POINTS * sizeof(**tgt_field_collection));
461
462 for (size_t i = 0; i < NUM_TGT_POINTS; ++i) {
463 (*tgt_field_collection)[c][i] = TGT_UNSET_VALUE;
464 }
465 }
466}
467
468static void utest_free_data(
469 struct yac_collection_selection * sel, double *** src_fields_collection,
470 double *** src_fields_frac_mask_collection, double ** tgt_field_collection) {
471
473
474 for (size_t c = 0; c < MAX_COLLECTION_SIZE; ++c) {
475
476 for (size_t f = 0; f < MAX_NUM_SRC_FIELDS; ++f) {
477
478 free(src_fields_collection[c][f]);
479 free(src_fields_frac_mask_collection[c][f]);
480 }
481
482 free(src_fields_collection[c]);
483 free(src_fields_frac_mask_collection[c]);
484 }
485
486 free(src_fields_collection);
487 free(src_fields_frac_mask_collection);
488
489 for (size_t c = 0; c < collection_size; ++c) {
490
491 free(tgt_field_collection[c]);
492 }
493
494 free(tgt_field_collection);
495}
496
497static void utest_check_direct_mf(
498 Xt_redist * redists, size_t num_src_fields,
499 struct yac_collection_selection * sel,
500 double *** src_fields_collection, double ** tgt_field_collection) {
501
503 size_t const * collection_indices = yac_collection_selection_get_indices(sel);
504
505 // initialise reference target field with dummy values
506 // and generate array containg pointers to the field associated to
507 // each collection
508 double ** ref_tgt_field_collection =
509 xmalloc(collection_size * sizeof(*ref_tgt_field_collection));
510 for (size_t c = 0; c < collection_size; ++c) {
511 ref_tgt_field_collection[c] =
512 xmalloc(NUM_TGT_POINTS * sizeof(**ref_tgt_field_collection));
513 for (size_t i = 0; i < NUM_TGT_POINTS; ++i) {
514 ref_tgt_field_collection[c][i] = TGT_UNSET_VALUE;
515 }
516 }
517
518 // for each collection entry
519 for (size_t c = 0; c < collection_size; ++c) {
520
521 // get collection index (if non-contiguous) otherwise use c
522 size_t c_idx = (collection_indices == NULL) ? c : collection_indices[c];
523
524 // for each source field
525 for (size_t f = 0; f < num_src_fields; ++f) {
526
527 // receive source points
528 xt_redist_s_exchange1(
529 redists[f], src_fields_collection[c_idx][f],
530 ref_tgt_field_collection[c]);
531 }
532 }
533
534 for (size_t c = 0; c < collection_size; ++c) {
535 for (size_t i = 0; i < NUM_TGT_POINTS; ++i) {
536 if (tgt_field_collection[c][i] != ref_tgt_field_collection[c][i]) {
537 PUT_ERR("wrong data in direct multi-field interpolation");
538 }
539 }
540 }
541
542 // clean up
543 for (size_t c = 0; c < collection_size; ++c) {
544 free(ref_tgt_field_collection[c]);
545 }
546 free(ref_tgt_field_collection);
547}
size_t yac_collection_selection_get_collection_size(struct yac_collection_selection const *collection_selection)
Get the size of the collection selection.
size_t const * yac_collection_selection_get_indices(struct yac_collection_selection const *collection_selection)
Get explicit selection indices if non-contiguous.
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.
struct yac_interp_operator * yac_interp_operator_direct_mf_new(struct yac_collection_selection const *collection_selection, Xt_redist *redists, size_t num_src_fields)
Create a direct redistribution operator for multiple source fields.
void yac_interp_operator_execute_wait(struct yac_interp_operator *interp)
Wait for all pending put/get operations to finish.
int yac_interp_operator_is_target(struct yac_interp_operator *interp)
Checks if the current process holds target data for the interpolation operator.
struct yac_interp_operator * yac_interp_operator_copy(struct yac_interp_operator *interp)
Create a deep copy of the interpolation operator.
enum YAC_INTERP_TEST_STATUS yac_interp_operator_execute_put_test(struct yac_interp_operator *interp)
Test whether the put phase has completed.
int yac_interp_operator_is_source(struct yac_interp_operator *interp)
Checks if the current process holds source data for the interpolation operator.
enum YAC_INTERP_TEST_STATUS yac_interp_operator_execute_get_test(struct yac_interp_operator *interp)
Test whether the get phase has completed.
void yac_interp_operator_execute_get(struct yac_interp_operator *interp, double **tgt_field, double frac_mask_fallback_value, double scale_factor, double scale_summand)
void yac_interp_operator_execute_put(struct yac_interp_operator *interp, double ***src_fields, double ***src_frac_masks, int is_target, double frac_mask_fallback_value, double scale_factor, double scale_summand)
void yac_interp_operator_execute_get_async(struct yac_interp_operator *interp, double **tgt_field, double frac_mask_fallback_value, double scale_factor, double scale_summand)
void yac_interp_operator_execute(struct yac_interp_operator *interp, double ***src_fields, double ***src_frac_masks, double **tgt_field, double frac_mask_fallback_value, double scale_factor, double scale_summand)
void yac_interp_operator_delete(struct yac_interp_operator *interp)
Delete the interpolation operator and free resources.
@ YAC_INTERP_INCOMPLETE
@ YAC_INTERP_COMPLETE
Multi-field direct redistribution operator in YAC.
double const YAC_FRAC_MASK_NO_VALUE
Public interface for interpolation execution in YAC.
#define xmalloc(size)
Definition ppm_xfuncs.h:66
Abstract interpolation operator type.
int collection_size
#define TGT_UNSET_VALUE
#define N
#define TEST_EXIT_CODE
Definition tests.h:14
#define PUT_ERR(string)
Definition tests.h:10