YAC 3.13.0
Yet Another Coupler
Loading...
Searching...
No Matches
test_interp_operator_direct.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
24static void utest_init_data(
25 struct yac_collection_selection * sel, double **** src_fields_collection,
26 double **** src_fields_frac_mask_collection, double *** tgt_field_collection);
27static void utest_free_data(
28 struct yac_collection_selection * sel, double *** src_fields_collection,
29 double *** src_fields_frac_mask_collection, double ** tgt_field_collection);
30static void utest_check_direct(
31 Xt_redist redist, struct yac_collection_selection * sel,
32 double *** src_fields_collection, double ** tgt_field_collection);
33
34enum {
40};
41#define TGT_UNSET_VALUE (-1.0)
42
43int main(void) {
44
45 MPI_Init(NULL, NULL);
46 xt_initialize(MPI_COMM_WORLD);
47
48 int comm_rank, comm_size;
49 MPI_Comm_rank(MPI_COMM_WORLD, &comm_rank);
50 MPI_Comm_size(MPI_COMM_WORLD, &comm_size);
51
52 if (comm_size != 2) {
53 PUT_ERR("ERROR: test requires 2 processes");
54 xt_finalize();
55 MPI_Finalize();
56 return TEST_EXIT_CODE;
57 }
58
59 // generate yaxt index list containing global ids of all locally available
60 // source points (each source field contains the same global ids)
61 // each process holds the following global ids:
62 // i + comm_rank * NUM_SRC_POINTS
63 // with i in [0..NUM_SRC_POINTS]
64 Xt_int src_global_ids[NUM_SRC_POINTS];
65 for (size_t src_idx = 0; src_idx < NUM_SRC_POINTS; ++src_idx)
66 src_global_ids[src_idx] =
67 (Xt_int)(src_idx + comm_rank * NUM_SRC_POINTS);
68 Xt_idxlist src_idxlist =
69 xt_idxvec_new(src_global_ids, NUM_SRC_POINTS);
70
71 // collection selection configurations
72 struct {
73 size_t N;
74 size_t * indices;
75 } collection_selection_configs[] =
76 {{.N = 3, .indices = (size_t[]){0, 2, 3}},
77 {.N = 4, .indices = (size_t[]){0, 1, 2, 3}},
78 {.N = 2, .indices = NULL}};
79 enum {
80 NUM_COLL_SEL_CONFIGS =
81 sizeof(collection_selection_configs)/
82 sizeof(collection_selection_configs[0]) };
83
84 // loop over collection selections
85 for (size_t sel_idx = 0; sel_idx < NUM_COLL_SEL_CONFIGS; ++sel_idx) {
86
87 struct yac_collection_selection * sel =
89 collection_selection_configs[sel_idx].N,
90 collection_selection_configs[sel_idx].indices);
91
92 // interpolation configurations
93 // We assume that the global ids of the source source points of each field
94 // are:
95 // * for rank 0: [0, 1]
96 // * for rank 1: [2, 3]
97 struct {
98 struct {
99
100 //----------------------------------------------------------------------
101 // required source points
102 //----------------------------------------------------------------------
103 struct {
104 int num_indices; // number of source points to be received
105 Xt_int * indices; // global ids of required source points
106 } required_src_points;
107
108 //----------------------------------------------------------------------
109 // reference data
110 //----------------------------------------------------------------------
111 int is_source;
112 int is_target;
113
114 } interp_data[NUM_PROCS];
115 } interp_configs[] =
116 // no redistribution
117 // (processes are neither source nor target)
118 {{.interp_data =
119 {{.required_src_points = {.num_indices = 0, .indices = NULL},
120 .is_source = 0,
121 .is_target = 0},
122 {.required_src_points = {.num_indices = 0, .indices = NULL},
123 .is_source = 0,
124 .is_target = 0}}},
125 // rank 0 sends all its data to rank 1
126 // (rank 0 is source and rank 1 is target)
127 {.interp_data =
128 {{.required_src_points = {.num_indices = 0, .indices = NULL},
129 .is_source = 1,
130 .is_target = 0},
131 {.required_src_points = {.num_indices = 2,
132 .indices = (Xt_int[]){0, 1}},
133 .is_source = 0,
134 .is_target = 1}}},
135 // target data on each rank consists of its local source data
136 // (all processes are both source and target)
137 {.interp_data =
138 {{.required_src_points = {.num_indices = 2,
139 .indices = (Xt_int[]){0, 1}},
140 .is_source = 1,
141 .is_target = 1},
142 {.required_src_points = {.num_indices = 2,
143 .indices = (Xt_int[]){2, 3}},
144 .is_source = 1,
145 .is_target = 1}}},
146 // target data on each rank consists of remote and local source data
147 // (all processes are both source and target)
148 {.interp_data =
149 {{.required_src_points = {.num_indices = 2,
150 .indices = (Xt_int[]){0, 2}},
151 .is_source = 1,
152 .is_target = 1},
153 {.required_src_points = {.num_indices = 2,
154 .indices = (Xt_int[]){1, 3}},
155 .is_source = 1,
156 .is_target = 1}}}};
157 enum {
158 NUM_INTERP_CONFIGS = sizeof(interp_configs) / sizeof(interp_configs[0])};
159
160 // loop over all interpolation configurations
161 for (size_t interp_config_idx = 0; interp_config_idx < NUM_INTERP_CONFIGS;
162 ++interp_config_idx) {
163
164 Xt_idxlist required_source_idxlist =
165 (interp_configs[interp_config_idx].
166 interp_data[comm_rank].required_src_points.num_indices > 0)?
167 xt_idxvec_new(
168 interp_configs[interp_config_idx].
169 interp_data[comm_rank].required_src_points.indices,
170 interp_configs[interp_config_idx].
171 interp_data[comm_rank].required_src_points.num_indices):
172 xt_idxempty_new();
173
174 Xt_xmap xmap =
175 xt_xmap_all2all_new(
176 src_idxlist, required_source_idxlist, MPI_COMM_WORLD);
177 Xt_redist redist = xt_redist_p2p_new(xmap, MPI_DOUBLE);
178
179 xt_xmap_delete(xmap);
180 xt_idxlist_delete(required_source_idxlist);
181
182 // create direct interpolation operator
183 struct yac_interp_operator * interp =
185
186 for (int use_copy = 0; use_copy <= 1; ++use_copy) {
187
188 if (use_copy) {
189 struct yac_interp_operator * interp_copy =
192 interp = interp_copy;
193 }
194
195 for (int with_frac_mask = 0; with_frac_mask <= 1; ++with_frac_mask) {
196
197 // if without fractional masking, set fallback value to
198 // YAC_FRAC_MASK_NO_VALUE, which deacitavtes it
199 double frac_mask_fallback_value =
200 with_frac_mask?-10.0:YAC_FRAC_MASK_NO_VALUE;
201
202 { // check is_source and is_target
203
204 if (yac_interp_operator_is_source(interp) !=
205 interp_configs[interp_config_idx].
206 interp_data[comm_rank].is_source)
207 PUT_ERR("ERROR in is_source");
208
209 if (yac_interp_operator_is_target(interp) !=
210 interp_configs[interp_config_idx].
211 interp_data[comm_rank].is_target)
212 PUT_ERR("ERROR in is_target");
213 }
214
215 { // synchronous execute
216
217 // initialise source and target fields
218 double *** src_fields_collection;
219 double *** src_fields_frac_mask_collection;
220 double ** tgt_field_collection;
221 utest_init_data(
222 sel, &src_fields_collection, &src_fields_frac_mask_collection,
223 &tgt_field_collection);
224
226 interp, src_fields_collection, src_fields_frac_mask_collection,
227 tgt_field_collection, frac_mask_fallback_value, 1.0, 0.0);
228
229 // there should be no open put or get operation
232 PUT_ERR("ERROR in execute_put_test");
235 PUT_ERR("ERROR in execute_get_test");
236
237 // check results
238 utest_check_direct(
239 redist, sel, src_fields_collection, tgt_field_collection);
240
241 // free source and target fields
242 utest_free_data(
243 sel, src_fields_collection, src_fields_frac_mask_collection,
244 tgt_field_collection);
245 }
246
247 { // independent put + get
248
249 // initialise source and target fields
250 double *** src_fields_collection;
251 double *** src_fields_frac_mask_collection;
252 double ** tgt_field_collection;
253
254 utest_init_data(
255 sel, &src_fields_collection, &src_fields_frac_mask_collection,
256 &tgt_field_collection);
258 interp, src_fields_collection, src_fields_frac_mask_collection,
259 1, frac_mask_fallback_value, 1.0, 0.0);
261 interp, tgt_field_collection,
262 frac_mask_fallback_value, 1.0, 0.0);
263
264 // there should be no open put or get operation
267 PUT_ERR("ERROR in execute_put_test");
270 PUT_ERR("ERROR in execute_get_test");
271
272 // check data
273 utest_check_direct(
274 redist, sel, src_fields_collection, tgt_field_collection);
275
276 // free source and target fields
277 utest_free_data(
278 sel, src_fields_collection, src_fields_frac_mask_collection,
279 tgt_field_collection);
280 }
281
282 { // independent put + async get + wait
283
284 // initialise source and target fields
285 double *** src_fields_collection;
286 double *** src_fields_frac_mask_collection;
287 double ** tgt_field_collection;
288
289 utest_init_data(
290 sel, &src_fields_collection, &src_fields_frac_mask_collection,
291 &tgt_field_collection);
292
294 interp, src_fields_collection, src_fields_frac_mask_collection,
295 1, frac_mask_fallback_value, 1.0, 0.0);
297 interp, tgt_field_collection,
298 frac_mask_fallback_value, 1.0, 0.0);
300
301 // there should be no open put or get operation
304 PUT_ERR("ERROR in execute_put_test");
307 PUT_ERR("ERROR in execute_get_test");
308
309 // check data
310 utest_check_direct(
311 redist, sel, src_fields_collection, tgt_field_collection);
312
313 // free source and target fields
314 utest_free_data(
315 sel, src_fields_collection, src_fields_frac_mask_collection,
316 tgt_field_collection);
317 }
318
319 { // independent put + async get + test_get-loop
320
321 // initialise source and target fields
322 double *** src_fields_collection;
323 double *** src_fields_frac_mask_collection;
324 double ** tgt_field_collection;
325 utest_init_data(
326 sel, &src_fields_collection, &src_fields_frac_mask_collection,
327 &tgt_field_collection);
328
330 interp, src_fields_collection,
331 src_fields_frac_mask_collection,
332 1, frac_mask_fallback_value, 1.0, 0.0);
334 interp, tgt_field_collection,
335 frac_mask_fallback_value, 1.0, 0.0);
336 while(
339
340 // there should be no open put or get operation
343 PUT_ERR("ERROR in execute_put_test");
346 PUT_ERR("ERROR in execute_get_test");
347
348 // check data
349 utest_check_direct(
350 redist, sel, src_fields_collection, tgt_field_collection);
351
352 // free source and target fields
353 utest_free_data(
354 sel, src_fields_collection, src_fields_frac_mask_collection,
355 tgt_field_collection);
356 }
357
358 { // independent async get + put + wait
359
360 // initialise source and target fields
361 double *** src_fields_collection;
362 double *** src_fields_frac_mask_collection;
363 double ** tgt_field_collection;
364 utest_init_data(
365 sel, &src_fields_collection, &src_fields_frac_mask_collection,
366 &tgt_field_collection);
367
369 interp, tgt_field_collection,
370 frac_mask_fallback_value, 1.0, 0.0);
372 interp, src_fields_collection, src_fields_frac_mask_collection,
373 1, frac_mask_fallback_value, 1.0, 0.0);
375
376 // there should be no open put or get operation
379 PUT_ERR("ERROR in execute_put_test");
382 PUT_ERR("ERROR in execute_get_test");
383
384 // check data
385 utest_check_direct(
386 redist, sel, src_fields_collection, tgt_field_collection);
387
388 // free source and target fields
389 utest_free_data(
390 sel, src_fields_collection, src_fields_frac_mask_collection,
391 tgt_field_collection);
392 }
393
394 } // with_frac_mask
395
396 } // use_copy
397
399 xt_redist_delete(redist);
400
401 } // redist configs
402
404
405 } // collection selection configs
406
407 xt_idxlist_delete(src_idxlist);
408
409 xt_finalize();
410 MPI_Finalize();
411
412 return TEST_EXIT_CODE;
413}
414
415static void utest_init_data(
416 struct yac_collection_selection * sel, double **** src_fields_collection,
417 double **** src_fields_frac_mask_collection,
418 double *** tgt_field_collection) {
419
421
422 int rank;
423 MPI_Comm_rank(MPI_COMM_WORLD, &rank);
424
425 *src_fields_collection =
426 xmalloc(MAX_COLLECTION_SIZE * sizeof(**src_fields_collection));
427 *src_fields_frac_mask_collection =
428 xmalloc(MAX_COLLECTION_SIZE * sizeof(**src_fields_frac_mask_collection));
429
430 for (size_t c = 0; c < MAX_COLLECTION_SIZE; ++c) {
431
432 (*src_fields_collection)[c] =
433 xmalloc(MAX_NUM_SRC_FIELDS * sizeof(***src_fields_collection));
434 (*src_fields_frac_mask_collection)[c] =
435 xmalloc(MAX_NUM_SRC_FIELDS * sizeof(***src_fields_frac_mask_collection));
436
437 for (size_t f = 0; f < MAX_NUM_SRC_FIELDS; ++f) {
438
439 (*src_fields_collection)[c][f] =
440 xmalloc(NUM_SRC_POINTS * sizeof(***src_fields_collection));
441 (*src_fields_frac_mask_collection)[c][f] =
442 xmalloc(NUM_SRC_POINTS * sizeof(***src_fields_frac_mask_collection));
443
444 for (size_t i = 0; i < NUM_SRC_POINTS; ++i) {
445 (*src_fields_collection)[c][f][i] =
446 (double)(c*1000 + f*100 + rank*10 + i);
447 (*src_fields_frac_mask_collection)[c][f][i] = 1.0;
448 }
449 }
450 }
451
452 *tgt_field_collection =
453 xmalloc(collection_size * sizeof(**tgt_field_collection));
454
455 for (size_t c = 0; c < collection_size; ++c) {
456
457 (*tgt_field_collection)[c] =
458 xmalloc(NUM_TGT_POINTS * sizeof(**tgt_field_collection));
459
460 for (size_t i = 0; i < NUM_TGT_POINTS; ++i) {
461 (*tgt_field_collection)[c][i] = TGT_UNSET_VALUE;
462 }
463 }
464}
465
466static void utest_free_data(
467 struct yac_collection_selection * sel, double *** src_fields_collection,
468 double *** src_fields_frac_mask_collection, double ** tgt_field_collection) {
469
471
472 for (size_t c = 0; c < MAX_COLLECTION_SIZE; ++c) {
473
474 for (size_t f = 0; f < MAX_NUM_SRC_FIELDS; ++f) {
475
476 free(src_fields_collection[c][f]);
477 free(src_fields_frac_mask_collection[c][f]);
478 }
479
480 free(src_fields_collection[c]);
481 free(src_fields_frac_mask_collection[c]);
482 }
483
484 free(src_fields_collection);
485 free(src_fields_frac_mask_collection);
486
487 for (size_t c = 0; c < collection_size; ++c) {
488
489 free(tgt_field_collection[c]);
490 }
491
492 free(tgt_field_collection);
493}
494
495static void utest_check_direct(
496 Xt_redist redist, struct yac_collection_selection * sel,
497 double *** src_fields_collection, double ** tgt_field_collection) {
498
499 size_t collection_size =
501 size_t const * collection_indices =
503
504 // initialise reference target field with dummy values
505 // and generate array containg pointers to the field associated to
506 // each collection
507 double ** ref_tgt_field_collection =
508 xmalloc(collection_size * sizeof(*ref_tgt_field_collection));
509 for (size_t c = 0; c < collection_size; ++c) {
510 ref_tgt_field_collection[c] =
511 xmalloc(NUM_TGT_POINTS * sizeof(**ref_tgt_field_collection));
512 for (size_t i = 0; i < NUM_TGT_POINTS; ++i) {
513 ref_tgt_field_collection[c][i] = TGT_UNSET_VALUE;
514 }
515 }
516
517 // for each collection entry
518 for (size_t c = 0; c < collection_size; ++c) {
519
520 // get collection index (if non-contiguous) otherwise use c
521 size_t c_idx = (collection_indices == NULL)?c:collection_indices[c];
522
523 // receive source points
524 xt_redist_s_exchange1(
525 redist, src_fields_collection[c_idx][0], ref_tgt_field_collection[c]);
526 }
527
528 for (size_t c = 0; c < collection_size; ++c) {
529 for (size_t i = 0; i < NUM_TGT_POINTS; ++i) {
530 if (tgt_field_collection[c][i] != ref_tgt_field_collection[c][i])
531 PUT_ERR("wrong data in direct interpolation");
532 }
533 }
534
535 for (size_t c = 0; c < collection_size; ++c) {
536 free(ref_tgt_field_collection[c]);
537 }
538 free(ref_tgt_field_collection);
539}
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_new(struct yac_collection_selection const *collection_selection, Xt_redist redist_)
Create a direct redistribution interpolation operator.
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
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