YAC 3.12.0
Yet Another Coupler
Loading...
Searching...
No Matches
test_instance_parallel2.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#include <stdlib.h>
6#include <stdio.h>
7#include <unistd.h>
8#include <string.h>
9
10#include <mpi.h>
11
12#include "tests.h"
13#include "test_common.h"
14#include "instance.h"
16#include "yac.h"
17#include "yac_mpi.h"
18#include "event.h"
19
26static void check_constructor(void * user_data);
27
28static void check_do_search(
29 yac_int const * global_ids, double const (*coordinates_xyz)[3],
30 size_t count, void * user_data);
31
32struct field_config {
33 size_t grid_idx;
34 size_t point_idx;
35};
36
40
41static int utest_get_num_unique_configurations(
42 struct field_config field_config_a[4],
43 struct field_config field_config_b[4]);
44
46 IN = 0,
47 OUT = 1,
48};
49
50static void run_test_configuration(struct field_config test_config[2][3][4]);
51
52int main (void) {
53
54 // This test checks whether weights are reused for different fields
55 // if grid and field data is identical. In case any of these two differs
56 // weights cannot be reused.
57
59 yac_yaxt_init(MPI_COMM_WORLD);
60 int rank, size;
61 MPI_Comm_rank(MPI_COMM_WORLD, &rank);
62 MPI_Comm_size(MPI_COMM_WORLD, &size);
63
65
66 if (size != 9) {
67
68 PUT_ERR("ERROR: wrong number of processes\n");
69 return TEST_EXIT_CODE;
70 }
71
72 int local_comp_idx = rank % 3;
73
74 // dimensions: [test_idx][field_idx]
75 struct field_config test_cases[][4] =
76 {{{.grid_idx = 0, .point_idx = 0},
77 {.grid_idx = 1, .point_idx = 1},
78 {.grid_idx = 2, .point_idx = 2},
79 {.grid_idx = 3, .point_idx = 3}},
80 {{.grid_idx = 1, .point_idx = 1},
81 {.grid_idx = 1, .point_idx = 2},
82 {.grid_idx = 1, .point_idx = 2},
83 {.grid_idx = 3, .point_idx = 2}},
84 {{.grid_idx = 3, .point_idx = 2},
85 {.grid_idx = 3, .point_idx = 2},
86 {.grid_idx = 3, .point_idx = 2},
87 {.grid_idx = 3, .point_idx = 2}},
88 {{.grid_idx = 0, .point_idx = 0},
89 {.grid_idx = 0, .point_idx = 1},
90 {.grid_idx = 0, .point_idx = 2},
91 {.grid_idx = 0, .point_idx = 3}},
92 {{.grid_idx = 0, .point_idx = 0},
93 {.grid_idx = 1, .point_idx = 0},
94 {.grid_idx = 2, .point_idx = 0},
95 {.grid_idx = 3, .point_idx = 0}},
96 {{.grid_idx = 0, .point_idx = 2},
97 {.grid_idx = 1, .point_idx = 3},
98 {.grid_idx = 0, .point_idx = 2},
99 {.grid_idx = 1, .point_idx = 3}}};
100 enum {
101 NUM_TEST_CASES = sizeof(test_cases) / sizeof(test_cases[0]),
102 };
103
104 //[direction][other_comp]
105 int check_constructor_call_count[2][3];
106 int check_do_search_call_count[2][3];
107
108 for (int comp_offset = -1; comp_offset <= 1; comp_offset += 2) {
109 int other_comp_idx = (local_comp_idx + comp_offset + 3)%3;
110 for (int direction = 0; direction < 2; ++direction) {
111
112 char check_constructor_key[256];
113 sprintf(check_constructor_key, "check_constructor_%u_to_%u",
114 (direction == IN)?(other_comp_idx + 1):(local_comp_idx + 1),
115 (direction == IN)?(local_comp_idx + 1):(other_comp_idx + 1));
118 &(check_constructor_call_count[direction][other_comp_idx]),
119 check_constructor_key);
120
121 char check_do_search_key[256];
122 sprintf(check_do_search_key, "check_do_search_%u_to_%u",
123 (direction == IN)?(other_comp_idx + 1):(local_comp_idx + 1),
124 (direction == IN)?(local_comp_idx + 1):(other_comp_idx + 1));
127 &(check_do_search_call_count[direction][other_comp_idx]),
128 check_do_search_key);
129 }
130 }
131
132 struct field_config test_config[2][3][4];
133
134 // [direction][comp_idx]
135 int test_idx[2][3];
136
137 // for all in field configurations
138 for (int test_idx_in = 0; test_idx_in < NUM_TEST_CASES; ++test_idx_in) {
139
140 for (int comp_idx = 0; comp_idx < 3; ++comp_idx)
141 test_idx[IN][comp_idx] = test_idx_in;
142
143 // check all out configurations agains the current in config
144 for (int test_idx_out = 0, test_run_out = 0;
145 test_run_out < (NUM_TEST_CASES + 2) / 3; ++test_run_out) {
146
147 for (int comp_idx = 0; comp_idx < 3; ++comp_idx,
148 test_idx_out = (test_idx_out + 1)%NUM_TEST_CASES)
149 test_idx[OUT][comp_idx] = test_idx_out;
150
151 for (int direction = 0; direction < 2; ++direction)
152 for (int comp_idx = 0; comp_idx < 3; ++comp_idx)
153 for (int field_idx = 0; field_idx < 4; ++field_idx)
154 test_config[direction][comp_idx][field_idx] =
155 test_cases[test_idx[direction][comp_idx]][field_idx];
156
157 memset(check_constructor_call_count, 0,
158 sizeof(check_constructor_call_count));
159 memset(check_do_search_call_count, 0,
160 sizeof(check_do_search_call_count));
161
162 // run the current test configuration
163 run_test_configuration(test_config);
164
165 // check results
166 for (int comp_offset = -1; comp_offset <= 1; comp_offset += 2) {
167 int other_comp_idx = (local_comp_idx + comp_offset + 3)%3;
168 for (int direction = 0; direction < 2; ++direction)
169 if ((check_constructor_call_count[direction][other_comp_idx] !=
170 check_do_search_call_count[direction][other_comp_idx]) ||
171 (check_constructor_call_count[direction][other_comp_idx] !=
172 utest_get_num_unique_configurations(
173 test_config[direction][local_comp_idx ],
174 test_config[direction^1][other_comp_idx])))
175 PUT_ERR("invalid call count");
176 }
177 }
178 }
179
180 // cleanup
183
184 return TEST_EXIT_CODE;
185}
186
187static void check_constructor(void * user_data) {
188
189 ++*(int*)user_data;
190
191 return;
192}
193
194static void check_do_search(
195 yac_int const * global_ids, double const (*coordinates_xyz)[3],
196 size_t num_points, void * user_data) {
197
198 UNUSED(global_ids);
199 UNUSED(coordinates_xyz);
201
202 ++*(int*)user_data;
203
204 return;
205}
206
207static int compare_size_t(const void * a, const void * b) {
208
209 return (*((const size_t*)a) > *((const size_t*)b)) -
210 (*((const size_t*)a) < *((const size_t*)b));
211}
212
213static int compare_field_config(const void * a, const void * b) {
214
215 int ret = compare_size_t(&(((const struct field_config*)a)->grid_idx),
216 &(((const struct field_config*)b)->grid_idx));
217 if (ret) return ret;
218 else return compare_size_t(&(((const struct field_config*)a)->point_idx),
219 &(((const struct field_config*)b)->point_idx));
220}
221
222static int compare_field_config_src_tgt(const void * a, const void * b) {
223
224 int ret =
225 compare_field_config(&(((const struct field_config_src_tgt*)a)->src),
226 &(((const struct field_config_src_tgt*)b)->src));
227 if (ret) return ret;
228 else
229 return compare_field_config(&(((const struct field_config_src_tgt*)a)->tgt),
230 &(((const struct field_config_src_tgt*)b)->tgt));
231}
232
233static int utest_get_num_unique_configurations(
234 struct field_config field_config_a[4],
235 struct field_config field_config_b[4]) {
236
237 struct field_config_src_tgt field_configs[4];
238
239 for (int i = 0; i < 4; ++i) {
240 field_configs[i].src = field_config_a[i];
241 field_configs[i].tgt = field_config_b[i];
242 }
243
244 qsort(
245 field_configs, 4, sizeof(field_configs[0]), compare_field_config_src_tgt);
246
247 int num_unique_config = 1;
248 for (int i = 1; i < 4; ++i)
249 if (compare_field_config_src_tgt(&field_configs[i-1], &field_configs[i]))
250 ++num_unique_config;
251
252 return num_unique_config;
253}
254
255static void run_test_configuration(struct field_config test_config[2][3][4]) {
256
257 int rank;
258 MPI_Comm_rank(MPI_COMM_WORLD, &rank);
259
260 int comp_idx = rank % 3;
261
262 struct yac_instance * instance =
263 yac_instance_new(MPI_COMM_WORLD);
264
265 // define couples
267 instance, "2008-03-09T16:05:07", "2008-03-10T16:05:07");
268 char * coupling_period =
269 strdup(yac_time_to_ISO("60", C_SECOND));
270 for (size_t src_comp_idx = 0; src_comp_idx < 3; ++src_comp_idx) {
271 char src_comp_id = '1' + (char)src_comp_idx;
272 for (size_t tgt_comp_idx = 0; tgt_comp_idx < 3; ++tgt_comp_idx) {
273 char tgt_comp_id = '1' + (char)tgt_comp_idx;
274 if (src_comp_id == tgt_comp_id) continue;
275 char src_comp_name[32], tgt_comp_name[32];
276 sprintf(src_comp_name, "comp_%c", src_comp_id);
277 sprintf(tgt_comp_name, "comp_%c", tgt_comp_id);
278 char constructor_key[32], do_search_key[32];
279 sprintf(constructor_key, "check_constructor_%c_to_%c",
280 src_comp_id, tgt_comp_id);
281 sprintf(do_search_key, "check_do_search_%c_to_%c",
282 src_comp_id, tgt_comp_id);
283 struct yac_interp_stack_config * interp_stack =
286 interp_stack, constructor_key, do_search_key);
287 yac_interp_stack_config_add_fixed(interp_stack, -1.0);
288 for (size_t field_idx = 0; field_idx < 4; ++field_idx) {
289 char field_id = '1' + (char)field_idx;
290 char src_grid_name[32], tgt_grid_name[32];
291 sprintf(src_grid_name, "grid_%c_%zu_out",
292 src_comp_id, test_config[OUT][src_comp_idx][field_idx].grid_idx+1);
293 sprintf(tgt_grid_name, "grid_%c_%zu_in",
294 tgt_comp_id, test_config[IN][tgt_comp_idx][field_idx].grid_idx+1);
295 char field_name[32];
296 sprintf(field_name, "field_from_%c_to_%c_%c",
297 src_comp_id, tgt_comp_id, field_id);
299 instance, src_comp_name, src_grid_name, field_name,
300 tgt_comp_name, tgt_grid_name, field_name,
301 coupling_period, YAC_REDUCTION_TIME_NONE, interp_stack, 60, 60,
302 NULL, YAC_WEIGHT_FILE_ON_EXISTING_DEFAULT_VALUE, 0, 1.0, 0.0, 0,
303 NULL, NULL, NULL, NULL, 0);
304 }
305 yac_interp_stack_config_delete(interp_stack);
306 }
307 }
308 free(coupling_period);
309
310 char const * component_names[3] = {"comp_1", "comp_2", "comp_3"};
312 instance, &(component_names[comp_idx]), 1);
313
314 int comp_rank;
315 MPI_Comm component_comm =
317 instance, &(component_names[comp_idx]), 1);
318 MPI_Comm_rank(component_comm, &comp_rank);
319 MPI_Comm_free(&component_comm);
320
321 size_t num_vertices[2] = {2,2};
322 int cyclic[2] = {0,0};
323 double coordinates_x[2];
324 double coordinates_y[4][2] = {{0,1},{1,2},{2,3},{3,4}};
325
326 coordinates_x[0] = comp_rank;
327 coordinates_x[1] = comp_rank + 1;
328
329 yac_int global_cell_ids[1] = {comp_rank};
330 yac_int global_corner_ids[4] =
331 {4 * comp_rank + 0, 4 * comp_rank + 1,
332 4 * comp_rank + 2, 4 * comp_rank + 3};
333 int cell_core_mask[1] = {1};
334 int corner_core_mask[4] = {1,1,1,1};
335
336 // [direction][grid_idx]
337 struct yac_basic_grid * grid[2][4];
338 // [direction][grid_idx][field_idx]
339 struct yac_interp_field interp_fields[2][4][4];
340
341 char * timestep[2] = {strdup(yac_time_to_ISO("20", C_SECOND)),
342 strdup(yac_time_to_ISO("10", C_SECOND))};
343 size_t collection_size = 1;
344 char const * str_direction[2] = {"in", "out"};
345
346 for (int grid_idx = 0; grid_idx < 4; ++grid_idx) {
347 for (int direction = 0; direction < 2; ++direction) {
348 char grid_name[256];
349 sprintf(
350 grid_name, "grid_%d_%d_%s", comp_idx+1,
351 grid_idx+1, str_direction[direction]);
355 grid_data.cell_ids = TO_POINTER(global_cell_ids);
356 grid_data.vertex_ids = TO_POINTER(global_corner_ids);
357 grid_data.core_cell_mask = TO_POINTER(cell_core_mask);
358 grid_data.core_vertex_mask = TO_POINTER(corner_core_mask);
359 grid[direction][grid_idx] = yac_basic_grid_new(grid_name, grid_data);
360 for (int point_idx = 0; point_idx < 4; ++point_idx) {
361 size_t coordinates_idx =
363 grid[direction][grid_idx], YAC_LOC_CORNER,
364 grid_data.vertex_coordinates, grid_data.num_vertices);
365 interp_fields[direction]
366 [grid_idx]
367 [point_idx].location = YAC_LOC_CORNER;
368 interp_fields[direction]
369 [grid_idx]
370 [point_idx].coordinates_idx = coordinates_idx;
371 interp_fields[direction]
372 [grid_idx]
373 [point_idx].masks_idx = SIZE_MAX;
374 }
375 }
376 }
377
378 for (int comp_offset = -1; comp_offset <= 1; comp_offset += 2) {
379 int other_comp_idx = (comp_idx + comp_offset + 3) % 3;
380 for (int field_idx = 0; field_idx < 4; ++field_idx) {
381 for (int direction = 0; direction < 2; ++direction) {
382 char field_name[256];
383 sprintf(field_name, "field_from_%u_to_%u_%u",
384 ((direction == IN)?other_comp_idx:comp_idx)+1,
385 ((direction == IN)?comp_idx:other_comp_idx)+1,
386 field_idx + 1);
387 struct field_config transient_config =
388 test_config[direction][comp_idx][field_idx];
389 int grid_idx = transient_config.grid_idx;
390 int point_idx = transient_config.point_idx;
392 instance, field_name, component_names[comp_idx], grid[direction][grid_idx],
393 &interp_fields[direction][grid_idx][point_idx], 1,
394 collection_size, timestep[direction]);
395 }
396 }
397 }
398 free(timestep[1]);
399 free(timestep[0]);
400
401 yac_instance_setup(instance, &grid[0][0], 2 * 4);
402
403 yac_instance_delete(instance);
404
405 for (int grid_idx = 0; grid_idx < 4; ++grid_idx)
406 for (int direction = 0; direction < 2; ++direction)
407 yac_basic_grid_delete(grid[direction][grid_idx]);
408}
char const * component_names[]
unsigned grid_idx[3]
struct yac_basic_grid * yac_basic_grid_new(char const *name, struct yac_basic_grid_data grid_data)
Definition basic_grid.c:50
size_t yac_basic_grid_add_coordinates(struct yac_basic_grid *grid, enum yac_location location, yac_coordinate_pointer coordinates, size_t count)
Definition basic_grid.c:232
void yac_basic_grid_delete(struct yac_basic_grid *grid)
Definition basic_grid.c:70
struct yac_basic_grid_data yac_generate_basic_grid_data_reg_2d_deg(size_t nbr_vertices[2], int cyclic[2], double *lon_vertices, double *lat_vertices)
Definition grid_reg2d.c:74
char const * yac_time_to_ISO(char const *time, enum yac_time_unit_type time_unit)
Definition event.c:329
#define UNUSED(x)
Definition core.h:73
@ C_SECOND
void yac_instance_delete(struct yac_instance *instance)
Definition instance.c:1401
void yac_instance_def_datetime(struct yac_instance *instance, const char *start_datetime, const char *end_datetime)
Definition instance.c:1440
void yac_instance_setup(struct yac_instance *instance, struct yac_basic_grid **grids, size_t num_grids)
Definition instance.c:1306
struct yac_instance * yac_instance_new(MPI_Comm comm)
Definition instance.c:1376
struct coupling_field * yac_instance_add_field(struct yac_instance *instance, char const *field_name, char const *comp_name, struct yac_basic_grid *grid, struct yac_interp_field *interp_fields, size_t num_interp_fields, int collection_size, char const *timestep)
Definition instance.c:1487
void yac_instance_def_components(struct yac_instance *instance, char const **comp_names, size_t num_comps)
Definition instance.c:1458
void yac_instance_def_couple(struct yac_instance *instance, char const *src_comp_name, char const *src_grid_name, char const *src_field_name, char const *tgt_comp_name, char const *tgt_grid_name, char const *tgt_field_name, char const *coupling_period, int time_reduction, struct yac_interp_stack_config *interp_stack_config, int src_lag, int tgt_lag, const char *weight_file_name, int weight_file_on_existing, int mapping_on_source, double scale_factor, double scale_summand, size_t num_src_mask_names, char const *const *src_mask_names, char const *tgt_mask_name, char const *yaxt_exchanger_name, struct yac_collection_selection const *collection_selection, int use_raw_exchange)
Definition instance.c:1546
MPI_Comm yac_instance_get_comps_comm(struct yac_instance *instance, char const **comp_names, size_t num_comp_names)
Definition instance.c:1342
void yac_interp_method_cleanup()
void * user_data
void yac_interp_method_check_add_constructor_callback(func_constructor constructor_callback, void *user_data, char const *key)
void yac_interp_method_check_add_do_search_callback(func_do_search do_search_callback, void *user_data, char const *key)
void yac_interp_stack_config_add_check(struct yac_interp_stack_config *interp_stack_config, char const *constructor_key, char const *do_search_key)
void yac_interp_stack_config_add_fixed(struct yac_interp_stack_config *interp_stack_config, double value)
void yac_interp_stack_config_delete(struct yac_interp_stack_config *interp_stack_config)
struct yac_interp_stack_config * yac_interp_stack_config_new()
#define YAC_WEIGHT_FILE_ON_EXISTING_DEFAULT_VALUE
@ YAC_LOC_CORNER
Definition location.h:15
Definition __init__.py:1
struct field_config src tgt
enum yac_location location
Definition basic_grid.h:16
size_t coordinates_idx
Definition basic_grid.h:17
#define TO_POINTER(a)
Definition test_common.h:14
int collection_size
static int compare_size_t(const void *a, const void *b)
static void check_do_search(yac_int const *global_ids, double const (*coordinates_xyz)[3], size_t count, void *user_data)
static void check_constructor(void *user_data)
static void run_test_configuration(struct field_config test_config[2][3][4])
static int compare_field_config_src_tgt(const void *a, const void *b)
static int compare_field_config(const void *a, const void *b)
char const src_grid_name[]
char const tgt_grid_name[]
double coordinates_x[]
double coordinates_y[]
unsigned cyclic[2]
#define TEST_EXIT_CODE
Definition tests.h:14
#define PUT_ERR(string)
Definition tests.h:10
int * cell_core_mask
int * field_id
void yac_cdef_calendar(int calendar)
Definition yac.c:746
int const YAC_PROLEPTIC_GREGORIAN
Definition yac.c:65
static size_t num_points
Definition yac.c:159
int const YAC_REDUCTION_TIME_NONE
Definition yac.c:49
void yac_mpi_finalize()
Definition yac_mpi.c:108
void yac_yaxt_init(MPI_Comm comm)
Definition yac_mpi.c:40
void yac_mpi_init()
Definition yac_mpi.c:77
YAC_INT yac_int
Definition yac_types.h:15