YAC 3.21.0
Yet Another Coupler
Loading...
Searching...
No Matches
test_interp_method_fixed_parallel.c
Go to the documentation of this file.
1// Copyright (c) 2026 The YAC Authors
2//
3// SPDX-License-Identifier: BSD-3-Clause
4
5#include <stdlib.h>
6#include <math.h>
7#include <string.h>
8
9#include "tests.h"
10#include "test_common.h"
11#include "geometry.h"
15#include "dist_grid_utils.h"
16#include "yac_mpi.h"
17
18#include <mpi.h>
19#include <yaxt.h>
20
29
32size_t num_reorder_types = sizeof(reorder_types) / sizeof(reorder_types[0]);
33static char const * grid_names[2] = {"src_grid", "tgt_grid"};
34
35
63static void utest_fixed_value(double fixed_value)
64{
65 int is_tgt = split_comm_size == 1;
66 double coordinates_x[2][4] = {{0.0,1.0,2.0,3.0}, {0.5,1.5,2.5}};
67 double coordinates_y[2][3] = {{0.0,1.0,2.0}, {0.5,1.5,2.5}};
68 size_t const num_cells[2][2] = {{3,2}, {2,2}};
69 size_t local_start[2][2][2] = {{{0,0},{1,0}}, {{0,0}}};
70 size_t local_count[2][2][2] = {{{2,2},{2,2}}, {{2,2}}};
71 int with_halo = 0;
72 for (size_t i = 0; i <= num_cells[is_tgt][0]; ++i)
73 coordinates_x[is_tgt][i] *= YAC_RAD;
74 for (size_t i = 0; i <= num_cells[is_tgt][1]; ++i)
75 coordinates_y[is_tgt][i] *= YAC_RAD;
76
78 utest_generate_basic_grid_data_reg2d(
79 coordinates_x[is_tgt], coordinates_y[is_tgt], num_cells[is_tgt],
80 local_start[is_tgt][split_comm_rank],
81 local_count[is_tgt][split_comm_rank], with_halo);
82
83 struct yac_basic_grid * grids[2] =
86
87 struct yac_dist_grid_pair * grid_pair =
88 yac_dist_grid_pair_new(grids[0], grids[1], MPI_COMM_WORLD);
89
90 struct yac_interp_field src_fields[] =
92 .coordinates_idx = SIZE_MAX,
93 .masks_idx = SIZE_MAX}};
94 size_t num_src_fields = sizeof(src_fields) / sizeof(src_fields[0]);
96 {.location = YAC_LOC_CORNER,
97 .coordinates_idx = SIZE_MAX,
98 .masks_idx = SIZE_MAX};
99
100 struct yac_interp_grid * interp_grid =
103
104 struct interp_method * method_stack[] =
106
107 struct yac_interp_weights * weights =
108 yac_interp_method_do_search(method_stack, interp_grid);
109
110 for (size_t i = 0; i < num_reorder_types; ++i) {
111
112 struct yac_interpolation * interpolation =
114 weights, reorder_types[i], 1,
115 YAC_FRAC_MASK_NO_VALUE, 1.0, 0.0, NULL, 1, 1);
116
117 {
118 double * src_field = NULL;
119 double ** src_fields_ptr = &src_field;
120 double * tgt_field_buf = NULL;
121
122 if (is_tgt) {
123 tgt_field_buf =
124 xmalloc(grid_data.num_vertices * sizeof(*tgt_field_buf));
125 for (size_t j = 0; j < grid_data.num_vertices; ++j)
126 tgt_field_buf[j] = -42.0;
127 } else {
128 src_field =
129 xmalloc(grid_data.num_vertices * sizeof(*src_field));
130 for (size_t j = 0; j < grid_data.num_vertices; ++j)
131 src_field[j] = -666.0;
132 }
133
134 yac_interpolation_execute(interpolation, &src_fields_ptr, &tgt_field_buf);
135
136 if (is_tgt)
137 for (size_t j = 0; j < grid_data.num_vertices; ++j)
138 if (memcmp(&tgt_field_buf[j], &fixed_value, sizeof(double)) != 0)
139 PUT_ERR_F("wrong fixed interpolation result (expected %g, got %g)",
140 fixed_value, tgt_field_buf[j]);
141
142 free(src_field);
143 free(tgt_field_buf);
144 }
145
146 yac_interpolation_delete(interpolation);
147 }
148
150 yac_interp_method_delete(method_stack);
151 yac_interp_grid_delete(interp_grid);
152 yac_dist_grid_pair_delete(grid_pair);
153 yac_basic_grid_delete(grids[1]);
154 yac_basic_grid_delete(grids[0]);
155}
156
157int main(void) {
158
159 MPI_Init(NULL, NULL);
160
161 xt_initialize(MPI_COMM_WORLD);
162
163 int comm_rank, comm_size;
164 MPI_Comm_rank(MPI_COMM_WORLD, &comm_rank);
165 MPI_Comm_size(MPI_COMM_WORLD, &comm_size);
166 MPI_Barrier(MPI_COMM_WORLD);
167
168 // Guard: this test requires exactly 3 MPI processes (2 src + 1 tgt)
169 if (comm_size != 3) {
170 PUT_ERR("ERROR: wrong number of processes");
171 xt_finalize();
172 MPI_Finalize();
173 return TEST_EXIT_CODE;
174 }
175
176 MPI_Comm split_comm;
177 MPI_Comm_split(
178 MPI_COMM_WORLD, comm_rank < 2, 0, &split_comm);
179
180 MPI_Comm_rank(split_comm, &split_comm_rank);
181 MPI_Comm_size(split_comm, &split_comm_size);
182
183 // Test 1: Basic fixed value = -1.0
184 // fixed-value interpolation with two source processes and one target process
185 // ALL target points must receive exactly -1.0
186 // tests both YAC_MAPPING_ON_SRC and YAC_MAPPING_ON_TGT reorder types
187 utest_fixed_value(-1.0);
188
189 // Test 2: Fixed value = 0.0
190 // Every target point must receive exactly 0.0
191 utest_fixed_value(0.0);
192
193 // Test 3: Fixed value = NaN
194 // Every target point must receive NaN (verified via memcmp on bit pattern)
195 utest_fixed_value(NAN);
196
197 { // Test 4: Fixed as fallback in a method stack (avg first, then fixed)
198 // Source grid has a mask that leaves the top-right corner uncovered.
199 // Covered target points get avg-interpolated values; uncovered ones get -2.0.
200 //
201 // source mask (vertex mask, 4x3 vertices = 12 total):
202 // 1-------1-------1-------1
203 // | | | |
204 // | | | |
205 // | | | |
206 // 1-------1-------1-------1
207 // | | | |
208 // | | | |
209 // | | | |
210 // 1-------1-------1-------0 <- vertex (3,0) masked out
211 //
212 // Source vertex ids: row 0: 0,1,2,3 / row 1: 4,5,6,7 / row 2: 8,9,10,11
213 // Masked vertex: global id 3 (bottom-right corner).
214 // Target corners near masked vertex will fall back to fixed = -2.0.
215
216 int is_tgt = split_comm_size == 1;
217 double coordinates_x[2][4] = {{0.0,1.0,2.0,3.0}, {0.5,1.5,2.5}};
218 double coordinates_y[2][3] = {{0.0,1.0,2.0}, {0.5,1.5,2.5}};
219 size_t const num_cells[2][2] = {{3,2}, {2,2}};
220 size_t local_start[2][2][2] = {{{0,0},{1,0}}, {{0,0}}};
221 size_t local_count[2][2][2] = {{{2,2},{2,2}}, {{2,2}}};
222 // mask: all vertices valid except global id 3 (bottom-right of src grid)
223 int global_src_mask[12] = {1, 1, 1, 0,
224 1, 1, 1, 1,
225 1, 1, 1, 1};
226 int with_halo = 0;
227 for (size_t i = 0; i <= num_cells[is_tgt][0]; ++i)
228 coordinates_x[is_tgt][i] *= YAC_RAD;
229 for (size_t i = 0; i <= num_cells[is_tgt][1]; ++i)
230 coordinates_y[is_tgt][i] *= YAC_RAD;
231
233 utest_generate_basic_grid_data_reg2d(
234 coordinates_x[is_tgt], coordinates_y[is_tgt], num_cells[is_tgt],
235 local_start[is_tgt][split_comm_rank],
236 local_count[is_tgt][split_comm_rank], with_halo);
237
238 struct yac_basic_grid * grids[2] =
241
242 int * src_mask = NULL;
243 if (!is_tgt) {
244 src_mask = xmalloc(grid_data.num_vertices * sizeof(*src_mask));
245 for (size_t i = 0; i < grid_data.num_vertices; ++i)
246 src_mask[i] = global_src_mask[grid_data.vertex_ids[i]];
247 yac_basic_grid_add_mask_nocpy(grids[0], YAC_LOC_CORNER, src_mask, NULL);
248 }
249
250 struct yac_dist_grid_pair * grid_pair =
251 yac_dist_grid_pair_new(grids[0], grids[1], MPI_COMM_WORLD);
252
253 struct yac_interp_field src_fields[] =
254 {{.location = YAC_LOC_CORNER, .coordinates_idx = SIZE_MAX, .masks_idx = 0}};
255 size_t num_src_fields = sizeof(src_fields) / sizeof(src_fields[0]);
257 {.location = YAC_LOC_CORNER, .coordinates_idx = SIZE_MAX, .masks_idx = SIZE_MAX};
258
259 struct yac_interp_grid * interp_grid =
262
263 // avg first (no partial coverage), then fixed = -2.0 as fallback
264 struct interp_method * method_stack[] =
266 yac_interp_method_fixed_new(-2.0), NULL};
267
268 struct yac_interp_weights * weights =
269 yac_interp_method_do_search(method_stack, interp_grid);
270
271 for (size_t i = 0; i < num_reorder_types; ++i) {
272
273 struct yac_interpolation * interpolation =
275 weights, reorder_types[i], 1,
276 YAC_FRAC_MASK_NO_VALUE, 1.0, 0.0, NULL, 1, 1);
277
278 {
279 double * src_field = NULL;
280 double ** src_fields_ptr = &src_field;
281 double * tgt_field_buf = NULL;
282 // Reference target values:
283 // Global target vertex ids 0..8 in a 3x3 arrangement.
284 // src vertex values = their global ids (0..11).
285 // Vertices near the masked src corner (global id 3) cannot be
286 // fully covered by avg => they fall back to -2.0.
287 // Covered tgt vertices get arithmetic avg of surrounding src corners.
288 // ref_global_tgt_field[9] matches the avg test with partial_coverage=0
289 // except where masking forces fallback to -2.0.
290 double ref_global_tgt_field[9] =
291 {2.5, 3.5, -2.0, // <- last tgt vertex is in src cell with masked vertex
292 6.5, 7.5, 8.5,
293 -2.0, -2.0, -2.0}; // <- out of src domain
294
295 if (is_tgt) {
296 tgt_field_buf =
297 xmalloc(grid_data.num_vertices * sizeof(*tgt_field_buf));
298 for(size_t j = 0; j<grid_data.num_vertices; ++j)
299 tgt_field_buf[j] = -42;
300 double * ref_tgt_field =
301 xmalloc(grid_data.num_vertices * sizeof(*ref_tgt_field));
302 for (size_t j = 0; j < grid_data.num_vertices; ++j)
303 ref_tgt_field[j] = ref_global_tgt_field[grid_data.vertex_ids[j]];
304
305 yac_interpolation_execute(interpolation, &src_fields_ptr, &tgt_field_buf);
306
307 for (size_t j = 0; j < grid_data.num_vertices; ++j)
308 if (fabs(ref_tgt_field[j] - tgt_field_buf[j]) > 1e-9)
309 PUT_ERR("Test 4: wrong interpolation result (avg+fixed fallback)");
310
311 free(ref_tgt_field);
312 free(tgt_field_buf);
313 } else {
314 src_field = xmalloc(grid_data.num_vertices * sizeof(*src_field));
315 for (size_t j = 0; j < grid_data.num_vertices; ++j)
316 src_field[j] = (double)(grid_data.vertex_ids[j]);
317
318 yac_interpolation_execute(interpolation, &src_fields_ptr, &tgt_field_buf);
319
320 free(src_field);
321 }
322 }
323
324 yac_interpolation_delete(interpolation);
325 }
326
328 yac_interp_method_delete(method_stack);
329 yac_interp_grid_delete(interp_grid);
330 yac_dist_grid_pair_delete(grid_pair);
331 yac_basic_grid_delete(grids[1]);
332 yac_basic_grid_delete(grids[0]);
333 }
334
335 { // Test 5: collection_size > 1 with fixed value = 42.0
336 // All target points in all 3 collections must receive 42.0
337
338 int is_tgt = split_comm_size == 1;
339 double coordinates_x[2][4] = {{0.0,1.0,2.0,3.0}, {0.5,1.5,2.5}};
340 double coordinates_y[2][3] = {{0.0,1.0,2.0}, {0.5,1.5,2.5}};
341 size_t const num_cells[2][2] = {{3,2}, {2,2}};
342 size_t local_start[2][2][2] = {{{0,0},{1,0}}, {{0,0}}};
343 size_t local_count[2][2][2] = {{{2,2},{2,2}}, {{2,2}}};
344 int with_halo = 0;
345 size_t const collection_size = 3;
346 for (size_t i = 0; i <= num_cells[is_tgt][0]; ++i)
347 coordinates_x[is_tgt][i] *= YAC_RAD;
348 for (size_t i = 0; i <= num_cells[is_tgt][1]; ++i)
349 coordinates_y[is_tgt][i] *= YAC_RAD;
350
352 utest_generate_basic_grid_data_reg2d(
353 coordinates_x[is_tgt], coordinates_y[is_tgt], num_cells[is_tgt],
354 local_start[is_tgt][split_comm_rank],
355 local_count[is_tgt][split_comm_rank], with_halo);
356
357 struct yac_basic_grid * grids[2] =
360
361 struct yac_dist_grid_pair * grid_pair =
362 yac_dist_grid_pair_new(grids[0], grids[1], MPI_COMM_WORLD);
363
364 struct yac_interp_field src_fields[] =
365 {{.location = YAC_LOC_CORNER, .coordinates_idx = SIZE_MAX, .masks_idx = SIZE_MAX}};
366 size_t num_src_fields = sizeof(src_fields) / sizeof(src_fields[0]);
368 {.location = YAC_LOC_CORNER, .coordinates_idx = SIZE_MAX, .masks_idx = SIZE_MAX};
369
370 struct yac_interp_grid * interp_grid =
373
374 struct interp_method * method_stack[] =
375 {yac_interp_method_fixed_new(42.0), NULL};
376
377 struct yac_interp_weights * weights =
378 yac_interp_method_do_search(method_stack, interp_grid);
379
380 for (size_t i = 0; i < num_reorder_types; ++i) {
381
382 struct yac_interpolation * interpolation =
384 weights, reorder_types[i], collection_size,
385 YAC_FRAC_MASK_NO_VALUE, 1.0, 0.0, NULL,
386 1, 1);
387
388 {
389 // src_data layout: [collection_idx][field_idx][local_idx]
390 double *** src_data =
391 xmalloc(collection_size * sizeof(*src_data));
392 // tgt_data layout: [collection_idx][local_idx]
393 double ** tgt_data =
394 xmalloc(collection_size * sizeof(*tgt_data));
395
396 for (size_t c = 0; c < collection_size; ++c) {
397 // one src field per collection
398 src_data[c] = xmalloc(1 * sizeof(**src_data));
399 src_data[c][0] = NULL;
400 tgt_data[c] = NULL;
401 }
402
403 if (is_tgt)
404 for (size_t c = 0; c < collection_size; ++c){
405 tgt_data[c] =
406 xmalloc(grid_data.num_vertices * sizeof(*tgt_data[c]));
407 for(size_t j = 0; j<grid_data.num_vertices; ++j)
408 tgt_data[c][j] = -42;
409 }
410 else
411 for (size_t c = 0; c < collection_size; ++c){
412 src_data[c][0] =
413 xmalloc(grid_data.num_vertices * sizeof(*src_data[c][0]));
414 for(size_t j = 0; j<grid_data.num_vertices; ++j)
415 src_data[c][0][j] = -666;
416 }
417
418 yac_interpolation_execute(interpolation, src_data, tgt_data);
419
420 if (is_tgt)
421 for (size_t c = 0; c < collection_size; ++c)
422 for (size_t j = 0; j < grid_data.num_vertices; ++j)
423 if (tgt_data[c][j] != 42.0)
424 PUT_ERR("Test 5: wrong fixed interpolation result "
425 "(expected 42.0 in all collections)");
426
427 for (size_t c = 0; c < collection_size; ++c) {
428 free(src_data[c][0]);
429 free(src_data[c]);
430 free(tgt_data[c]);
431 }
432 free(src_data);
433 free(tgt_data);
434 }
435
436 yac_interpolation_delete(interpolation);
437 }
438
440 yac_interp_method_delete(method_stack);
441 yac_interp_grid_delete(interp_grid);
442 yac_dist_grid_pair_delete(grid_pair);
443 yac_basic_grid_delete(grids[1]);
444 yac_basic_grid_delete(grids[0]);
445 }
446
447 MPI_Comm_free(&split_comm);
448
449 xt_finalize();
450 MPI_Finalize();
451
452 return TEST_EXIT_CODE;
453}
struct yac_basic_grid * yac_basic_grid_new(char const *name, struct yac_basic_grid_data grid_data)
Definition basic_grid.c:57
struct yac_basic_grid * yac_basic_grid_empty_new(char const *name)
Definition basic_grid.c:70
void yac_basic_grid_delete(struct yac_basic_grid *grid)
Definition basic_grid.c:77
size_t yac_basic_grid_add_mask_nocpy(struct yac_basic_grid *grid, enum yac_location location, int const *mask, char const *mask_name)
Definition basic_grid.c:244
void yac_dist_grid_pair_delete(struct yac_dist_grid_pair *grid_pair)
Definition dist_grid.c:2377
struct yac_dist_grid_pair * yac_dist_grid_pair_new(struct yac_basic_grid *grid_a, struct yac_basic_grid *grid_b, MPI_Comm comm)
Definition dist_grid.c:2089
#define YAC_RAD
void yac_interp_grid_delete(struct yac_interp_grid *interp_grid)
struct yac_interp_grid * yac_interp_grid_new(struct yac_dist_grid_pair *grid_pair, char const *src_grid_name, char const *tgt_grid_name, size_t num_src_fields, struct yac_interp_field const *src_fields, struct yac_interp_field const tgt_field)
Definition interp_grid.c:31
void yac_interp_method_delete(struct interp_method **method)
Delete an interpolation stack and free its resources (but not the pointer array).
struct yac_interp_weights * yac_interp_method_do_search(struct interp_method **method, struct yac_interp_grid *interp_grid)
Perform weight computation using given interpolation stack and grid.
Defines the interface of the interpolation method "base class" in YAC.
struct interp_method * yac_interp_method_avg_new(enum yac_interp_avg_weight_type weight_type, int partial_coverage)
@ YAC_INTERP_AVG_ARITHMETIC
struct interp_method * yac_interp_method_fixed_new(double value)
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)
void yac_interp_weights_delete(struct yac_interp_weights *weights)
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
void yac_interpolation_execute(struct yac_interpolation *interp, double ***src_fields, double **tgt_field)
Execute interpolation synchronously and write results to the target field.
void yac_interpolation_delete(struct yac_interpolation *interp)
Free an interpolation object and release all resources.
double const YAC_FRAC_MASK_NO_VALUE
@ YAC_LOC_CORNER
Definition location.h:15
#define xmalloc(size)
Definition ppm_xfuncs.h:66
enum yac_location location
Definition basic_grid.h:16
struct yac_interp_field tgt_field
Definition interp_grid.c:26
size_t num_src_fields
Definition interp_grid.c:27
struct yac_dist_grid_pair * grid_pair
Definition interp_grid.c:25
struct yac_interp_field src_fields[]
Definition interp_grid.c:28
int collection_size
static double const fixed_value
static MPI_Comm split_comm
static char const * grid_names[2]
enum yac_interp_weights_reorder_type reorder_types[]
double coordinates_x[]
size_t num_cells[2]
double coordinates_y[]
#define PUT_ERR_F(fmt,...)
Definition tests.h:11
#define TEST_EXIT_CODE
Definition tests.h:15
#define PUT_ERR(string)
Definition tests.h:10