YAC 3.7.0
Yet Another Coupler
Loading...
Searching...
No Matches
interp_method_spmap.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#ifdef HAVE_CONFIG_H
6// Get the definition of the 'restrict' keyword.
7#include "config.h"
8#endif
9
10#include <float.h>
11#include <string.h>
12
14#include "interp_method_spmap.h"
15#include "ensure_array_size.h"
16#include "area.h"
17#include "io_utils.h"
18#include "yac_mpi_internal.h"
19
20static size_t do_search_spmap(struct interp_method * method,
21 struct yac_interp_grid * interp_grid,
22 size_t * tgt_points, size_t count,
23 struct yac_interp_weights * weights,
24 int * interpolation_complete);
25static void delete_spmap(struct interp_method * method);
26
27static struct interp_method_vtable
32
41
42static inline int compare_size_t(const void * a, const void * b) {
43
44 size_t const * a_ = a, * b_ = b;
45
46 return (*a_ > *b_) - (*b_ > *a_);
47}
48
49static int lists_overlap(
50 size_t * list_a, size_t count_a, size_t * list_b, size_t count_b) {
51
52 if ((count_a == 0) || (count_b == 0)) return 0;
53
54 size_t i = 0, j = 0;
55 size_t curr_a = SIZE_MAX, curr_b = list_b[0];
56
57 do {
58 while ((i < count_a) && (((curr_a = list_a[i++])) < curr_b));
59 if (curr_a == curr_b) return 1;
60 while ((j < count_b) && (((curr_b = list_b[j++])) < curr_a));
61 if (curr_a == curr_b) return 1;
62 } while ((i < count_a) || (j < count_b));
63
64 return 0;
65}
66
67static void merge_lists(
68 size_t * list, size_t * list_size, size_t * insert, size_t insert_size) {
69
70 if (insert_size == 0) return;
71
72 size_t new_list_size = *list_size;
73 size_t old_list_size = *list_size;
74
75 for (size_t i = 0, j = 0; i < insert_size; ++i) {
76 size_t curr_insert = insert[i];
77 while ((j < old_list_size) && (list[j] < curr_insert)) ++j;
78 if ((j >= old_list_size) || (list[j] != curr_insert))
79 list[new_list_size++] = curr_insert;
80 }
81
82 if (new_list_size != old_list_size) {
83 qsort(list, new_list_size, sizeof(*list), compare_size_t);
84 *list_size = new_list_size;
85 }
86}
87
89 yac_const_coordinate_pointer tgt_field_coords, double max_distance,
90 size_t tgt_start_point, size_t * tgt_points, size_t * count) {
91
92 double const * start_coord = tgt_field_coords[tgt_start_point];
93 size_t new_count = 0;
94 for (size_t i = 0, old_count = *count; i < old_count; ++i) {
96 start_coord, tgt_field_coords[tgt_points[i]]) <= max_distance) {
97 if (new_count != i) tgt_points[new_count] = tgt_points[i];
98 ++new_count;
99 }
100 }
101
102 *count = new_count;
103}
104
106 struct yac_interp_grid * interp_grid, size_t tgt_start_point,
107 size_t * from_tgt_points, size_t * to_tgt_points,
108 size_t * count, int * flag, size_t * temp_cell_edges,
109 size_t ** edges_buffer, size_t * edges_buffer_array_size) {
110
111 struct yac_const_basic_grid_data * tgt_grid_data =
115 tgt_grid_data->cell_to_edge_offsets;
116 const int * num_vertices_per_cell =
117 tgt_grid_data->num_vertices_per_cell;
118
119 size_t old_count = *count;
120 memset(flag, 0, old_count * sizeof(*flag));
121
122 for (size_t i = 0; i < old_count; ++i) {
123 if (from_tgt_points[i] == tgt_start_point) {
124 flag[i] = 1;
125 break;
126 }
127 }
128
129 size_t * edges = *edges_buffer;
130 size_t num_edges = 0;
131 size_t edges_array_size = *edges_buffer_array_size;
132
133 const_size_t_pointer curr_edges =
134 cell_to_edge + cell_to_edge_offsets[tgt_start_point];
135 size_t curr_num_edges = num_vertices_per_cell[tgt_start_point];
136
137 ENSURE_ARRAY_SIZE(edges, edges_array_size, curr_num_edges);
138 num_edges = curr_num_edges;
139 memcpy(edges, curr_edges, num_edges * sizeof(*edges));
140 qsort(edges, num_edges, sizeof(*edges), compare_size_t);
141
142 int change_flag = 0;
143 do {
144
145 change_flag = 0;
146
147 for (size_t i = 0; i < old_count; ++i) {
148
149 if (flag[i]) continue;
150
151 const_size_t_pointer curr_edges =
152 tgt_grid_data->cell_to_edge + cell_to_edge_offsets[from_tgt_points[i]];
153 curr_num_edges = num_vertices_per_cell[from_tgt_points[i]];
154 memcpy(
155 temp_cell_edges, curr_edges, curr_num_edges * sizeof(*temp_cell_edges));
156 qsort(temp_cell_edges, curr_num_edges, sizeof(*edges), compare_size_t);
157 ENSURE_ARRAY_SIZE(edges, edges_array_size, num_edges + curr_num_edges);
158
159 if (lists_overlap(edges, num_edges, temp_cell_edges, curr_num_edges)) {
160 merge_lists(edges, &num_edges, temp_cell_edges, curr_num_edges);
161 flag[i] = 1;
162 change_flag = 1;
163 }
164 }
165 } while (change_flag);
166
167 *edges_buffer = edges;
168 *edges_buffer_array_size = edges_array_size;
169
170 size_t new_count = 0;
171 for (size_t i = 0; i < old_count; ++i)
172 if (flag[i]) to_tgt_points[new_count++] = from_tgt_points[i];
173
174 *count = new_count;
175}
176
178 struct yac_interp_grid * interp_grid, double spread_distance,
179 size_t num_src_points, size_t const * const tgt_result_points,
180 size_t * num_tgt_per_src, size_t * spread_tgt_result_points) {
181
182 size_t max_num_tgt_per_src = 0;
183 for (size_t i = 0; i < num_src_points; ++i)
184 if (num_tgt_per_src[i] > max_num_tgt_per_src)
185 max_num_tgt_per_src = num_tgt_per_src[i];
186
187 int * flag = xmalloc(max_num_tgt_per_src * sizeof(*flag));
188
189 size_t new_offset = 0;
190 size_t * cell_edge_buffer = NULL;
191 size_t cell_edge_buffer_array_size = 0;
192 size_t * edge_buffer = NULL;
193 size_t edge_buffer_array_size = 0;
194 int max_num_vertice_per_tgt = 0;
195 const int * num_vertices_per_tgt =
198
199 yac_const_coordinate_pointer tgt_field_coords =
201
202 // for all source points
203 for (size_t i = 0, old_offset = 0; i < num_src_points; ++i) {
204
205 size_t * old_results = spread_tgt_result_points + old_offset;
206 size_t * new_results = spread_tgt_result_points + new_offset;
207 old_offset += num_tgt_per_src[i];
208
209 // remove all target points, which exceed the spread distance from
210 // the original tgt
212 tgt_field_coords, spread_distance, tgt_result_points[i],
213 old_results, num_tgt_per_src + i);
214
215 // check buffer sizes required by routine remove_disconnected_points
216 for (size_t j = 0, curr_num_tgt_per_src = num_tgt_per_src[i];
217 j < curr_num_tgt_per_src; ++j)
218 if (num_vertices_per_tgt[old_results[j]] > max_num_vertice_per_tgt)
219 max_num_vertice_per_tgt = num_vertices_per_tgt[old_results[j]];
220
222 cell_edge_buffer, cell_edge_buffer_array_size,
223 max_num_vertice_per_tgt);
224
225 // remove all tgts that are not directly connected to the original tgt
227 interp_grid, tgt_result_points[i],
228 old_results, new_results, num_tgt_per_src + i, flag,
229 cell_edge_buffer, &edge_buffer, &edge_buffer_array_size);
230
231 new_offset += num_tgt_per_src[i];
232 }
233
234 free(edge_buffer);
235 free(cell_edge_buffer);
236 free(flag);
237
238 return new_offset;
239}
240
241static double * compute_weights(
242 struct yac_interp_grid * interp_grid,
243 enum yac_interp_spmap_weight_type weight_type, size_t num_src_points,
244 size_t const * const src_points, size_t const * const num_tgt_per_src,
245 size_t total_num_tgt, size_t const * const tgt_result_points) {
246
247 double * weights = xmalloc(total_num_tgt * sizeof(*weights));
251 "ERROR(do_search_spmap): invalid weight_type")
252 switch (weight_type) {
253 case (YAC_INTERP_SPMAP_AVG): {
254 for (size_t i = 0, offset = 0; i < num_src_points; ++i) {
255 size_t curr_num_tgt = num_tgt_per_src[i];
256 if (curr_num_tgt == 0) continue;
257 if (curr_num_tgt > 1) {
258 double curr_weight_data = 1.0 / (double)(curr_num_tgt);
259 for (size_t j = 0; j < curr_num_tgt; ++j, ++offset) {
260 weights[offset] = curr_weight_data;
261 }
262 } else {
263 weights[offset] = 1.0;
264 ++offset;
265 }
266 }
267 break;
268 }
269 default:
270 case (YAC_INTERP_SPMAP_DIST): {
271
272 yac_const_coordinate_pointer src_field_coords =
274 yac_const_coordinate_pointer tgt_field_coords =
276
277 for (size_t i = 0, offset = 0; i < num_src_points; ++i) {
278
279 size_t curr_num_tgt = num_tgt_per_src[i];
280
281 if (curr_num_tgt == 0) continue;
282
283 double * curr_weights = weights + offset;
284
285 if (curr_num_tgt > 1) {
286
287 size_t const * const curr_result_points =
288 tgt_result_points + offset;
289 double const * curr_src_coord = src_field_coords[src_points[offset]];
290 offset += curr_num_tgt;
291
292 int match_flag = 0;
293
294 for (size_t j = 0; j < curr_num_tgt; ++j) {
295
296 double distance =
298 (double*)curr_src_coord,
299 (double*)tgt_field_coords[curr_result_points[j]]);
300
301 if (distance < yac_angle_tol) {
302 for (size_t k = 0; k < curr_num_tgt; ++k) curr_weights[k] = 0.0;
303 curr_weights[j] = 1.0;
304 match_flag = 1;
305 break;
306 }
307 curr_weights[j] = 1.0 / distance;
308 }
309
310 if (!match_flag) {
311
312 // compute scaling factor for the weights
313 double inv_distance_sum = 0.0;
314 for (size_t j = 0; j < curr_num_tgt; ++j)
315 inv_distance_sum += curr_weights[j];
316 double scale = 1.0 / inv_distance_sum;
317
318 for (size_t j = 0; j < curr_num_tgt; ++j) curr_weights[j] *= scale;
319 }
320 } else {
321 *curr_weights = 1.0;
322 ++offset;
323 }
324 }
325 break;
326 }
327 };
328
329 return weights;
330}
331
333 struct yac_const_basic_grid_data * basic_grid_data,
334 int * required_cell_areas, double area_scale, char const * type,
335 double * cell_areas) {
336
337 struct yac_grid_cell grid_cell;
338 yac_init_grid_cell(&grid_cell);
339
340 size_t num_cells = basic_grid_data->count[YAC_LOC_CELL];
341
342 for (size_t i = 0; i < num_cells; ++i) {
343 if (required_cell_areas[i]) {
344 yac_const_basic_grid_data_get_grid_cell(basic_grid_data, i, &grid_cell);
345 double cell_area = yac_huiliers_area(grid_cell) * area_scale;
347 cell_area > YAC_AREA_TOL,
348 "ERROR(get_cell_areas): "
349 "area of %s cell (global id %"XT_INT_FMT") is close to zero (%e)",
350 type, basic_grid_data->ids[YAC_LOC_CELL][i], cell_area);
351 cell_areas[i] = cell_area;
352 } else {
353 cell_areas[i] = 0.0;
354 }
355 }
356
357 yac_free_grid_cell(&grid_cell);
358}
359
361 char const * filename, char const * varname, MPI_Comm comm,
362 int * io_ranks, int io_rank_idx, int num_io_ranks,
363 double ** dist_cell_areas, size_t * dist_cell_areas_global_size) {
364
365#ifndef YAC_NETCDF_ENABLED
366
367 UNUSED(filename);
368 UNUSED(varname);
369 UNUSED(comm);
370 UNUSED(io_ranks);
371 UNUSED(io_rank_idx);
372 UNUSED(num_io_ranks);
373
374 *dist_cell_areas = NULL;
375 *dist_cell_areas_global_size = 0;
376
377 die(
378 "ERROR(interp_method_spmap::dist_read_cell_areas): "
379 "YAC is built without the NetCDF support");
380#else
381
382 if ((io_rank_idx >= 0) && (io_rank_idx < num_io_ranks)) {
383
384 // open file
385 int ncid;
386 yac_nc_open(filename, NC_NOWRITE, &ncid);
387
388 // get variable id
389 int varid;
390 yac_nc_inq_varid(ncid, varname, &varid);
391
392 // get dimension ids
393 int ndims;
394 int dimids[NC_MAX_VAR_DIMS];
396 nc_inq_var(ncid, varid, NULL, NULL, &ndims, dimids, NULL));
397
399 (ndims == 1) || (ndims == 2),
400 "ERROR(dist_read_cell_areas): "
401 "invalid number of dimensions for cell area variable \"%s\" from "
402 "file \"%s\" (is %d, but should be either 1 or 2)",
403 varname, filename, ndims);
404
405 // get size of dimensions
406 size_t dimlen[2];
407 *dist_cell_areas_global_size = 1;
408 for (int i = 0; i < ndims; ++i) {
409 YAC_HANDLE_ERROR(nc_inq_dimlen(ncid, dimids[i], &dimlen[i]));
411 dimlen[i] > 0,
412 "ERROR(dist_read_cell_areas): "
413 "invalid dimension size for cell area variable \"%s\" from "
414 "file \"%s\" (is %zu, should by > 0)",
415 varname, filename, dimlen[i]);
416 *dist_cell_areas_global_size *= dimlen[i];
417 }
418
419 // compute start/count
420 // (in 2D case we have to round a little bit and then adjust the
421 // data afterwards)
422 size_t start[2], count[2], offset, read_size;
423 size_t local_start =
424 (size_t)(
425 ((long long)*dist_cell_areas_global_size * (long long)io_rank_idx) /
426 (long long)num_io_ranks);
427 size_t local_count =
428 (size_t)(
429 ((long long)*dist_cell_areas_global_size *
430 (long long)(io_rank_idx+1)) / (long long)num_io_ranks) - local_start;
431 if (ndims == 1) {
432 start[0] = local_start;
433 count[0] = local_count;
434 offset = 0;
435 read_size = local_count;
436 } else {
437 start[0] = local_start / dimlen[1];
438 count[0] =
439 (local_start + local_count + dimlen[1] - 1) / dimlen[1] - start[0];
440 start[1] = 0;
441 count[1] = dimlen[1];
442 offset = local_start - start[0] * dimlen[1];
443 read_size = count[0] * count[1];
444 }
445
446 // read data
447 *dist_cell_areas = xmalloc(read_size * sizeof(**dist_cell_areas));
449 nc_get_vara_double(ncid, varid, start, count, *dist_cell_areas));
450
451 // adjust data if necessary
452 if (ndims == 2)
453 memmove(
454 *dist_cell_areas, *dist_cell_areas + offset,
455 local_count * sizeof(**dist_cell_areas));
456
457 // close file
458 YAC_HANDLE_ERROR(nc_close(ncid));
459
460 } else {
461 *dist_cell_areas = xmalloc(1*sizeof(**dist_cell_areas));
462 *dist_cell_areas_global_size = 0;
463 }
464
466 MPI_Bcast(
467 dist_cell_areas_global_size, 1, YAC_MPI_SIZE_T, io_ranks[0], comm),
468 comm);
469
470#endif // YAC_NETCDF_ENABLED
471}
472
473static void read_cell_areas(
474 struct yac_const_basic_grid_data * basic_grid_data,
475 struct yac_spmap_cell_area_file_config file_config, MPI_Comm comm,
476 int * required_cell_areas, char const * type,
477 double * cell_areas) {
478
479 char const * routine = "read_cell_areas";
480
481 size_t num_cells = basic_grid_data->count[YAC_LOC_CELL];
482
483 // get io configuration
484 int local_is_io, * io_ranks, num_io_ranks;
485 yac_get_io_ranks(comm, &local_is_io, &io_ranks, &num_io_ranks);
486
487 int comm_rank, comm_size;
488 yac_mpi_call(MPI_Comm_rank(comm, &comm_rank), comm);
489 yac_mpi_call(MPI_Comm_size(comm, &comm_size), comm);
490
491 int io_rank_idx = 0;
492 while ((io_rank_idx < num_io_ranks) &&
493 (comm_rank != io_ranks[io_rank_idx]))
494 ++io_rank_idx;
496 !local_is_io || (io_rank_idx < num_io_ranks),
497 "ERROR(%s): unable to determine io_rank_idx", routine);
498
499 double * dist_cell_areas;
500 size_t dist_cell_areas_global_size;
501
502 // read the data on the io processes
504 file_config.filename, file_config.varname, comm,
505 io_ranks, io_rank_idx, num_io_ranks,
506 &dist_cell_areas, &dist_cell_areas_global_size);
507
508 // count the number of locally required cell areas
509 size_t num_required_cell_areas = 0;
510 for (size_t i = 0; i < num_cells; ++i)
511 if (required_cell_areas[i]) ++num_required_cell_areas;
512
513 size_t * global_idx = xmalloc(num_required_cell_areas * sizeof(*global_idx));
514 size_t * reorder_idx =
515 xmalloc(num_required_cell_areas * sizeof(*reorder_idx));
516
517 size_t * sendcounts, * recvcounts, * sdispls, * rdispls;
519 1, &sendcounts, &recvcounts, &sdispls, &rdispls, comm);
520
521 // determine global indices of locally required cell areas
522 yac_int const * global_cell_ids = basic_grid_data->ids[YAC_LOC_CELL];
523 yac_int min_global_id = file_config.min_global_id;
524 for (size_t i = 0, j = 0; i < num_cells; ++i) {
525 if (required_cell_areas[i]) {
527 global_cell_ids[i] >= min_global_id,
528 "ERROR(%s): %s global id %" XT_INT_FMT " is smaller than "
529 "the minimum global id provided by the user (%" XT_INT_FMT ")",
530 routine, type, global_cell_ids[i], min_global_id);
531 size_t idx = (size_t)(global_cell_ids[i] - min_global_id);
533 idx < dist_cell_areas_global_size,
534 "ERROR(%s): %s global id %" XT_INT_FMT " exceeds "
535 "available size of array \"%s\" in file \"%s\" "
536 "(min_global_id %" XT_INT_FMT ")", routine, type, global_cell_ids[i],
537 file_config.varname, file_config.filename, file_config.min_global_id);
538 global_idx[j] = idx;
539 reorder_idx[j] = i;
540 int dist_rank_idx =
541 ((long long)idx * (long long)num_io_ranks +
542 (long long)num_io_ranks - 1) / (long long)dist_cell_areas_global_size;
543 sendcounts[io_ranks[dist_rank_idx]]++;
544 ++j;
545 }
546 }
547 free(io_ranks);
548
550 1, sendcounts, recvcounts, sdispls, rdispls, comm);
551
552 // sort required data by their global index
554 global_idx, num_required_cell_areas, reorder_idx);
555
556 // send required points to io processes
557 size_t request_count = recvcounts[comm_size - 1] + rdispls[comm_size - 1];
558 size_t * request_global_idx =
559 xmalloc(request_count * sizeof(*request_global_idx));
561 global_idx, sendcounts, sdispls+1,
562 request_global_idx, recvcounts, rdispls,
563 sizeof(*global_idx), YAC_MPI_SIZE_T, comm, routine, __LINE__);
564 free(global_idx);
565
566 // pack requested cell areas
567 double * requested_cell_areas =
568 xmalloc(request_count * sizeof(*requested_cell_areas));
569 size_t global_idx_offset =
570 ((long long)io_rank_idx * (long long)dist_cell_areas_global_size) /
571 (long long)num_io_ranks;
572 for (size_t i = 0; i < request_count; ++i)
573 requested_cell_areas[i] =
574 dist_cell_areas[request_global_idx[i] - global_idx_offset];
575 free(request_global_idx);
576 free(dist_cell_areas);
577
578 // return cell areas
579 double * temp_cell_areas =
580 xmalloc(num_required_cell_areas * sizeof(*temp_cell_areas));
582 requested_cell_areas, recvcounts, rdispls,
583 temp_cell_areas, sendcounts, sdispls+1,
584 sizeof(*requested_cell_areas), MPI_DOUBLE, comm, routine, __LINE__);
585 free(requested_cell_areas);
586
587 yac_free_comm_buffers(sendcounts, recvcounts, sdispls, rdispls);
588
589 // unpack cell areas
590 for (size_t i = 0; i < num_required_cell_areas; ++i)
591 cell_areas[reorder_idx[i]] = temp_cell_areas[i];
592
593 free(temp_cell_areas);
594 free(reorder_idx);
595}
596
597static double * get_cell_areas(
598 struct yac_const_basic_grid_data * basic_grid_data,
599 char const * type, struct yac_spmap_cell_area_config cell_area_config,
600 MPI_Comm comm, size_t const * required_points, size_t num_required_points) {
601
602 size_t num_cells = basic_grid_data->count[YAC_LOC_CELL];
603
604 // determine which cell areas are actually required
605 int * required_cell_areas = xcalloc(num_cells, sizeof(*required_cell_areas));
606 for (size_t i = 0; i < num_required_points; ++i)
607 required_cell_areas[required_points[i]] = 1;
608
609 // compute and scale cell areas
610 double * cell_areas = xmalloc(num_cells * sizeof(*cell_areas));
611
613 (cell_area_config.cell_area_provider == YAC_INTERP_SPMAP_CELL_AREA_YAC) ||
614 (cell_area_config.cell_area_provider == YAC_INTERP_SPMAP_CELL_AREA_FILE),
615 "ERROR(get_cell_areas): unsupported %s cell area origin", type);
616
617 switch (cell_area_config.cell_area_provider) {
618
619 default:
621
622 double area_scale =
623 cell_area_config.sphere_radius * cell_area_config.sphere_radius;
625 basic_grid_data, required_cell_areas, area_scale, type,
626 cell_areas);
627 break;
628 }
630
632 basic_grid_data, cell_area_config.file_config, comm,
633 required_cell_areas, type, cell_areas);
634 }
635 };
636
637 free(required_cell_areas);
638
639 return cell_areas;
640}
641
642static void scale_weights(
643 struct yac_interp_grid * interp_grid,
644 struct yac_spmap_scale_config scale_config,
645 size_t num_src_points, size_t const * src_points,
646 size_t const * num_tgt_per_src, size_t const * tgt_points,
647 size_t total_num_weights, double * weights) {
648
650 (scale_config.type == YAC_INTERP_SPMAP_NONE) ||
651 (scale_config.type == YAC_INTERP_SPMAP_SRCAREA) ||
652 (scale_config.type == YAC_INTERP_SPMAP_INVTGTAREA) ||
653 (scale_config.type == YAC_INTERP_SPMAP_FRACAREA),
654 "ERROR(scale_weights): invalid scale_type")
655
656 // if there is no scaling
657 if (scale_config.type == YAC_INTERP_SPMAP_NONE) return;
658
659 // get cell areas if they are required
660 double const * src_cell_areas =
661 ((scale_config.type == YAC_INTERP_SPMAP_SRCAREA) ||
662 (scale_config.type == YAC_INTERP_SPMAP_FRACAREA))?
665 "source", scale_config.src, yac_interp_grid_get_MPI_Comm(interp_grid),
666 src_points, total_num_weights):NULL;
667 double const * tgt_cell_areas =
668 ((scale_config.type == YAC_INTERP_SPMAP_INVTGTAREA) ||
669 (scale_config.type == YAC_INTERP_SPMAP_FRACAREA))?
672 "target", scale_config.tgt, yac_interp_grid_get_MPI_Comm(interp_grid),
673 tgt_points, total_num_weights):NULL;
674
675#define SCALE_WEIGHTS( \
676 SRC_CELL_AREA, TGT_CELL_AREA) \
677{ \
678 for (size_t i = 0, offset = 0; i < num_src_points; ++i) { \
679 size_t curr_num_tgt = num_tgt_per_src[i]; \
680 for (size_t j = 0; j < curr_num_tgt; ++j, ++offset) { \
681 weights[offset] *= SRC_CELL_AREA / TGT_CELL_AREA; \
682 } \
683 } \
684}
685
686 switch (scale_config.type) {
688 SCALE_WEIGHTS(src_cell_areas[src_points[offset]], 1.0)
689 break;
691 SCALE_WEIGHTS(1.0, tgt_cell_areas[tgt_points[offset]])
692 break;
693 default:
696 src_cell_areas[src_points[offset]], tgt_cell_areas[tgt_points[offset]])
697 break;
698 }
699
700 free((void*)src_cell_areas);
701 free((void*)tgt_cell_areas);
702}
703
704static void spread_src_data(
705 struct yac_interp_grid * interp_grid, double spread_distance,
707 struct yac_spmap_scale_config scale_config,
708 size_t num_src_points, size_t ** src_points_,
709 size_t ** tgt_result_points_, double ** weights_,
710 size_t * total_num_weights_) {
711
712 // shortcut in case there is only a single "1.0" weight for all source points
713 if ((spread_distance <= 0) && (scale_config.type == YAC_INTERP_SPMAP_NONE)) {
714
715 *weights_ = NULL;
716 *total_num_weights_ = num_src_points;
717 return;
718 }
719
720 size_t * src_points = *src_points_;
721 size_t * tgt_result_points = *tgt_result_points_;
722
723 size_t * num_tgt_per_src =
724 xmalloc(num_src_points * sizeof(*num_tgt_per_src));
725 size_t total_num_weights;
726
727 // search for additional target points if spread distance is bigger than 0.0
728 if (spread_distance > 0.0) {
729
730 struct sin_cos_angle inc_angle =
731 sin_cos_angle_new(sin(spread_distance), cos(spread_distance));
732 yac_const_coordinate_pointer tgt_field_coords =
734
735 struct bounding_circle * search_bnd_circles =
736 xmalloc(num_src_points * sizeof(*search_bnd_circles));
737 for (size_t i = 0; i < num_src_points; ++i) {
738 memcpy(
739 search_bnd_circles[i].base_vector,
740 tgt_field_coords[tgt_result_points[i]], sizeof(*tgt_field_coords));
741 search_bnd_circles[i].inc_angle = inc_angle;
742 search_bnd_circles[i].sq_crd = DBL_MAX;
743 }
744 size_t * spread_tgt_result_points = NULL;
745
746 // do bounding circle search around found tgt points
748 interp_grid, search_bnd_circles, num_src_points,
749 &spread_tgt_result_points, num_tgt_per_src);
750 free(search_bnd_circles);
751
752 // remove target points which exceed the spread distance and only keep
753 // targets that are connected to the original target point or other
754 // target that have already been selected
755 total_num_weights =
757 interp_grid, spread_distance, num_src_points, tgt_result_points,
758 num_tgt_per_src, spread_tgt_result_points);
759 free((void*)tgt_result_points);
760 tgt_result_points =
761 xrealloc(
762 spread_tgt_result_points,
763 total_num_weights * sizeof(*spread_tgt_result_points));
764
765 // adjust src_points (one source per target)
766 size_t * new_src_points =
767 xmalloc(total_num_weights * sizeof(*new_src_points));
768 for (size_t i = 0, offset = 0; i < num_src_points; ++i)
769 for (size_t j = 0, curr_src_point = src_points[i];
770 j < num_tgt_per_src[i]; ++j, ++offset)
771 new_src_points[offset] = curr_src_point;
772 free((void*)src_points);
773 src_points = new_src_points;
774
775 } else {
776
777 for (size_t i = 0; i < num_src_points; ++i) num_tgt_per_src[i] = 1;
778 total_num_weights = num_src_points;
779 }
780
781 // compute weights
782 double * weights =
784 interp_grid, weight_type, num_src_points, src_points,
785 num_tgt_per_src, total_num_weights, tgt_result_points);
786
787 // scale weights
789 interp_grid, scale_config, num_src_points, src_points, num_tgt_per_src,
790 tgt_result_points, total_num_weights, weights);
791
792 free(num_tgt_per_src);
793
794 // set return values
795 *tgt_result_points_ = tgt_result_points;
796 *src_points_ = src_points;
797 *weights_ = weights;
798 *total_num_weights_ = total_num_weights;
799}
800
801static size_t do_search_spmap (struct interp_method * method,
802 struct yac_interp_grid * interp_grid,
803 size_t * tgt_points, size_t count,
804 struct yac_interp_weights * weights,
805 int * interpolation_complete) {
806
807 if (*interpolation_complete) return 0;
808
810 yac_interp_grid_get_num_src_fields(interp_grid) == 1,
811 "ERROR(do_search_spmap): invalid number of source fields")
814 "ERROR(do_search_spmap): "
815 "invalid source field location (has to be YAC_LOC_CELL)")
818 "ERROR(do_search_spmap): "
819 "invalid target field location (has to be YAC_LOC_CELL)")
820
821 // get coordinates of all source points
822 size_t * src_points;
823 size_t num_src_points;
825 interp_grid, 0, &src_points, &num_src_points);
826 yac_coordinate_pointer src_coords = xmalloc(num_src_points * sizeof(*src_coords));
828 interp_grid, src_points, num_src_points, 0, src_coords);
829
830 // search for matching tgt points
831 size_t * tgt_result_points =
832 xmalloc(num_src_points * sizeof(*tgt_result_points));
834 interp_grid, src_coords, num_src_points, 1, tgt_result_points,
835 ((struct interp_method_spmap*)method)->max_search_distance);
836
837 free(src_coords);
838
839 // remove source points for which matching target point was found
840 {
841 size_t new_num_src_points = 0;
842 for (size_t i = 0; i < num_src_points; ++i) {
843 if (tgt_result_points[i] != SIZE_MAX) {
844 if (i != new_num_src_points) {
845 src_points[new_num_src_points] = src_points[i];
846 tgt_result_points[new_num_src_points] =
847 tgt_result_points[i];
848 }
849 ++new_num_src_points;
850 }
851 }
852 num_src_points = new_num_src_points;
853 }
854
855 // spread the data from each source point to multiple target points
856 // (weight_data is set to NULL if no spreading was applied)
857 double * weight_data;
858 size_t total_num_weights;
860 interp_grid, ((struct interp_method_spmap*)method)->spread_distance,
861 ((struct interp_method_spmap*)method)->weight_type,
862 ((struct interp_method_spmap*)method)->scale_config, num_src_points,
863 &src_points, &tgt_result_points, &weight_data, &total_num_weights);
864
865 // relocate source-target-point-pairs to dist owners of the respective
866 // target points
867 size_t result_count = total_num_weights;
868 int to_tgt_owner = 1;
870 interp_grid, to_tgt_owner,
871 0, &src_points, &tgt_result_points, &weight_data, &result_count);
872 total_num_weights = result_count;
873
874 // sort source-target-point-pairs by target points
876 tgt_result_points, result_count, src_points, weight_data);
877
878 // generate num_src_per_tgt and compact tgt_result_points
879 size_t * num_src_per_tgt = xmalloc(result_count * sizeof(*num_src_per_tgt));
880 size_t num_unique_tgt_result_points = 0;
881 for (size_t i = 0; i < result_count;) {
882 size_t prev_i = i;
883 size_t curr_tgt = tgt_result_points[i];
884 while ((i < result_count) && (curr_tgt == tgt_result_points[i])) ++i;
885 num_src_per_tgt[num_unique_tgt_result_points] = i - prev_i;
886 tgt_result_points[num_unique_tgt_result_points] = curr_tgt;
887 ++num_unique_tgt_result_points;
888 }
889 result_count = num_unique_tgt_result_points;
890 num_src_per_tgt =
891 xrealloc(num_src_per_tgt, result_count * sizeof(*num_src_per_tgt));
892 tgt_result_points =
893 xrealloc(tgt_result_points, result_count * sizeof(*tgt_result_points));
894
895 // match tgt_result_points with available target points
896 qsort(tgt_points, count, sizeof(*tgt_points), compare_size_t);
897 int * reorder_flag = xmalloc(count * sizeof(*tgt_points));
898 {
899 size_t j = 0;
900 for (size_t i = 0; i < result_count; ++i) {
901 size_t curr_result_tgt = tgt_result_points[i];
902 while ((j < count) && (tgt_points[j] < curr_result_tgt))
903 reorder_flag[j++] = 1;
905 (j < count) && (curr_result_tgt == tgt_points[j]),
906 "ERROR(do_search_spmap): "
907 "required target points already in use or not available")
908 reorder_flag[j++] = 0;
909 }
910 for (; j < count; ++j) reorder_flag[j] = 1;
911 }
912
913 // sort used target points to the beginning of the array
914 yac_quicksort_index_int_size_t(reorder_flag, count, tgt_points);
915 free(reorder_flag);
916
917 struct remote_point * srcs =
919 interp_grid, 0, src_points, total_num_weights);
920 struct remote_points tgts = {
921 .data =
923 interp_grid, tgt_result_points, result_count),
924 .count = result_count};
925 free(tgt_result_points);
926
927 // store results
928 if (weight_data == NULL)
930 weights, &tgts, num_src_per_tgt, srcs);
931 else
933 weights, &tgts, num_src_per_tgt, srcs, weight_data);
934
935 free(weight_data);
936 free(src_points);
937 free(tgts.data);
938 free(srcs);
939 free(num_src_per_tgt);
940
941 return result_count;
942}
943
945 struct yac_spmap_cell_area_config * cell_area_config, char const * type) {
946
948 (cell_area_config->cell_area_provider == YAC_INTERP_SPMAP_CELL_AREA_YAC) ||
949 (cell_area_config->cell_area_provider == YAC_INTERP_SPMAP_CELL_AREA_FILE),
950 "ERROR(check_cell_area_config): invalid %s cell_area_provider type", type);
951
952 switch (cell_area_config->cell_area_provider) {
953 default:
956 cell_area_config->sphere_radius > 0.0,
957 "ERROR(check_cell_area_config): invalid %s sphere_radius "
958 "(has to be >= 0.0", type);
959 cell_area_config->file_config.filename = NULL;
960 cell_area_config->file_config.varname = NULL;
961 cell_area_config->file_config.min_global_id = XT_INT_MAX;
962 break;
963 }
965#ifndef YAC_NETCDF_ENABLED
966 die(
967 "ERROR(interp_method_spmap::check_cell_area_config): "
968 "YAC is built without the NetCDF support");
969#endif
971 (cell_area_config->file_config.filename != NULL) &&
972 (strlen(cell_area_config->file_config.filename) > 0),
973 "ERROR(check_cell_area_config): invalid filename for %s areas", type);
975 (cell_area_config->file_config.varname!= NULL) &&
976 (strlen(cell_area_config->file_config.varname) > 0),
977 "ERROR(check_cell_area_config): invalid varname for %s areas", type);
978 cell_area_config->sphere_radius = 0.0;
979 cell_area_config->file_config.filename =
980 strdup(cell_area_config->file_config.filename);
981 cell_area_config->file_config.varname =
982 strdup(cell_area_config->file_config.varname);
983 break;
984 }
985 }
986}
987
989 double spread_distance, double max_search_distance,
991 struct yac_spmap_scale_config scale_config) {
992
993 struct interp_method_spmap * method = xmalloc(1 * sizeof(*method));
994
997 method->max_search_distance =
999 method->weight_type = weight_type;
1000 method->scale_config = scale_config;
1001
1002 YAC_ASSERT(
1003 (spread_distance >= 0.0) && (spread_distance <= M_PI_2),
1004 "ERROR(yac_interp_method_spmap_new): invalid spread_distance "
1005 "(has to be >= 0 and <= PI/2")
1006
1007 YAC_ASSERT(
1008 (max_search_distance >= 0.0) && (max_search_distance <= M_PI),
1009 "ERROR(yac_interp_method_spmap_new): invalid max_search_distance "
1010 "(has to be >= 0 and <= PI")
1011
1012 check_cell_area_config(&(method->scale_config.src), "source");
1013 check_cell_area_config(&(method->scale_config.tgt), "target");
1014
1015 return (struct interp_method*)method;
1016}
1017
1018static void delete_spmap(struct interp_method * method) {
1019
1020 struct interp_method_spmap * method_spmap =
1021 (struct interp_method_spmap*)(method);
1022
1023 free((void*)method_spmap->scale_config.src.file_config.filename);
1024 free((void*)method_spmap->scale_config.src.file_config.varname);
1025 free((void*)method_spmap->scale_config.tgt.file_config.filename);
1026 free((void*)method_spmap->scale_config.tgt.file_config.varname);
1027 free(method);
1028}
double yac_huiliers_area(struct yac_grid_cell cell)
Area calculation on a unit sphere taken from ESMF based on L'Huilier's Theorem.
Definition area.c:449
Structs and interfaces for area calculations.
#define YAC_AREA_TOL
Definition area.h:23
enum yac_interp_ncc_weight_type weight_type
#define UNUSED(x)
Definition core.h:73
void yac_const_basic_grid_data_get_grid_cell(struct yac_const_basic_grid_data *grid_data, size_t cell_idx, struct yac_grid_cell *buffer_cell)
Definition dist_grid.c:2440
size_t const *const const_size_t_pointer
#define ENSURE_ARRAY_SIZE(arrayp, curr_array_size, req_size)
#define yac_angle_tol
Definition geometry.h:34
static double get_vector_angle(double const a[3], double const b[3])
Definition geometry.h:350
static struct sin_cos_angle sin_cos_angle_new(double sin, double cos)
Definition geometry.h:387
void yac_init_grid_cell(struct yac_grid_cell *cell)
Definition grid_cell.c:14
void yac_free_grid_cell(struct yac_grid_cell *cell)
Definition grid_cell.c:44
enum yac_location yac_interp_grid_get_tgt_field_location(struct yac_interp_grid *interp_grid)
void yac_interp_grid_relocate_src_tgt_pairs(struct yac_interp_grid *interp_grid, int to_tgt_owner, size_t src_field_idx, size_t **src_points, size_t **tgt_points, double **weights, size_t *count)
size_t yac_interp_grid_get_num_src_fields(struct yac_interp_grid *interp_grid)
void yac_interp_grid_do_bnd_circle_search_tgt(struct yac_interp_grid *interp_grid, const_bounding_circle_pointer bnd_circles, size_t count, size_t **tgt_cells, size_t *num_tgt_per_bnd_circle)
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)
void yac_interp_grid_get_src_points(struct yac_interp_grid *interp_grid, size_t src_field_idx, size_t **src_indices, size_t *count)
Definition interp_grid.c:87
enum yac_location yac_interp_grid_get_src_field_location(struct yac_interp_grid *interp_grid, size_t src_field_idx)
void yac_interp_grid_get_src_coordinates(struct yac_interp_grid *interp_grid, size_t *src_points, size_t count, size_t src_field_idx, yac_coordinate_pointer src_coordinates)
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)
yac_const_coordinate_pointer yac_interp_grid_get_src_field_coords(struct yac_interp_grid *interp_grid, size_t src_field_idx)
yac_const_coordinate_pointer yac_interp_grid_get_tgt_field_coords(struct yac_interp_grid *interp_grid)
struct yac_const_basic_grid_data * yac_interp_grid_get_basic_grid_data_tgt(struct yac_interp_grid *interp_grid)
void yac_interp_grid_do_nnn_search_tgt(struct yac_interp_grid *interp_grid, yac_coordinate_pointer search_coords, size_t count, size_t n, size_t *tgt_points, double max_search_distance)
struct yac_const_basic_grid_data * yac_interp_grid_get_basic_grid_data_src(struct yac_interp_grid *interp_grid)
enum callback_type type
static int lists_overlap(size_t *list_a, size_t count_a, size_t *list_b, size_t count_b)
static void delete_spmap(struct interp_method *method)
static int compare_size_t(const void *a, const void *b)
static size_t do_search_spmap(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 struct interp_method_vtable interp_method_spmap_vtable
static void merge_lists(size_t *list, size_t *list_size, size_t *insert, size_t insert_size)
static void remove_disconnected_points(struct yac_interp_grid *interp_grid, size_t tgt_start_point, size_t *from_tgt_points, size_t *to_tgt_points, size_t *count, int *flag, size_t *temp_cell_edges, size_t **edges_buffer, size_t *edges_buffer_array_size)
static void compute_cell_areas(struct yac_const_basic_grid_data *basic_grid_data, int *required_cell_areas, double area_scale, char const *type, double *cell_areas)
static void check_cell_area_config(struct yac_spmap_cell_area_config *cell_area_config, char const *type)
static void spread_src_data(struct yac_interp_grid *interp_grid, double spread_distance, enum yac_interp_spmap_weight_type weight_type, struct yac_spmap_scale_config scale_config, size_t num_src_points, size_t **src_points_, size_t **tgt_result_points_, double **weights_, size_t *total_num_weights_)
#define SCALE_WEIGHTS(SRC_CELL_AREA, TGT_CELL_AREA)
static void read_cell_areas(struct yac_const_basic_grid_data *basic_grid_data, struct yac_spmap_cell_area_file_config file_config, MPI_Comm comm, int *required_cell_areas, char const *type, double *cell_areas)
struct interp_method * yac_interp_method_spmap_new(double spread_distance, double max_search_distance, enum yac_interp_spmap_weight_type weight_type, struct yac_spmap_scale_config scale_config)
static size_t check_tgt_result_points(struct yac_interp_grid *interp_grid, double spread_distance, size_t num_src_points, size_t const *const tgt_result_points, size_t *num_tgt_per_src, size_t *spread_tgt_result_points)
static void check_spread_distance(yac_const_coordinate_pointer tgt_field_coords, double max_distance, size_t tgt_start_point, size_t *tgt_points, size_t *count)
static void dist_read_cell_areas(char const *filename, char const *varname, MPI_Comm comm, int *io_ranks, int io_rank_idx, int num_io_ranks, double **dist_cell_areas, size_t *dist_cell_areas_global_size)
static double * compute_weights(struct yac_interp_grid *interp_grid, enum yac_interp_spmap_weight_type weight_type, size_t num_src_points, size_t const *const src_points, size_t const *const num_tgt_per_src, size_t total_num_tgt, size_t const *const tgt_result_points)
static void scale_weights(struct yac_interp_grid *interp_grid, struct yac_spmap_scale_config scale_config, size_t num_src_points, size_t const *src_points, size_t const *num_tgt_per_src, size_t const *tgt_points, size_t total_num_weights, double *weights)
static double * get_cell_areas(struct yac_const_basic_grid_data *basic_grid_data, char const *type, struct yac_spmap_cell_area_config cell_area_config, MPI_Comm comm, size_t const *required_points, size_t num_required_points)
@ YAC_INTERP_SPMAP_NONE
weights are not scaled
@ YAC_INTERP_SPMAP_INVTGTAREA
@ YAC_INTERP_SPMAP_SRCAREA
@ YAC_INTERP_SPMAP_FRACAREA
@ YAC_INTERP_SPMAP_CELL_AREA_FILE
@ YAC_INTERP_SPMAP_CELL_AREA_YAC
yac_interp_spmap_weight_type
@ YAC_INTERP_SPMAP_AVG
@ YAC_INTERP_SPMAP_DIST
void yac_interp_weights_add_wsum(struct yac_interp_weights *weights, struct remote_points *tgts, size_t *num_src_per_tgt, struct remote_point *srcs, double *w)
void yac_interp_weights_add_sum(struct yac_interp_weights *weights, struct remote_points *tgts, size_t *num_src_per_tgt, struct remote_point *srcs)
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
#define YAC_HANDLE_ERROR(exp)
Definition io_utils.h:35
@ YAC_LOC_CELL
Definition location.h:14
#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 sin_cos_angle inc_angle
angle between the middle point and the boundary of the spherical cap
Definition geometry.h:61
double base_vector[3]
Definition geometry.h:59
double sq_crd
Definition geometry.h:64
struct yac_spmap_scale_config scale_config
enum yac_interp_spmap_weight_type weight_type
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
double sin
Definition geometry.h:41
double cos
Definition geometry.h:41
const const_int_pointer num_vertices_per_cell
const_size_t_pointer cell_to_edge
const const_yac_int_pointer ids[3]
const_size_t_pointer cell_to_edge_offsets
struct yac_spmap_scale_config::yac_spmap_cell_area_config::yac_spmap_cell_area_file_config file_config
struct yac_spmap_scale_config::yac_spmap_cell_area_config src
struct yac_spmap_scale_config::yac_spmap_cell_area_config tgt
enum yac_interp_spmap_scale_type type
void yac_quicksort_index_size_t_size_t_double(size_t *a, size_t n, size_t *b, double *c)
void yac_quicksort_index_int_size_t(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:19
#define die(msg)
Definition yac_assert.h:12
#define YAC_ASSERT(exp, msg)
Definition yac_assert.h:16
void yac_generate_alltoallv_args(int count, size_t const *sendcounts, size_t *recvcounts, size_t *sdispls, size_t *rdispls, MPI_Comm comm)
Definition yac_mpi.c:577
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
double const (* yac_const_coordinate_pointer)[3]
Definition yac_types.h:20
double(* yac_coordinate_pointer)[3]
Definition yac_types.h:19