YetAnotherCoupler 3.2.0_a
Loading...
Searching...
No Matches
interp_method_file.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 <string.h>
6
9#include "dist_grid.h"
10#include "yac_mpi_internal.h"
11#include "io_utils.h"
12
13static size_t do_search_file(struct interp_method * method,
14 struct yac_interp_grid * interp_grid,
15 size_t * tgt_points, size_t count,
16 struct yac_interp_weights * weights);
17static void delete_file(struct interp_method * method);
18
19static struct interp_method_vtable
23
25
27 char const * weight_file_name;
28 char const * src_grid_name;
29 char const * tgt_grid_name;
30};
31
32struct link_data {
33 union {
35 size_t local_id;
36 } src, tgt;
37 double weight;
39};
40
41struct fixed_data {
42 double value;
43 struct {
45 } * tgt;
46 size_t num_tgt;
47};
48
50 double value;
51 struct {
53 } tgt;
54};
55
57 enum {
58 LINK = 0,
59 FIXED = 1,
62 union {
63 struct {
64 struct link_data * links;
65 size_t count;
67 struct {
68 double value;
71 struct {
73 size_t local_id;
74 } tgt;
75 int owner;
77};
78
79static void read_weight_file(
80 char const * weight_file_name, MPI_Comm comm,
81 char const * src_grid_name, char const * tgt_grid_name,
82 enum yac_location * src_locations, enum yac_location tgt_location,
83 size_t num_src_fields,
84 struct link_data ** links, size_t * num_links,
85 struct fixed_data ** fixed, size_t * num_fixed) {
86
87#ifndef YAC_NETCDF_ENABLED
88
89 UNUSED(weight_file_name);
90 UNUSED(comm);
91 UNUSED(src_grid_name);
92 UNUSED(tgt_grid_name);
93 UNUSED(src_locations);
94 UNUSED(tgt_location);
95 UNUSED(num_src_fields);
96 UNUSED(links);
97 UNUSED(num_links);
98 UNUSED(fixed);
99 UNUSED(num_fixed);
100
101 die("ERROR(read_weight_file): YAC is built without the NetCDF support");
102#else
103
104 *links = NULL;
105 *num_links = 0;
106 *fixed = NULL;
107 *num_fixed = 0;
108
109 int rank;
110 yac_mpi_call(MPI_Comm_rank(comm, &rank), comm);
111
112 // determine ranks that do input
113 int local_is_io;
114 int * io_ranks;
115 int num_io_ranks;
116 yac_get_io_ranks(comm, &local_is_io, &io_ranks, &num_io_ranks);
117
118 int io_idx = INT_MAX;
119 if (local_is_io)
120 for (int i = 0; (i < num_io_ranks) && (io_idx == INT_MAX); ++i)
121 if (io_ranks[i] == rank) io_idx = i;
122 free(io_ranks);
123
124 // if the local process does not have to read anything from the file
125 if (!local_is_io) return;
126
127 // open weight file on io processes
128 int ncid;
129 yac_nc_open(weight_file_name, NC_NOWRITE, &ncid);
130
131 //\todo use parallel netcdf if available
132
133 int dimid, var_id;
134
135 // global attributes
136 size_t version_len;
137 char * version;
138 YAC_HANDLE_ERROR(nc_inq_attlen(ncid, NC_GLOBAL, "version", &version_len));
139 version = xmalloc(version_len + 1);
140 version[version_len] = '\0';
141 YAC_HANDLE_ERROR(nc_get_att_text(ncid, NC_GLOBAL, "version", version));
143 (strlen(YAC_WEIGHT_FILE_VERSION_STRING) == version_len) &&
144 !strncmp(version, YAC_WEIGHT_FILE_VERSION_STRING, version_len),
145 "ERROR(read_weight_file): "
146 "version string from weight file (\"%s\") does not match "
147 "with YAC version \"%s\"", version, YAC_WEIGHT_FILE_VERSION_STRING)
148 free(version);
149
150 size_t grid_name_len;
151 char * grid_name;
152 YAC_HANDLE_ERROR(nc_inq_attlen(ncid, NC_GLOBAL, "src_grid_name", &grid_name_len));
153 grid_name = xmalloc(grid_name_len + 1);
154 grid_name[grid_name_len] = '\0';
155 YAC_HANDLE_ERROR(nc_get_att_text(ncid, NC_GLOBAL, "src_grid_name", grid_name));
157 (strlen(src_grid_name) == grid_name_len) &&
158 !strncmp(src_grid_name, grid_name, grid_name_len),
159 "ERROR(read_weight_file): source grid name from weight file (\"%s\") "
160 "does not match with the one provided through the interface (\"%s\")",
161 grid_name, src_grid_name)
162
163 free(grid_name);
164
165 YAC_HANDLE_ERROR(nc_inq_attlen(ncid, NC_GLOBAL, "dst_grid_name", &grid_name_len));
166 grid_name = xmalloc(grid_name_len + 1);
167 grid_name[grid_name_len] = '\0';
168 YAC_HANDLE_ERROR(nc_get_att_text(ncid, NC_GLOBAL, "dst_grid_name", grid_name));
170 (strlen(tgt_grid_name) == grid_name_len) &&
171 !strncmp(tgt_grid_name, grid_name, grid_name_len),
172 "ERROR(read_weight_file): target grid name from weight file (\"%s\") "
173 "does not match with the one provided through the interface (\"%s\")",
174 grid_name, tgt_grid_name)
175
176 free(grid_name);
177
178 //---------------
179 // read link data
180 //---------------
181
182 size_t str_link_len;
183 char * str_link;
184 var_id = NC_GLOBAL;
185 YAC_HANDLE_ERROR(nc_inq_attlen(ncid, var_id, "contains_links", &str_link_len));
186 str_link = xmalloc(str_link_len + 1);
187 str_link[str_link_len] = '\0';
188 YAC_HANDLE_ERROR(nc_get_att_text(ncid, var_id, "contains_links", str_link));
189
190 int contains_links = (strlen("TRUE") == str_link_len) &&
191 !strncmp("TRUE", str_link, str_link_len);
193 contains_links ||
194 ((strlen("FALSE") == str_link_len) &&
195 !strncmp("FALSE", str_link, str_link_len)),
196 "ERROR(read_weight_file): invalid global attribute contains_links")
197 free(str_link);
198
199 size_t num_wgts = 0;
200 if (contains_links) {
201 yac_nc_inq_dimid(ncid, "num_wgts", &dimid);
202 YAC_HANDLE_ERROR(nc_inq_dimlen(ncid, dimid, &num_wgts));
204 num_wgts == 1, "ERROR(read_weight_file): YAC only supports num_wgts == 1")
205 }
206
207 // get number of links from file
208
209 size_t num_links_in_file = 0;
210 if (contains_links) {
211 yac_nc_inq_dimid(ncid, "num_links", &dimid);
212 YAC_HANDLE_ERROR(nc_inq_dimlen(ncid, dimid, &num_links_in_file));
214 num_links_in_file != 0, "ERROR(read_weight_file): no links defined")
215 }
216
217 // get number of source fields
218 size_t tmp_num_src_fields = 0;
219 if (contains_links) {
220 yac_nc_inq_dimid(ncid, "num_src_fields", &dimid);
221 YAC_HANDLE_ERROR(nc_inq_dimlen(ncid, dimid, &tmp_num_src_fields));
223 tmp_num_src_fields != 0,
224 "ERROR(read_weight_file): no source fields in file")
226 tmp_num_src_fields == num_src_fields,
227 "ERROR(read_weight_file): number of source fields in file (%zu) does not "
228 "match with the number provided through the interface (%zu)",
229 tmp_num_src_fields, num_src_fields)
230 }
231
232 // get max location string length from file
233 size_t max_loc_str_len;
234 yac_nc_inq_dimid(ncid, "max_loc_str_len", &dimid);
235 YAC_HANDLE_ERROR(nc_inq_dimlen(ncid, dimid, &max_loc_str_len));
237 max_loc_str_len == YAC_MAX_LOC_STR_LEN,
238 "ERROR(read_weight_file): wrong max location string length in weight file")
239
240 // get source locations
241 enum yac_location * tmp_src_locations =
242 xmalloc(num_src_fields * sizeof(*tmp_src_locations));
243 yac_nc_inq_varid(ncid, "src_locations", &var_id);
244
245 for (size_t i = 0; i < num_src_fields; ++i) {
246
247 char loc_str[YAC_MAX_LOC_STR_LEN];
248
249 size_t str_start[2] = {i, 0};
250 size_t str_count[2] = {1, YAC_MAX_LOC_STR_LEN};
251
253 nc_get_vara_text(ncid, var_id, str_start, str_count, loc_str));
254
255 tmp_src_locations[i] = yac_str2loc(loc_str);
256
258 tmp_src_locations[i] == src_locations[i],
259 "ERROR(read_weight_file): source locations in file does not match with "
260 "the locations provided through the interface\n"
261 "location index: %d\n"
262 "location in weight file: %s\n"
263 "location from interface: %s",
264 (int)i, loc_str, yac_loc2str(src_locations[i]))
265 }
266
267 free(tmp_src_locations);
268
269 // get target location
270 yac_nc_inq_varid(ncid, "dst_location", &var_id);
271 {
272 char loc_str[YAC_MAX_LOC_STR_LEN];
273 YAC_HANDLE_ERROR(nc_get_var_text(ncid, var_id, loc_str));
275 tgt_location == yac_str2loc(loc_str),
276 "ERROR(read_weight_file): target locations in file does not match with "
277 "the locations provided through the interface")
278 }
279
280 if (contains_links) {
281
282 // get number of links per source field
283 unsigned * num_links_per_src_field =
284 xmalloc(num_src_fields * sizeof(*num_links_per_src_field));
285 yac_nc_inq_varid(ncid, "num_links_per_src_field", &var_id);
286 YAC_HANDLE_ERROR(nc_get_var_uint(ncid, var_id, num_links_per_src_field));
287
288 size_t offset =
289 (size_t)(((long long)io_idx * (long long)num_links_in_file) /
290 (long long)num_io_ranks);
291 size_t count =
292 (size_t)((((long long)io_idx + 1) * (long long)num_links_in_file) /
293 (long long)num_io_ranks) - offset;
294
295 *num_links = count;
296
297 *links = xmalloc(count * sizeof(**links));
298
299 if (count > 0) {
300 size_t src_field_idx = 0, src_field_start_offset = 0;
301 while ((src_field_idx < num_src_fields) &&
302 (src_field_start_offset +
303 (size_t)num_links_per_src_field[src_field_idx] <
304 offset)) {
305
306 src_field_start_offset += (size_t)num_links_per_src_field[src_field_idx];
307 ++src_field_idx;
308 };
310 src_field_idx < num_src_fields,
311 "ERROR(read_weight_file): problem in num_links_per_src_field")
312 size_t src_field_offset = offset - src_field_start_offset;
313 for (size_t k = 0; (src_field_idx < num_src_fields) && (k < count);
314 src_field_offset = 0, ++src_field_idx) {
315
316 for (; (src_field_offset <
317 (size_t)num_links_per_src_field[src_field_idx]) &&
318 (k < count); ++src_field_offset, ++k) {
319 (*links)[k].src_field_idx = src_field_idx;
320 }
321 }
322 }
323 free(num_links_per_src_field);
324
325 // get links
326 int * address = xmalloc(count * sizeof(*address));
327 yac_nc_inq_varid(ncid, "src_address", &var_id);
328 YAC_HANDLE_ERROR(nc_get_vara_int(ncid, var_id, &offset, &count, address));
329 for (size_t i = 0; i < count; ++i)
330 (*links)[i].src.global_id = (yac_int)(address[i] - 1);
331
332 yac_nc_inq_varid(ncid, "dst_address", &var_id);
333 YAC_HANDLE_ERROR(nc_get_vara_int(ncid, var_id, &offset, &count, address));
334 for (size_t i = 0; i < count; ++i)
335 (*links)[i].tgt.global_id = (yac_int)(address[i] - 1);
336 free(address);
337
338 double * weights = xmalloc(count * sizeof(*weights));
339
340 yac_nc_inq_varid(ncid, "remap_matrix", &var_id);
341 size_t offsets[2] = {offset, 0};
342 size_t counts[2] = {count, 1};
343 YAC_HANDLE_ERROR(nc_get_vara_double(ncid, var_id, offsets, counts, weights));
344 for (size_t i = 0; i < count; ++i)
345 (*links)[i].weight = weights[i];
346
347 free(weights);
348 }
349
350 //----------------
351 // read fixed data
352 //----------------
353
354 // global attributes
355 size_t str_fixed_len;
356 char * str_fixed;
357 var_id = NC_GLOBAL;
359 nc_inq_attlen(ncid, var_id, "contains_fixed_dst", &str_fixed_len));
360 str_fixed = xmalloc(str_fixed_len + 1);
361 str_fixed[str_fixed_len] = '\0';
362 YAC_HANDLE_ERROR(nc_get_att_text(ncid, var_id, "contains_fixed_dst", str_fixed));
363
364 int contains_fixed = (strlen("TRUE") == str_fixed_len) &&
365 !strncmp("TRUE", str_fixed, str_fixed_len);
366
368 contains_fixed ||
369 ((strlen("FALSE") == str_fixed_len) &&
370 !strncmp("FALSE", str_fixed, str_fixed_len)),
371 "ERROR(read_weight_file): invalid global attribute contains_fixed_dst")
372 free(str_fixed);
373
374 if (contains_fixed) {
375
376 // get number of fixed values
377 size_t num_fixed_values;
378 yac_nc_inq_dimid(ncid, "num_fixed_values", &dimid);
379 YAC_HANDLE_ERROR(nc_inq_dimlen(ncid, dimid, &num_fixed_values));
380
381 // get number of fixed target points
382 size_t num_fixed_tgt;
383 yac_nc_inq_dimid(ncid, "num_fixed_dst", &dimid);
384 YAC_HANDLE_ERROR(nc_inq_dimlen(ncid, dimid, &num_fixed_tgt));
385
386 size_t offset =
387 (size_t)(((long long)io_idx * (long long)num_fixed_tgt) /
388 (long long)num_io_ranks);
389 size_t count =
390 (size_t)((((long long)io_idx + 1) * (long long)num_fixed_tgt) /
391 (long long)num_io_ranks) - offset;
392
393 *fixed = xmalloc(num_fixed_values * sizeof(**fixed));
394 *num_fixed = num_fixed_values;
395
396 double * fixed_values = xmalloc(num_fixed_values * sizeof(*fixed_values));
397 int * num_tgt_indices_per_fixed_value =
398 xmalloc(num_fixed_values * sizeof(*num_tgt_indices_per_fixed_value));
399 int * global_tgt_indices = xmalloc(count * sizeof(*global_tgt_indices));
400
401 // get number of fixed target points per fixed value
402 yac_nc_inq_varid(ncid, "num_dst_per_fixed_value", &var_id);
403 YAC_HANDLE_ERROR(nc_get_var_int(ncid, var_id, num_tgt_indices_per_fixed_value));
404
405 // read data
406 yac_nc_inq_varid(ncid, "fixed_values", &var_id);
407 YAC_HANDLE_ERROR(nc_get_var_double(ncid, var_id, fixed_values));
408
409 yac_nc_inq_varid(ncid, "dst_address_fixed", &var_id);
411 nc_get_vara_int(ncid, var_id, &offset, &count, global_tgt_indices));
412
413 if (count > 0) {
414 void * tgt_global_id_buffer = xmalloc(count * sizeof(*((*fixed)->tgt)));
415 size_t fixed_value_idx = 0, fixed_value_start_offset = 0;
416 while ((fixed_value_idx < num_fixed_values) &&
417 (fixed_value_start_offset +
418 (size_t)num_tgt_indices_per_fixed_value[fixed_value_idx] <
419 offset)) {
420
421 fixed_value_start_offset +=
422 (size_t)num_tgt_indices_per_fixed_value[fixed_value_idx];
423 (*fixed)[fixed_value_idx].value = fixed_values[fixed_value_idx];
424 (*fixed)[fixed_value_idx].num_tgt = 0;
425 (*fixed)[fixed_value_idx].tgt = tgt_global_id_buffer;
426 ++fixed_value_idx;
427 };
429 fixed_value_idx < num_fixed_values,
430 "ERROR(read_weight_file): problem in num_tgt_indices_per_fixed_value")
431 size_t fixed_value_offset = offset - fixed_value_start_offset;
432 for (size_t k = 0; (fixed_value_idx < num_fixed_values) && (k < count);
433 fixed_value_offset = 0, ++fixed_value_idx) {
434
435 size_t curr_tgt_count =
436 MIN((size_t)num_tgt_indices_per_fixed_value[fixed_value_idx] -
437 fixed_value_offset, count - k);
438
439 (*fixed)[fixed_value_idx].value = fixed_values[fixed_value_idx];
440 (*fixed)[fixed_value_idx].num_tgt = curr_tgt_count;
441 (*fixed)[fixed_value_idx].tgt =
442 (void*)(((unsigned char *)tgt_global_id_buffer) +
443 k * sizeof(*((*fixed)->tgt)));
444
445 for (size_t i = 0; i < curr_tgt_count; ++fixed_value_offset, ++k, ++i)
446 (*fixed)[fixed_value_idx].tgt[i].global_id =
447 (yac_int)(global_tgt_indices[k] - 1);
448 }
449 for (; fixed_value_idx < num_fixed_values; ++fixed_value_idx) {
450 (*fixed)[fixed_value_idx].value = fixed_values[fixed_value_idx];
451 (*fixed)[fixed_value_idx].num_tgt = 0;
452 (*fixed)[fixed_value_idx].tgt = NULL;
453 }
454 }
455 free(fixed_values);
456 free(global_tgt_indices);
457 free(num_tgt_indices_per_fixed_value);
458 }
459#endif
460}
461
462static inline int
463compute_bucket(yac_int value, int comm_size) {
464 return (int)(value / 128) % comm_size;
465}
466
467static int get_tgt_pack_size(MPI_Comm comm) {
468
469 int tgt_pack_size;
470 yac_mpi_call(MPI_Pack_size(1, yac_int_dt, comm, &tgt_pack_size), comm);
471 return tgt_pack_size;
472}
473
474static int get_link_pack_size(MPI_Comm comm) {
475
476 int global_id_pack_size;
477 int weight_pack_size;
478 int src_field_idx_pack_size;
479
481 MPI_Pack_size(1, yac_int_dt, comm, &global_id_pack_size), comm);
483 MPI_Pack_size(1, MPI_DOUBLE, comm, &weight_pack_size), comm);
485 MPI_Pack_size(1, MPI_UINT64_T, comm, &src_field_idx_pack_size), comm);
486
487 return 2 * global_id_pack_size + weight_pack_size +
488 src_field_idx_pack_size;
489}
490
491static int get_fixed_pack_size(MPI_Comm comm) {
492
493 int value_pack_size;
494 int global_id_pack_size;
495 int count_pack_size;
496
498 MPI_Pack_size(1, MPI_DOUBLE, comm, &value_pack_size), comm);
500 MPI_Pack_size(1, yac_int_dt, comm, &global_id_pack_size), comm);
502 MPI_Pack_size(1, MPI_UINT64_T, comm, &count_pack_size), comm);
503
504 return value_pack_size + global_id_pack_size + count_pack_size;
505}
506
507static void pack_tgt(
508 yac_int global_tgt_id, void * buffer, int buffer_size, MPI_Comm comm) {
509
510 int position = 0;
512 MPI_Pack(&global_tgt_id, 1, yac_int_dt, buffer,
513 buffer_size, &position, comm), comm);
514}
515
516static void pack_link(
517 struct link_data * link, void * buffer, int buffer_size, MPI_Comm comm) {
518
519 int position = 0;
521 MPI_Pack(&(link->src.global_id), 1, yac_int_dt, buffer,
522 buffer_size, &position, comm), comm);
524 MPI_Pack(&(link->tgt.global_id), 1, yac_int_dt, buffer,
525 buffer_size, &position, comm), comm);
527 MPI_Pack(&(link->weight), 1, MPI_DOUBLE, buffer,
528 buffer_size, &position, comm), comm);
529 uint64_t temp_src_field_idx = (uint64_t)(link->src_field_idx);
531 MPI_Pack(&temp_src_field_idx, 1, MPI_UINT64_T, buffer,
532 buffer_size, &position, comm), comm);
533
534}
535
536static void pack_fixed(
537 double fixed_value, yac_int global_tgt_id,
538 void * buffer, int buffer_size, MPI_Comm comm) {
539
540 int position = 0;
542 MPI_Pack(&fixed_value, 1, MPI_DOUBLE, buffer,
543 buffer_size, &position, comm), comm);
545 MPI_Pack(&global_tgt_id, 1, yac_int_dt, buffer,
546 buffer_size, &position, comm), comm);
547}
548
549static void unpack_tgt(
550 void * buffer, int buffer_size, yac_int * global_tgt_id, MPI_Comm comm) {
551
552 int position = 0;
554 MPI_Unpack(buffer, buffer_size, &position, global_tgt_id, 1,
555 yac_int_dt, comm), comm);
556}
557
558static void unpack_link(
559 void * buffer, int buffer_size, struct link_data * link, MPI_Comm comm) {
560
561 int position = 0;
563 MPI_Unpack(buffer, buffer_size, &position, &(link->src.global_id), 1,
564 yac_int_dt, comm), comm);
566 MPI_Unpack(buffer, buffer_size, &position, &(link->tgt.global_id), 1,
567 yac_int_dt, comm), comm);
569 MPI_Unpack(buffer, buffer_size, &position, &(link->weight), 1,
570 MPI_DOUBLE, comm), comm);
571 uint64_t temp_src_field_idx;
573 MPI_Unpack(buffer, buffer_size, &position, &temp_src_field_idx, 1,
574 MPI_UINT64_T, comm), comm);
575 link->src_field_idx = (size_t)temp_src_field_idx;
576}
577
578static void unpack_fixed(
579 void * buffer, int buffer_size, struct temp_fixed_data * fixed,
580 MPI_Comm comm) {
581
582 int position = 0;
584 MPI_Unpack(buffer, buffer_size, &position, &(fixed->value), 1,
585 MPI_DOUBLE, comm), comm);
587 MPI_Unpack(buffer, buffer_size, &position, &(fixed->tgt.global_id), 1,
588 yac_int_dt, comm), comm);
589}
590
591static int compare_temp_result_tgt (void const * a, void const * b) {
592
593 struct temp_result const * result_a = (struct temp_result const *)a;
594 struct temp_result const * result_b = (struct temp_result const *)b;
595
596 return (result_a->tgt.global_id > result_b->tgt.global_id) -
597 (result_a->tgt.global_id < result_b->tgt.global_id);
598}
599
600static int compare_link_data_tgt (void const * a, void const * b) {
601
602 struct link_data const * link_a = (struct link_data const *)a;
603 struct link_data const * link_b = (struct link_data const *)b;
604
605 return (link_a->tgt.global_id > link_b->tgt.global_id) -
606 (link_a->tgt.global_id < link_b->tgt.global_id);
607}
608
609static int compare_temp_result_type (void const * a, void const * b) {
610
611 struct temp_result const * result_a = (struct temp_result const *)a;
612 struct temp_result const * result_b = (struct temp_result const *)b;
613
614 return (result_a->type > result_b->type) - (result_a->type < result_b->type);
615}
616
617static int compare_temp_result_fixed (void const * a, void const * b) {
618
619 struct temp_result const * result_a = (struct temp_result const *)a;
620 struct temp_result const * result_b = (struct temp_result const *)b;
621
622 return (result_a->data.fixed.value > result_b->data.fixed.value) -
623 (result_a->data.fixed.value < result_b->data.fixed.value);
624}
625
626static int compare_temp_result_reorder_idx (void const * a, void const * b) {
627
628 struct temp_result const * result_a = (struct temp_result const *)a;
629 struct temp_result const * result_b = (struct temp_result const *)b;
630
631 return (result_a->reorder_idx > result_b->reorder_idx) -
632 (result_a->reorder_idx < result_b->reorder_idx);
633}
634
635static int compare_temp_fixed_data_tgt (void const * a, void const * b) {
636
637 struct temp_fixed_data const * fixed_a = (struct temp_fixed_data const *)a;
638 struct temp_fixed_data const * fixed_b = (struct temp_fixed_data const *)b;
639
640 return (fixed_a->tgt.global_id > fixed_b->tgt.global_id) -
641 (fixed_a->tgt.global_id < fixed_b->tgt.global_id);
642}
643
645 struct temp_result * result, MPI_Comm comm) {
646
647 int type_pack_size;
648 int data_pack_size;
649 int owner_pack_size;
650
652 MPI_Pack_size(1, MPI_INT, comm, &type_pack_size), comm);
654 (result->type == LINK) ||
655 (result->type == FIXED) ||
656 (result->type == NO_INTERP),
657 "ERROR(get_temp_result_pack_size): invalid result type")
658 switch(result->type) {
659 case(LINK): {
660 int count_pack_size;
661 int links_pack_size;
663 MPI_Pack_size(1, MPI_UINT64_T, comm, &count_pack_size), comm);
664 links_pack_size =
665 (int)(result->data.link.count) * get_link_pack_size(comm);
666 data_pack_size = links_pack_size + count_pack_size;
667 break;
668 }
669 case(FIXED): {
670 int fixed_value_pack_size;
672 MPI_Pack_size(1, MPI_DOUBLE, comm, &fixed_value_pack_size), comm);
673 data_pack_size = fixed_value_pack_size;
674 break;
675 }
676 default:
677 case(NO_INTERP): {
678 data_pack_size = 0;
679 break;
680 }
681 };
682 int tgt_global_id_pack_size;
684 MPI_Pack_size(1, yac_int_dt, comm, &tgt_global_id_pack_size), comm);
686 MPI_Pack_size(1, MPI_INT, comm, &owner_pack_size), comm);
687
688 return type_pack_size + data_pack_size + tgt_global_id_pack_size +
689 owner_pack_size;
690}
691
693 struct temp_result * result, void * buffer, int buffer_size, MPI_Comm comm) {
694
695 int position = 0;
696 int temp_type = (int)(result->type);
698 MPI_Pack(&temp_type, 1, MPI_INT, buffer,
699 buffer_size, &position, comm), comm);
701 (result->type == LINK) ||
702 (result->type == FIXED) ||
703 (result->type == NO_INTERP),
704 "ERROR(get_temp_result_pack_size): invalid result type")
705 switch(result->type) {
706 case(LINK): {
707 uint64_t temp_count = (uint64_t)(result->data.link.count);
709 MPI_Pack(&temp_count, 1, MPI_UINT64_T, buffer,
710 buffer_size, &position, comm), comm);
711 for (uint64_t i = 0; i < temp_count; ++i) {
713 MPI_Pack(&(result->data.link.links[i].src.global_id), 1,
714 yac_int_dt, buffer, buffer_size, &position, comm), comm);
716 MPI_Pack(&(result->data.link.links[i].tgt.global_id), 1,
717 yac_int_dt, buffer, buffer_size, &position, comm), comm);
719 MPI_Pack(&(result->data.link.links[i].weight), 1,
720 MPI_DOUBLE, buffer, buffer_size, &position, comm), comm);
721 uint64_t temp_src_field_idx =
722 (uint64_t)result->data.link.links[i].src_field_idx;
724 MPI_Pack(&temp_src_field_idx, 1, MPI_UINT64_T,
725 buffer, buffer_size, &position, comm), comm);
726 }
727 break;
728 }
729 case(FIXED): {
731 MPI_Pack(&(result->data.fixed.value), 1,
732 MPI_DOUBLE, buffer, buffer_size, &position, comm), comm);
733 break;
734 }
735 default:
736 case(NO_INTERP): {
737 break;
738 }
739 };
741 MPI_Pack(&(result->tgt.global_id), 1,
742 yac_int_dt, buffer, buffer_size, &position, comm), comm);
744 MPI_Pack(&(result->owner), 1, MPI_INT,
745 buffer, buffer_size, &position, comm), comm);
746}
747
749 void * buffer, int buffer_size, struct temp_result * result,
750 MPI_Comm comm) {
751
752 int position = 0;
753
754 int temp_type;
756 MPI_Unpack(buffer, buffer_size, &position, &temp_type, 1,
757 MPI_INT, comm), comm);
759 (temp_type == LINK) || (temp_type == FIXED) || (temp_type == NO_INTERP),
760 "ERROR(unpack_temp_result): invalid result type")
761 switch (temp_type) {
762 case(LINK): {
763 result->type = LINK;
764 uint64_t temp_count;
766 MPI_Unpack(buffer, buffer_size, &position, &temp_count, 1,
767 MPI_UINT64_T, comm), comm);
768 result->data.link.count = (size_t)temp_count;
769 result->data.link.links =
770 xmalloc((size_t)temp_count * sizeof(*(result->data.link.links)));
771 for (uint64_t i = 0; i < temp_count; ++i) {
772
774 MPI_Unpack(buffer, buffer_size, &position,
775 &(result->data.link.links[i].src.global_id), 1,
776 yac_int_dt, comm), comm);
778 MPI_Unpack(buffer, buffer_size, &position,
779 &(result->data.link.links[i].tgt.global_id), 1,
780 yac_int_dt, comm), comm);
782 MPI_Unpack(buffer, buffer_size, &position,
783 &(result->data.link.links[i].weight), 1,
784 MPI_DOUBLE, comm), comm);
785 uint64_t temp_src_field_idx;
787 MPI_Unpack(buffer, buffer_size, &position, &temp_src_field_idx, 1,
788 MPI_UINT64_T, comm), comm);
789 result->data.link.links[i].src_field_idx = (size_t)temp_src_field_idx;
790 }
791 break;
792 }
793 case (FIXED): {
794 result->type = FIXED;
796 MPI_Unpack(buffer, buffer_size, &position,
797 &(result->data.fixed.value), 1, MPI_DOUBLE, comm), comm);
798 break;
799 }
800 default:
801 case (NO_INTERP): {
802 result->type = NO_INTERP;
803 break;
804 }
805 };
807 MPI_Unpack(buffer, buffer_size, &position,
808 &(result->tgt.global_id), 1, yac_int_dt, comm), comm);
810 MPI_Unpack(buffer, buffer_size, &position,
811 &(result->owner), 1, MPI_INT, comm), comm);
812}
813
815 struct yac_interp_grid * interp_grid, size_t * tgt_points, size_t tgt_count,
816 size_t * num_interpolated_points,
817 struct link_data ** links, size_t * num_links,
818 struct fixed_data ** fixed, size_t * num_fixed) {
819
820 MPI_Comm comm = yac_interp_grid_get_MPI_Comm(interp_grid);
821
822 int comm_size;
823 yac_mpi_call(MPI_Comm_size(comm, &comm_size), comm);
824
825 // get global ids of target points that have to be interpolated
826 yac_int * tgt_global_ids = xmalloc(tgt_count * sizeof(*tgt_global_ids));
828 interp_grid, tgt_points, tgt_count, tgt_global_ids);
829
830 yac_quicksort_index_yac_int_size_t(tgt_global_ids, tgt_count, tgt_points);
831
832 int tgt_pack_size = get_tgt_pack_size(comm),
833 link_pack_size = get_link_pack_size(comm),
834 fixed_pack_size = get_fixed_pack_size(comm);
835
836 size_t * size_t_buffer =
837 xmalloc(4 * (size_t)comm_size * sizeof(*size_t_buffer));
838 size_t * total_sendcounts = size_t_buffer + 0 * comm_size;
839 size_t * total_recvcounts = size_t_buffer + 1 * comm_size;
840 size_t * total_sdispls = size_t_buffer + 2 * comm_size;
841 size_t * total_rdispls = size_t_buffer + 3 * comm_size;
842 size_t * sendcounts, * recvcounts, * sdispls, *rdispls;
844 3, &sendcounts, &recvcounts, &sdispls, &rdispls, comm);
845
846 for (size_t i = 0; i < tgt_count; ++i)
847 sendcounts[3 * compute_bucket(tgt_global_ids[i], comm_size) + 0]++;
848 for (size_t i = 0; i < *num_links; ++i)
849 sendcounts[3 * compute_bucket((*links)[i].tgt.global_id, comm_size) + 1]++;
850 for (size_t i = 0; i < *num_fixed; ++i)
851 for (size_t j = 0; j < (*fixed)[i].num_tgt; ++j)
852 sendcounts[
853 3 * compute_bucket((*fixed)[i].tgt[j].global_id, comm_size) + 2]++;
854
855 // exchange sendcounts
856 yac_mpi_call(MPI_Alltoall(sendcounts, 3, YAC_MPI_SIZE_T,
857 recvcounts, 3, YAC_MPI_SIZE_T, comm), comm);
858
859 size_t saccu = 0, raccu = 0;
860 for (int i = 0; i < comm_size; ++i) {
861 total_sdispls[i] = saccu;
862 sdispls[3*i+0] = saccu;
863 sdispls[3*i+1] =
864 (saccu +
865 (total_sendcounts[i] =
866 sendcounts[3*i+0] * (size_t)tgt_pack_size));
867 sdispls[3*i+2] =
868 (saccu +
869 (total_sendcounts[i] +=
870 sendcounts[3*i+1] * (size_t)link_pack_size));
871 total_sendcounts[i] +=
872 sendcounts[3*i+2] * (size_t)fixed_pack_size;
873 total_rdispls[i] = raccu;
874 rdispls[3*i+0] = raccu;
875 rdispls[3*i+1] =
876 (raccu +
877 (total_recvcounts[i] =
878 recvcounts[3*i+0] * (size_t)tgt_pack_size));
879 rdispls[3*i+2] =
880 (raccu +
881 (total_recvcounts[i] +=
882 recvcounts[3*i+1] * (size_t)link_pack_size));
883 total_recvcounts[i] +=
884 recvcounts[3*i+2] * (size_t)fixed_pack_size;
885 saccu += total_sendcounts[i];
886 raccu += total_recvcounts[i];
887 }
888
889 size_t send_size = total_sendcounts[comm_size - 1] +
890 total_sdispls[comm_size - 1];
891 size_t recv_size = total_recvcounts[comm_size - 1] +
892 total_rdispls[comm_size - 1];
893
894 void * pack_buffer = xmalloc(send_size + recv_size);
895 void * send_pack_buffer = pack_buffer;
896 void * recv_pack_buffer = (void*)((unsigned char *)pack_buffer + send_size);
897
898 // pack data
899 for (size_t i = 0; i < tgt_count; ++i) {
900 yac_int curr_global_id = tgt_global_ids[i];
901 int rank = compute_bucket(curr_global_id, comm_size);
902 pack_tgt(
903 curr_global_id,
904 (void*)((unsigned char*)send_pack_buffer + sdispls[3*rank+0]),
905 tgt_pack_size, comm);
906 sdispls[3*rank+0] += (size_t)tgt_pack_size;
907 }
908 for (size_t i = 0; i < *num_links; ++i) {
909 struct link_data * curr_link = (*links) + i;
910 int rank = compute_bucket(curr_link->tgt.global_id, comm_size);
911 pack_link(
912 curr_link,
913 (void*)((unsigned char*)send_pack_buffer + sdispls[3*rank+1]),
914 link_pack_size, comm);
915 sdispls[3*rank+1] += (size_t)link_pack_size;
916 }
917 for (size_t i = 0; i < *num_fixed; ++i) {
918 double curr_fixed_value = (*fixed)[i].value;
919 size_t curr_num_tgt = (*fixed)[i].num_tgt;
920 for (size_t j = 0; j < curr_num_tgt; ++j) {
921 yac_int curr_global_id = (*fixed)[i].tgt[j].global_id;
922 int rank = compute_bucket(curr_global_id, comm_size);
924 curr_fixed_value, curr_global_id,
925 (void*)((unsigned char*)send_pack_buffer + sdispls[3*rank+2]),
926 fixed_pack_size, comm);
927 sdispls[3*rank+2] += (size_t)fixed_pack_size;
928 }
929 }
930
931 // exchange data
932 yac_alltoallv_packed_p2p(
933 send_pack_buffer, total_sendcounts, total_sdispls,
934 recv_pack_buffer, total_recvcounts, total_rdispls, comm);
935
936 size_t recv_tgt_count = 0, recv_link_count = 0, recv_fixed_count = 0;
937 for (int i = 0; i < comm_size; ++i) {
938 recv_tgt_count += recvcounts[3*i+0];
939 recv_link_count += recvcounts[3*i+1];
940 recv_fixed_count += recvcounts[3*i+2];
941 }
942 struct link_data * recv_links =
943 xrealloc(*links, recv_link_count * sizeof(*recv_links));
944 struct temp_fixed_data * recv_fixed =
945 xmalloc(recv_fixed_count * sizeof(*recv_fixed));
946 struct temp_result * result_buffer =
947 xmalloc((recv_tgt_count + tgt_count) * sizeof(*result_buffer));
948 struct temp_result * send_results = result_buffer;
949 struct temp_result * recv_results = result_buffer + recv_tgt_count;
950
951 // unpack data
952 recv_tgt_count = 0, recv_link_count = 0, recv_fixed_count = 0;
953 size_t unpack_offset = 0;
954 for (int i = 0; i < comm_size; ++i) {
955 size_t curr_num_tgt = recvcounts[3 * i + 0];
956 size_t curr_num_links = recvcounts[3 * i + 1];
957 size_t curr_num_fixed = recvcounts[3 * i + 2];
958 for (size_t j = 0; j < curr_num_tgt; ++j, ++recv_tgt_count) {
960 (void*)((unsigned char *)recv_pack_buffer + unpack_offset),
961 tgt_pack_size, &(send_results[recv_tgt_count].tgt.global_id),
962 comm);
963 unpack_offset += (size_t)tgt_pack_size;
964 send_results[recv_tgt_count].owner = i;
965 send_results[recv_tgt_count].reorder_idx = recv_tgt_count;
966 }
967 for (int j = 0; j < curr_num_links; ++j, ++recv_link_count) {
969 (void*)((unsigned char *)recv_pack_buffer + unpack_offset),
970 link_pack_size, recv_links + recv_link_count, comm);
971 unpack_offset += (size_t)link_pack_size;
972 }
973 for (int j = 0; j < curr_num_fixed; ++j, ++recv_fixed_count) {
975 (void*)((unsigned char *)recv_pack_buffer + unpack_offset),
976 fixed_pack_size, recv_fixed + recv_fixed_count, comm);
977 unpack_offset += (size_t)fixed_pack_size;
978 }
979 }
980
981 // sort received target point inforation by global target id
982 qsort(
983 send_results, recv_tgt_count, sizeof(*send_results),
985
986 // sort links by global target ids
987 qsort(
988 recv_links, recv_link_count, sizeof(*recv_links), compare_link_data_tgt);
989
990 // sort fixed data by global target ids
991 qsort(
992 recv_fixed, recv_fixed_count, sizeof(*recv_fixed),
994
995 // match target points with linked and fixed data from the weight file
996 for (size_t tgt_idx = 0, link_idx = 0, fixed_idx = 0;
997 tgt_idx < recv_tgt_count; ++tgt_idx) {
998
999 yac_int curr_tgt = send_results[tgt_idx].tgt.global_id;
1000
1001 while ((link_idx < recv_link_count) &&
1002 (recv_links[link_idx].tgt.global_id < curr_tgt)) ++link_idx;
1003 while ((fixed_idx < recv_fixed_count) &&
1004 (recv_fixed[fixed_idx].tgt.global_id < curr_tgt)) ++fixed_idx;
1005
1006 YAC_ASSERT(
1007 (link_idx >= recv_link_count) ||
1008 (recv_links[link_idx].tgt.global_id != curr_tgt) ||
1009 (fixed_idx >= recv_fixed_count) ||
1010 (recv_fixed[fixed_idx].tgt.global_id != curr_tgt),
1011 "ERROR(redist_weight_file_data): inconsistent data in weight file;"
1012 "link and fixed data available for a target point")
1013 if ((link_idx < recv_link_count) &&
1014 (recv_links[link_idx].tgt.global_id == curr_tgt)) {
1015
1016 size_t temp_link_idx = link_idx;
1017 while ((temp_link_idx < recv_link_count) &&
1018 (recv_links[temp_link_idx].tgt.global_id == curr_tgt))
1019 ++temp_link_idx;
1020 send_results[tgt_idx].type = LINK;
1021 send_results[tgt_idx].data.link.links = recv_links + link_idx;
1022 send_results[tgt_idx].data.link.count = temp_link_idx - link_idx;
1023
1024 } else if ((fixed_idx < recv_fixed_count) &&
1025 (recv_fixed[fixed_idx].tgt.global_id == curr_tgt)) {
1026
1027 send_results[tgt_idx].type = FIXED;
1028 send_results[tgt_idx].data.fixed.value = recv_fixed[fixed_idx].value;
1029
1030 } else {
1031 send_results[tgt_idx].type = NO_INTERP;
1032 }
1033 }
1034 free(recv_fixed);
1035
1036 // sort received target point inforatiom into origional receive order
1037 qsort(
1038 send_results, recv_tgt_count, sizeof(*send_results),
1040
1041 int * pack_size_buffer =
1042 xmalloc((recv_tgt_count + tgt_count) * sizeof(*pack_size_buffer));
1043 int * send_pack_sizes = pack_size_buffer;
1044 int * recv_pack_sizes = pack_size_buffer + recv_tgt_count;
1045 for (size_t i = 0; i < recv_tgt_count; ++i)
1046 send_pack_sizes[i] = get_temp_result_pack_size(send_results + i, comm);
1047
1048 saccu = 0, raccu = 0;
1049 for (int i = 0; i < comm_size; ++i) {
1050 sdispls[i] = saccu;
1051 rdispls[i] = raccu;
1052 int sendcount = recvcounts[3*i];
1053 int recvcount = sendcounts[3*i];
1054 saccu += (sendcounts[i] = sendcount);
1055 raccu += (recvcounts[i] = recvcount);
1056 }
1057
1058 yac_alltoallv_int_p2p(
1059 send_pack_sizes, sendcounts, sdispls,
1060 recv_pack_sizes, recvcounts, rdispls, comm);
1061
1062 saccu = 0, raccu = 0;
1063 for (int i = 0, k = 0, l = 0; i < comm_size; ++i) {
1064 size_t sendcount = sendcounts[i];
1065 size_t recvcount = recvcounts[i];
1066 sendcounts[i] = 0;
1067 recvcounts[i] = 0;
1068 for (size_t j = 0; j < sendcount; ++j, ++k)
1069 sendcounts[i] += send_pack_sizes[k];
1070 for (size_t j = 0; j < recvcount; ++j, ++l)
1071 recvcounts[i] += recv_pack_sizes[l];
1072 sdispls[i] = saccu;
1073 rdispls[i] = raccu;
1074 saccu += sendcounts[i];
1075 raccu += recvcounts[i];
1076 }
1077 size_t total_send_pack_size =
1078 sdispls[comm_size-1] + sendcounts[comm_size-1];
1079 size_t total_recv_pack_size =
1080 rdispls[comm_size-1] + recvcounts[comm_size-1];
1081
1082 pack_buffer =
1083 xrealloc(pack_buffer, total_send_pack_size + total_recv_pack_size);
1084 send_pack_buffer = pack_buffer;
1085 recv_pack_buffer =
1086 (void*)((unsigned char*)pack_buffer + total_send_pack_size);
1087
1088 for (size_t i = 0, offset = 0; i < recv_tgt_count; ++i) {
1090 send_results + i, (void*)((unsigned char*)send_pack_buffer + offset),
1091 send_pack_sizes[i], comm);
1092 offset += (size_t)(send_pack_sizes[i]);
1093 }
1094
1095 // redistribute link and fixed data to processes requiring this data for
1096 // their local target points
1098 send_pack_buffer, sendcounts, sdispls,
1099 recv_pack_buffer, recvcounts, rdispls,
1100 1, MPI_PACKED, comm);
1101
1102 // unpack results
1103 for (size_t i = 0, offset = 0; i < tgt_count; ++i) {
1105 (void*)((unsigned char*)recv_pack_buffer + offset),
1106 recv_pack_sizes[i], recv_results + i, comm);
1107 offset += (size_t)(recv_pack_sizes[i]);
1108 }
1109 free(pack_size_buffer);
1110
1111 // sort received results by global target id
1112 qsort(
1113 recv_results, tgt_count, sizeof(*recv_results),
1115
1116 for (size_t i = 0; i < tgt_count; ++i)
1117 recv_results[i].tgt.local_id = tgt_points[i];
1118
1119 // sort received results by type
1120 qsort(
1121 recv_results, tgt_count, sizeof(*recv_results),
1123
1124 size_t new_num_links = 0;
1125 size_t new_total_num_links = 0;
1126 size_t new_num_fixed = 0;
1127 {
1128 size_t i = 0;
1129 while ((i < tgt_count) && (recv_results[i].type == LINK))
1130 new_total_num_links += recv_results[i++].data.link.count;
1131 new_num_links = i;
1132 while ((i < tgt_count) && (recv_results[i].type == FIXED)) ++i;
1133 new_num_fixed = i - new_num_links;
1134 }
1135
1136 // extract links from results
1137 *links = xrealloc(recv_links, new_total_num_links * sizeof(**links));
1138 for (size_t i = 0, offset = 0; i < new_num_links;
1139 offset += recv_results[i++].data.link.count)
1140 memcpy(*links + offset, recv_results[i].data.link.links,
1141 recv_results[i].data.link.count * sizeof(**links));
1142 *num_links = new_total_num_links;
1143
1144 // extract fixed data from results
1145 if (new_num_fixed > 0) {
1146 recv_results += new_num_links;
1147 qsort(
1148 recv_results, new_num_fixed, sizeof(*recv_results),
1150 double curr_fixed_value =
1151 (recv_results[0].data.fixed.value == 1337.0)?(-1337.0):(1337.0);
1152 size_t num_fixed_values = 0;
1153 void * tgt_global_id_buffer =
1154 xrealloc((*num_fixed > 0)?(*fixed)->tgt:NULL,
1155 new_num_fixed * sizeof(*((*fixed)->tgt)));
1156 struct fixed_data * curr_fixed = NULL;
1157 for (size_t i = 0, offset = 0; i < new_num_fixed; ++i) {
1158 if (recv_results[i].data.fixed.value != curr_fixed_value) {
1159 curr_fixed_value = recv_results[i].data.fixed.value;
1160 *fixed = xrealloc(*fixed, (num_fixed_values + 1) * sizeof(**fixed));
1161 curr_fixed = *fixed + num_fixed_values;
1162 ++num_fixed_values;
1163 curr_fixed->value = curr_fixed_value;
1164 curr_fixed->tgt = (void*)(((unsigned char *)tgt_global_id_buffer) +
1165 offset * sizeof(*((*fixed)->tgt)));
1166 curr_fixed->num_tgt = 0;
1167 }
1168 curr_fixed->tgt[curr_fixed->num_tgt++].global_id =
1169 recv_results[i].tgt.global_id;
1170 }
1171 *num_fixed = num_fixed_values;
1172 recv_results -= new_num_links;
1173
1174 } else {
1175 if (*num_fixed > 0) free((*fixed)->tgt);
1176 free(*fixed);
1177 *fixed = NULL;
1178 *num_fixed = 0;
1179 }
1180
1181 for (size_t i = 0; i < tgt_count; ++i)
1182 tgt_points[i] = recv_results[i].tgt.local_id;
1183 *num_interpolated_points = new_num_links + new_num_fixed;
1184
1185 for (size_t i = 0; i < new_num_links; ++i)
1186 free(recv_results[i].data.link.links);
1187 free(result_buffer);
1188 free(pack_buffer);
1189 yac_free_comm_buffers(sendcounts, recvcounts, sdispls, rdispls);
1190 free(size_t_buffer);
1191 free(tgt_global_ids);
1192}
1193
1194static int compare_link_data_field_idx_src(void const *a, void const *b) {
1195
1196 struct link_data const * link_a = (struct link_data*)a;
1197 struct link_data const * link_b = (struct link_data*)b;
1198
1199 int ret = (link_a->src_field_idx > link_b->src_field_idx) -
1200 (link_a->src_field_idx < link_b->src_field_idx);
1201
1202 if (ret) return ret;
1203
1204 else return (link_a->src.global_id > link_b->src.global_id) -
1205 (link_a->src.global_id < link_b->src.global_id);
1206}
1207
1208// sort links by tgt local id and src ids (SIZE_MAX first; remaining by ascending src ids)
1209static int compare_link_data_tgt_src_mask(void const *a, void const *b) {
1210
1211 struct link_data const * link_a = (struct link_data*)a;
1212 struct link_data const * link_b = (struct link_data*)b;
1213
1214 int ret = (link_a->tgt.local_id > link_b->tgt.local_id) -
1215 (link_a->tgt.local_id < link_b->tgt.local_id);
1216
1217 if (ret) return ret;
1218
1219 if (link_a->src.local_id == SIZE_MAX) return -1;
1220 if (link_b->src.local_id == SIZE_MAX) return 1;
1221
1222 return (link_a->src.local_id > link_b->src.local_id) -
1223 (link_a->src.local_id < link_b->src.local_id);
1224}
1225
1226// sort links by tgt local id, source field index, and src local id
1227static int compare_link_data_tgt_src_field_src_id(void const *a, void const *b) {
1228
1229 struct link_data const * link_a = (struct link_data*)a;
1230 struct link_data const * link_b = (struct link_data*)b;
1231
1232 int ret = (link_a->tgt.local_id > link_b->tgt.local_id) -
1233 (link_a->tgt.local_id < link_b->tgt.local_id);
1234
1235 if (ret) return ret;
1236
1237 ret = (link_a->src_field_idx > link_b->src_field_idx) -
1238 (link_a->src_field_idx < link_b->src_field_idx);
1239
1240 if (ret) return ret;
1241
1242 if (link_a->src.local_id == SIZE_MAX) return -1;
1243 if (link_b->src.local_id == SIZE_MAX) return 1;
1244
1245 return (link_a->src.local_id > link_b->src.local_id) -
1246 (link_a->src.local_id < link_b->src.local_id);
1247}
1248
1249
1250static size_t do_search_file(struct interp_method * method,
1251 struct yac_interp_grid * interp_grid,
1252 size_t * tgt_points, size_t count,
1253 struct yac_interp_weights * weights) {
1254
1255 struct interp_method_file * method_file =
1256 (struct interp_method_file*)(method);
1257
1258 MPI_Comm comm = yac_interp_grid_get_MPI_Comm(interp_grid);
1259
1260 size_t num_src_fields = yac_interp_grid_get_num_src_fields(interp_grid);
1261 enum yac_location * src_locations =
1262 xmalloc(num_src_fields * sizeof(*src_locations));
1263 for (size_t i = 0; i < num_src_fields; ++i)
1264 src_locations[i] = yac_interp_grid_get_src_field_location(interp_grid, i);
1265 enum yac_location tgt_location =
1267
1268 struct link_data * links;
1269 size_t num_links;
1270 struct fixed_data * fixed;
1271 size_t num_fixed;
1272
1273 // read data from file
1275 method_file->weight_file_name, comm,
1276 method_file->src_grid_name, method_file->tgt_grid_name,
1277 src_locations, tgt_location, num_src_fields,
1278 &links, &num_links, &fixed, &num_fixed);
1279
1280 free(src_locations);
1281
1282 // relocates links and fixed to the processes, which require them to
1283 // interpolate their local target points
1284 // (the tgt_points first contain the link-tgt_points, then the fixed-tgt_points,
1285 // and followed the non-interpolated tgt_points)
1286 size_t num_interpolated_points;
1288 interp_grid, tgt_points, count, &num_interpolated_points,
1289 &links, &num_links, &fixed, &num_fixed);
1290
1291 size_t * tgt_points_reorder_idx =
1292 xmalloc(num_interpolated_points * sizeof(*tgt_points_reorder_idx));
1293 for (size_t i = 0; i < num_interpolated_points; ++i)
1294 tgt_points_reorder_idx[i] = i;
1295
1296 size_t num_fixed_tgt = 0;
1297 if (num_fixed) {
1298 for (size_t i = 0; i < num_fixed; ++i) num_fixed_tgt += fixed[i].num_tgt;
1299
1300 size_t tgt_points_offset = num_interpolated_points - num_fixed_tgt;
1301
1302 for (size_t i = 0; i < num_fixed; ++i) {
1303
1304 struct remote_points tgts = {
1305 .data =
1307 interp_grid, tgt_points + tgt_points_offset, fixed[i].num_tgt),
1308 .count = fixed[i].num_tgt};
1309
1310 yac_interp_weights_add_fixed(weights, &tgts, fixed[i].value);
1311 free(tgts.data);
1312 tgt_points_offset += fixed[i].num_tgt;
1313 }
1314 free(fixed->tgt);
1315 }
1316 free(fixed);
1317
1318 size_t num_link_tgt = 0;
1319 if (num_links > 0) {
1320
1321 // set local target ids for all links
1322 for (size_t link_idx = 0, tgt_idx = 0; link_idx < num_links; tgt_idx++) {
1323
1324 yac_int curr_global_id = links[link_idx].tgt.global_id;
1325 size_t curr_local_id = tgt_points[tgt_idx];
1326
1327 while ((link_idx < num_links) &&
1328 (links[link_idx].tgt.global_id == curr_global_id)) {
1329 links[link_idx].tgt.local_id = curr_local_id;
1330 link_idx++;
1331 }
1332 }
1333
1334 // sort links by field idx and src id
1335 qsort(links, num_links, sizeof(*links), compare_link_data_field_idx_src);
1336
1337 // determine number of source fields
1338 size_t num_src_fields = links[num_links-1].src_field_idx + 1;
1339
1340 {
1341 int int_num_src_fields = (int)num_src_fields;
1342 MPI_Comm comm = yac_interp_grid_get_MPI_Comm(interp_grid);
1344 MPI_Allreduce(MPI_IN_PLACE, &int_num_src_fields, 1, MPI_INT, MPI_MAX,
1345 comm), comm);
1346 num_src_fields = (size_t)int_num_src_fields;
1347 }
1348
1349 yac_int * src_global_ids = xmalloc(num_links * sizeof(*src_global_ids));
1350 size_t * src_local_ids = xmalloc(num_links * sizeof(*src_local_ids));
1351 size_t src_field_prefix_sum[num_src_fields];
1352
1353 // check the mask of the source points and get the local ids for the
1354 // remaining ones
1355 for (size_t src_field_idx = 0, link_idx = 0, offset = 0;
1356 src_field_idx < num_src_fields; ++src_field_idx) {
1357
1358 size_t curr_num_links = 0;
1359 while ((link_idx < num_links) &&
1360 (links[link_idx].src_field_idx == src_field_idx)) {
1361
1362 // get global source ids
1363 src_global_ids[offset + curr_num_links] =
1364 links[link_idx].src.global_id;
1365 ++curr_num_links;
1366 ++link_idx;
1367 }
1368
1369 // get local ids for all source points
1371 interp_grid, src_field_idx, src_global_ids + offset, curr_num_links,
1372 src_local_ids + offset);
1373
1374 // get the mask after the call to yac_interp_grid_src_global_to_local
1375 const_int_pointer src_mask =
1376 yac_interp_grid_get_src_field_mask(interp_grid, src_field_idx);
1377
1378 // check source masks and mask src ids of marked links with SIZE_MAX
1379 link_idx -= curr_num_links;
1380 if (src_mask != NULL) {
1381 for (size_t i = 0; i < curr_num_links; ++i, ++link_idx)
1382 links[link_idx].src.local_id =
1383 (src_mask[src_local_ids[link_idx]])?
1384 src_local_ids[link_idx]:SIZE_MAX;
1385 } else {
1386 for (size_t i = 0; i < curr_num_links; ++i, ++link_idx)
1387 links[link_idx].src.local_id = src_local_ids[link_idx];
1388 }
1389
1390 src_field_prefix_sum[src_field_idx] = offset;
1391 offset += curr_num_links;
1392 }
1393
1394 // sort links by tgt local id and src ids (SIZE_MAX first; remaining by ascending src ids)
1395 qsort(links, num_links, sizeof(*links), compare_link_data_tgt_src_mask);
1396
1397 // pack links (remove links with targets that have at least one masked source point)
1398 size_t new_num_links = 0;
1399 int contains_masked_tgt = 0;
1400 num_link_tgt = num_interpolated_points - num_fixed_tgt;
1401 size_t * tgt_local_ids = xmalloc(num_link_tgt * sizeof(*tgt_local_ids));
1402 size_t * num_src_per_field_per_tgt =
1403 xcalloc(num_link_tgt * num_src_fields, sizeof(*num_src_per_field_per_tgt));
1404 size_t num_links_per_src_field[num_src_fields];
1405 memset(num_links_per_src_field, 0, sizeof(num_links_per_src_field));
1406 num_link_tgt = 0;
1407 for (size_t link_idx = 0, tgt_idx = 0; link_idx < num_links; ++tgt_idx) {
1408
1409 size_t curr_tgt_local_id = links[link_idx].tgt.local_id;
1410 int is_masked = links[link_idx].src.local_id == SIZE_MAX;
1411 tgt_points[tgt_idx] = curr_tgt_local_id;
1412
1413 // if the current target point has a masked source point
1414 if (is_masked) {
1415
1416 while ((link_idx < num_links) &&
1417 (links[link_idx].tgt.local_id == curr_tgt_local_id)) ++link_idx;
1418 contains_masked_tgt = 1;
1419 tgt_points_reorder_idx[tgt_idx] += num_interpolated_points;
1420
1421 // if there already have been target points with masked source points
1422 } else {
1423 size_t * curr_num_src_per_field_per_tgt =
1424 num_src_per_field_per_tgt + num_link_tgt * num_src_fields;
1425 if (contains_masked_tgt) {
1426 while ((link_idx < num_links) &&
1427 (links[link_idx].tgt.local_id == curr_tgt_local_id)) {
1428 size_t curr_src_field_idx = links[link_idx].src_field_idx;
1429 src_local_ids[
1430 src_field_prefix_sum[curr_src_field_idx] +
1431 num_links_per_src_field[curr_src_field_idx] +
1432 curr_num_src_per_field_per_tgt[curr_src_field_idx]++] =
1433 links[link_idx].src.local_id;
1434 links[new_num_links++] = links[link_idx++];
1435 }
1436 } else {
1437
1438 while ((link_idx < num_links) &&
1439 (links[link_idx].tgt.local_id == curr_tgt_local_id)) {
1440 size_t curr_src_field_idx = links[link_idx].src_field_idx;
1441 src_local_ids[
1442 src_field_prefix_sum[curr_src_field_idx] +
1443 num_links_per_src_field[curr_src_field_idx] +
1444 curr_num_src_per_field_per_tgt[curr_src_field_idx]++] =
1445 links[link_idx].src.local_id;
1446 ++link_idx, ++new_num_links;
1447 }
1448 }
1449 for (size_t i = 0; i < num_src_fields; ++i) {
1450 num_links_per_src_field[i] += curr_num_src_per_field_per_tgt[i];
1451 }
1452 tgt_local_ids[num_link_tgt++] = curr_tgt_local_id;
1453 }
1454 }
1455 num_links = new_num_links;
1456 tgt_local_ids =
1457 xrealloc(tgt_local_ids, num_link_tgt * sizeof(*tgt_local_ids));
1458 num_src_per_field_per_tgt =
1459 xrealloc(
1460 num_src_per_field_per_tgt,
1461 num_link_tgt * num_src_fields * sizeof(*num_src_per_field_per_tgt));
1462
1463 // get the remote points for all required source points
1464 struct remote_point * srcs_per_field[num_src_fields];
1465 for (size_t src_field_idx = 0; src_field_idx < num_src_fields; ++src_field_idx)
1466 srcs_per_field[src_field_idx] =
1468 interp_grid, src_field_idx, src_local_ids + src_field_prefix_sum[src_field_idx],
1469 num_links_per_src_field[src_field_idx]);
1470 free(src_local_ids);
1471
1472 // sort links by tgt local id, source field index, and src local id
1473 qsort(links, num_links, sizeof(*links), compare_link_data_tgt_src_field_src_id);
1474
1475 // gather weights
1476 double * w = xmalloc(num_links * sizeof(*w));
1477 for (size_t link_idx = 0; link_idx < num_links; ++link_idx)
1478 w[link_idx] = links[link_idx].weight;
1479
1480 struct remote_points tgts = {
1481 .data =
1483 interp_grid, tgt_local_ids, num_link_tgt),
1484 .count = num_link_tgt};
1485 free(tgt_local_ids);
1486
1488 weights, &tgts, num_src_per_field_per_tgt, srcs_per_field, w, num_src_fields);
1489
1490 free(tgts.data);
1491 for (size_t i = 0; i < num_src_fields; ++i) free(srcs_per_field[i]);
1492 free(num_src_per_field_per_tgt);
1493 free(w);
1494 free(src_global_ids);
1495
1496 } else {
1497 int num_src_fields = 0;
1498 MPI_Comm comm = yac_interp_grid_get_MPI_Comm(interp_grid);
1500 MPI_Allreduce(MPI_IN_PLACE, &num_src_fields, 1, MPI_INT, MPI_MAX,
1501 comm), comm);
1502 // get local ids for all source points
1503 // (since this routine is collective for all processes, we have to call
1504 // this here if the local process received no links)
1505 for (int i = 0; i < num_src_fields; ++i)
1506 yac_interp_grid_src_global_to_local(interp_grid, 0, NULL, 0, NULL);
1507 }
1508 free(links);
1509
1511 tgt_points_reorder_idx, num_interpolated_points, tgt_points);
1512 free(tgt_points_reorder_idx);
1513
1514 return num_fixed_tgt + num_link_tgt;
1515}
1516
1518 char const * weight_file_name,
1519 char const * src_grid_name, char const * tgt_grid_name) {
1520
1521 struct interp_method_file * method = xmalloc(1 * sizeof(*method));
1522
1524 method->weight_file_name = xmalloc(strlen(weight_file_name) + 1);
1525 strcpy((char*)(method->weight_file_name), weight_file_name);
1526 method->src_grid_name = xmalloc(strlen(src_grid_name) + 1);
1527 strcpy((char*)(method->src_grid_name), src_grid_name);
1528 method->tgt_grid_name = xmalloc(strlen(tgt_grid_name) + 1);
1529 strcpy((char*)(method->tgt_grid_name), tgt_grid_name);
1530
1531
1532 return (struct interp_method*)method;
1533}
1534
1535static void delete_file(struct interp_method * method) {
1536
1537 struct interp_method_file * method_file =
1538 (struct interp_method_file *)method;
1539 free((void*)(method_file->weight_file_name));
1540 free((void*)(method_file->src_grid_name));
1541 free((void*)(method_file->tgt_grid_name));
1542 free(method_file);
1543}
#define UNUSED(x)
Definition core.h:71
int const *const const_int_pointer
enum yac_location yac_interp_grid_get_tgt_field_location(struct yac_interp_grid *interp_grid)
size_t yac_interp_grid_get_num_src_fields(struct yac_interp_grid *interp_grid)
const_int_pointer yac_interp_grid_get_src_field_mask(struct yac_interp_grid *interp_grid, size_t src_field_idx)
void yac_interp_grid_get_tgt_global_ids(struct yac_interp_grid *interp_grid, size_t *tgt_points, size_t count, yac_int *tgt_global_ids)
MPI_Comm yac_interp_grid_get_MPI_Comm(struct yac_interp_grid *interp_grid)
struct remote_point * yac_interp_grid_get_tgt_remote_points(struct yac_interp_grid *interp_grid, size_t *tgt_points, size_t count)
enum yac_location yac_interp_grid_get_src_field_location(struct yac_interp_grid *interp_grid, size_t src_field_idx)
struct remote_point * yac_interp_grid_get_src_remote_points(struct yac_interp_grid *interp_grid, size_t src_field_idx, size_t *src_points, size_t count)
void yac_interp_grid_src_global_to_local(struct yac_interp_grid *interp_grid, size_t src_field_idx, yac_int *src_global_ids, size_t count, size_t *src_local_ids)
struct @8::@9 value
enum callback_type type
static int compare_temp_result_fixed(void const *a, void const *b)
static int compare_link_data_tgt(void const *a, void const *b)
static int compare_link_data_tgt_src_mask(void const *a, void const *b)
static int compare_link_data_field_idx_src(void const *a, void const *b)
static int get_fixed_pack_size(MPI_Comm comm)
static int compute_bucket(yac_int value, int comm_size)
static int compare_temp_result_tgt(void const *a, void const *b)
static int get_link_pack_size(MPI_Comm comm)
static void pack_tgt(yac_int global_tgt_id, void *buffer, int buffer_size, MPI_Comm comm)
static void pack_temp_result(struct temp_result *result, void *buffer, int buffer_size, MPI_Comm comm)
static void redist_weight_file_data(struct yac_interp_grid *interp_grid, size_t *tgt_points, size_t tgt_count, size_t *num_interpolated_points, struct link_data **links, size_t *num_links, struct fixed_data **fixed, size_t *num_fixed)
static void unpack_temp_result(void *buffer, int buffer_size, struct temp_result *result, MPI_Comm comm)
static void unpack_fixed(void *buffer, int buffer_size, struct temp_fixed_data *fixed, MPI_Comm comm)
static void pack_link(struct link_data *link, void *buffer, int buffer_size, MPI_Comm comm)
static int compare_temp_result_reorder_idx(void const *a, void const *b)
static void pack_fixed(double fixed_value, yac_int global_tgt_id, void *buffer, int buffer_size, MPI_Comm comm)
static size_t do_search_file(struct interp_method *method, struct yac_interp_grid *interp_grid, size_t *tgt_points, size_t count, struct yac_interp_weights *weights)
static struct interp_method_vtable interp_method_file_vtable
static void unpack_link(void *buffer, int buffer_size, struct link_data *link, MPI_Comm comm)
static int get_temp_result_pack_size(struct temp_result *result, MPI_Comm comm)
static int compare_temp_result_type(void const *a, void const *b)
static void delete_file(struct interp_method *method)
static int compare_temp_fixed_data_tgt(void const *a, void const *b)
static int get_tgt_pack_size(MPI_Comm comm)
static void unpack_tgt(void *buffer, int buffer_size, yac_int *global_tgt_id, MPI_Comm comm)
struct interp_method * yac_interp_method_file_new(char const *weight_file_name, char const *src_grid_name, char const *tgt_grid_name)
static void read_weight_file(char const *weight_file_name, MPI_Comm comm, char const *src_grid_name, char const *tgt_grid_name, enum yac_location *src_locations, enum yac_location tgt_location, size_t num_src_fields, struct link_data **links, size_t *num_links, struct fixed_data **fixed, size_t *num_fixed)
static int compare_link_data_tgt_src_field_src_id(void const *a, void const *b)
#define YAC_WEIGHT_FILE_VERSION_STRING
void yac_interp_weights_add_fixed(struct yac_interp_weights *weights, struct remote_points *tgts, double fixed_value)
@ FIXED
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)
void yac_get_io_ranks(MPI_Comm comm, int *local_is_io_, int **io_ranks_, int *num_io_ranks_)
Definition io_utils.c:303
void yac_nc_inq_varid(int ncid, char const *name, int *varidp)
Definition io_utils.c:403
void yac_nc_open(const char *path, int omode, int *ncidp)
Definition io_utils.c:344
void yac_nc_inq_dimid(int ncid, char const *name, int *dimidp)
Definition io_utils.c:379
#define YAC_HANDLE_ERROR(exp)
Definition io_utils.h:30
enum yac_location yac_str2loc(char const *location_str)
Definition location.c:21
char const * yac_loc2str(enum yac_location location)
Definition location.c:32
yac_location
Definition location.h:12
#define YAC_MAX_LOC_STR_LEN
Definition location.h:10
Definition __init__.py:1
#define xrealloc(ptr, size)
Definition ppm_xfuncs.h:67
#define xcalloc(nmemb, size)
Definition ppm_xfuncs.h:64
#define xmalloc(size)
Definition ppm_xfuncs.h:66
struct fixed_data::@13 * tgt
char const * weight_file_name
struct interp_method_vtable * vtable
size_t(* do_search)(struct interp_method *method, struct yac_interp_grid *grid, size_t *tgt_points, size_t count, struct yac_interp_weights *weights)
struct remote_point * data
struct temp_fixed_data::@14 tgt
union temp_result::@16 data
struct temp_result::@16::@19 fixed
enum temp_result::@15 type
struct temp_result::@16::@18 link
struct temp_result::@17 tgt
struct link_data * links
#define MIN(a, b)
void yac_quicksort_index_yac_int_size_t(yac_int *a, size_t n, size_t *idx)
void yac_quicksort_index_size_t_size_t(size_t *a, size_t n, size_t *idx)
#define YAC_ASSERT_F(exp, format,...)
Definition yac_assert.h:18
#define die(msg)
Definition yac_assert.h:12
#define YAC_ASSERT(exp, msg)
Definition yac_assert.h:15
void yac_free_comm_buffers(size_t *sendcounts, size_t *recvcounts, size_t *sdispls, size_t *rdispls)
Definition yac_mpi.c:624
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:593
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)
Definition yac_mpi.c:129
#define yac_mpi_call(call, comm)
#define YAC_MPI_SIZE_T
Xt_int yac_int
Definition yac_types.h:15
#define yac_int_dt
Definition yac_types.h:16