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