YAC 3.7.0
Yet Another Coupler
Loading...
Searching...
No Matches
interp_method_avg.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 <string.h>
11
13#include "grid_cell.h"
14#include "interp_method_avg.h"
16
17#define SWAP(x, y, T) do { T SWAP = x; x = y; y = SWAP; } while (0)
18
19static size_t do_search_avg(struct interp_method * method,
20 struct yac_interp_grid * interp_grid,
21 size_t * tgt_points, size_t count,
22 struct yac_interp_weights * weights,
23 int * interpolation_complete);
24static void delete_avg(struct interp_method * method);
25
26typedef int (*func_compute_weights)(
27 double[3], size_t, yac_const_coordinate_pointer, int*, double*,
28 enum yac_cell_type cell_type);
29
30static struct interp_method_vtable
34
40
42 double * point, size_t field_cell, size_t cell_size,
43 size_t const * vertex_to_cell, size_t const * vertex_to_cell_offsets,
44 yac_const_coordinate_pointer field_coordinates,
45 struct yac_grid_cell * cell_buffer) {
46
47 if (cell_size == 0) return 0;
48
49 cell_buffer->num_corners = cell_size;
50
51 yac_coordinate_pointer coordinates_xyz;
52
53 if (cell_size > cell_buffer->array_size) {
54 cell_buffer->coordinates_xyz =
55 ((coordinates_xyz =
57 cell_buffer->coordinates_xyz,
58 cell_size * sizeof(*coordinates_xyz))));
59 cell_buffer->edge_type =
61 cell_buffer->edge_type, cell_size * sizeof(cell_buffer->edge_type));
62 for (size_t i = 0; i < cell_size; ++i)
63 cell_buffer->edge_type[i] = YAC_GREAT_CIRCLE_EDGE;
64 cell_buffer->array_size = cell_size;
65 } else {
66 coordinates_xyz = cell_buffer->coordinates_xyz;
67 }
68
69 size_t const * field_cell_vertices =
70 vertex_to_cell + vertex_to_cell_offsets[field_cell];
71 for (size_t i = 0; i < cell_size; ++i)
72 memcpy(coordinates_xyz[i], field_coordinates[field_cell_vertices[i]],
73 sizeof(*coordinates_xyz));
74
75 return yac_point_in_cell(point, *cell_buffer);
76}
77
78#define IS_GC(x) (((x) == YAC_GREAT_CIRCLE_EDGE) || ((x) == YAC_LON_CIRCLE_EDGE))
79#define IS_LON_LAT(x) (((x) == YAC_LAT_CIRCLE_EDGE) || ((x) == YAC_LON_CIRCLE_EDGE))
80
82 enum yac_edge_type const * edge_types,
83 size_t const * edge_indices, size_t num_edges) {
84
85 if (edge_types == NULL) return YAC_GREAT_CIRCLE_CELL;
86
87 int edge_type_flag = 0;
88
89 if (num_edges == 4) {
90
91 enum yac_edge_type temp_edges[4] =
92 {edge_types[edge_indices[0]],
93 edge_types[edge_indices[1]],
94 edge_types[edge_indices[2]],
95 edge_types[edge_indices[3]]};
96 if (IS_LON_LAT(temp_edges[0]) &&
97 IS_LON_LAT(temp_edges[1]) &&
98 (temp_edges[0] == temp_edges[2]) &&
99 (temp_edges[1] == temp_edges[3]) &&
100 (temp_edges[0] != temp_edges[1]))
101 return YAC_LON_LAT_CELL;
102 }
103
104 for (size_t i = 0; i < num_edges; ++i)
105 edge_type_flag |= (1 << (edge_types[edge_indices[i]] == YAC_LAT_CIRCLE_EDGE));
106
107 enum yac_cell_type cell_types[4] =
112 return cell_types[edge_type_flag];
113}
114#undef IS_LON_LAT
115#undef IS_GC
116
117static size_t do_search_avg (struct interp_method * method,
118 struct yac_interp_grid * interp_grid,
119 size_t * tgt_points, size_t count,
120 struct yac_interp_weights * weights,
121 int * interpolation_complete) {
122
123 if (*interpolation_complete) return 0;
124
125 struct interp_method_avg * method_avg = (struct interp_method_avg *)method;
127
129 yac_interp_grid_get_num_src_fields(interp_grid) == 1,
130 "ERROR(do_search_avg): invalid number of source fields")
131
132 enum yac_location src_field_location =
134
136 (src_field_location == YAC_LOC_CORNER) ||
137 (src_field_location == YAC_LOC_CELL),
138 "ERROR(do_search_avg): unsupported source field location type")
139
140 // get coordinates of target points
141 yac_coordinate_pointer tgt_coords = xmalloc(count * sizeof(*tgt_coords));
143 interp_grid, tgt_points, count, tgt_coords);
144
145 size_t * size_t_buffer = xmalloc(2 * count * sizeof(*size_t_buffer));
146 size_t * src_field_cells = size_t_buffer;
147 size_t * reorder_idx = size_t_buffer + count;
148
149 // get matching source cells for all target points
151 interp_grid, tgt_coords, count, src_field_cells);
152
153 size_t const * src_field_cell_to_vertex;
154 size_t const * src_field_cell_to_vertex_offsets;
155 size_t const * src_field_cell_to_edge;
156 size_t const * src_field_cell_to_edge_offsets;
157 int const * src_field_num_vertices_per_cell;
158 enum yac_edge_type const * src_edge_types;
159
160 // if the source field is location at cell points
161 if (src_field_location == YAC_LOC_CELL) {
162
163 // generate auxiliary grid for all search result cells
165 interp_grid, src_field_cells, count,
166 (size_t**)&src_field_cell_to_vertex,
167 (size_t**)&src_field_cell_to_vertex_offsets,
168 (int**)&src_field_num_vertices_per_cell);
169
170 struct yac_const_basic_grid_data * src_grid_data =
172 yac_const_coordinate_pointer src_field_coordinates =
174
175 struct yac_grid_cell cell_buffer;
176 yac_init_grid_cell(&cell_buffer);
177
178 // for all target point
179 for (size_t i = 0; i < count; ++i) {
180
181 size_t curr_src_cell = src_field_cells[i];
182 if (curr_src_cell == SIZE_MAX) continue;
183
184 double * curr_tgt_coord = tgt_coords[i];
185 size_t const * curr_vertices =
186 src_grid_data->cell_to_vertex +
187 src_grid_data->cell_to_vertex_offsets[curr_src_cell];
188 size_t curr_num_vertices =
189 src_grid_data->num_vertices_per_cell[curr_src_cell];
190
191 size_t result_src_field_cell = SIZE_MAX;
192
193 // for all auxiliary of the current source result cell
194 for (size_t j = 0; j < curr_num_vertices; ++j) {
195
196 size_t src_field_cell = curr_vertices[j];
197 size_t src_field_cell_size =
198 (size_t)src_field_num_vertices_per_cell[src_field_cell];
199
200 // check whether the target point is in the current source field cell
202 curr_tgt_coord, src_field_cell, src_field_cell_size,
203 src_field_cell_to_vertex, src_field_cell_to_vertex_offsets,
204 src_field_coordinates, &cell_buffer)) {
205 result_src_field_cell = src_field_cell;
206 break;
207 }
208 }
209
210 src_field_cells[i] = result_src_field_cell;
211 }
212 yac_free_grid_cell(&cell_buffer);
213
214 src_edge_types = NULL;
215 src_field_cell_to_edge = NULL;
216 src_field_cell_to_edge_offsets = NULL;
217 } else {
218
219 struct yac_const_basic_grid_data * grid_data =
221 src_field_cell_to_vertex = grid_data->cell_to_vertex;
222 src_field_cell_to_vertex_offsets = grid_data->cell_to_vertex_offsets;
223 src_field_num_vertices_per_cell = grid_data->num_vertices_per_cell;
224 src_edge_types = grid_data->edge_type;
225 src_field_cell_to_edge = grid_data->cell_to_edge;
226 src_field_cell_to_edge_offsets = grid_data->cell_to_edge_offsets;
227 }
228 yac_const_coordinate_pointer src_field_coordinates =
230 const_yac_int_pointer src_global_ids =
232
233 // sort target points, for which we found a source cell, to the beginning of
234 // the array
235 for (size_t i = 0; i < count; ++i) reorder_idx[i] = i;
236 yac_quicksort_index_size_t_size_t(src_field_cells, count, reorder_idx);
237
238 size_t result_count = 0;
239 for (result_count = 0; result_count < count; ++result_count)
240 if (src_field_cells[result_count] == SIZE_MAX) break;
241
242 size_t total_num_weights = 0;
243 size_t max_num_vertices_per_cell = 0;
244 size_t * num_weights_per_tgt =
245 xmalloc(result_count * sizeof(*num_weights_per_tgt));
246
247 // get the number of vertices per target cell and the total number of vertices
248 // required for the interpolation (may contain duplicated vertices)
249 for (size_t i = 0; i < result_count; ++i) {
250 size_t curr_num_vertices =
251 (size_t)(src_field_num_vertices_per_cell[src_field_cells[i]]);
252 num_weights_per_tgt[i] = curr_num_vertices;
253 total_num_weights += curr_num_vertices;
254 if (curr_num_vertices > max_num_vertices_per_cell)
255 max_num_vertices_per_cell = curr_num_vertices;
256 }
257 if (src_field_location == YAC_LOC_CELL)
258 free((void*)src_field_num_vertices_per_cell);
259
260 const_int_pointer src_field_mask =
262
263 yac_coordinate_pointer src_coord_buffer =
264 xmalloc(max_num_vertices_per_cell * sizeof(*src_coord_buffer));
265 int * mask_buffer =
266 (src_field_mask != NULL)?
267 xmalloc(max_num_vertices_per_cell * sizeof(*mask_buffer)):NULL;
268 double * w = xmalloc(total_num_weights * sizeof(*w));
269 size_t * src_points = xmalloc(total_num_weights * sizeof(*src_points));
270
271 // for each target point, extract relevant source data and compute the weights
272 // based on that
273 total_num_weights = 0;
274 for (size_t i = 0; i < result_count;) {
275
276 size_t curr_num_vertices = num_weights_per_tgt[i];
277
278 const_size_t_pointer curr_cell_to_vertex =
279 src_field_cell_to_vertex +
280 src_field_cell_to_vertex_offsets[src_field_cells[i]];
281 const_size_t_pointer curr_cell_to_edge =
282 (src_edge_types != NULL)?
283 (src_field_cell_to_edge +
284 src_field_cell_to_edge_offsets[src_field_cells[i]]):NULL;
285 double * curr_weights = w + total_num_weights;
286
287 // get the index of the source cell corner with the lowest global id
288 // (this is being used, that the order in which the source corners are
289 // processes is decomposition independent)
290 size_t lowest_global_id_idx = 0;
291 {
292 yac_int lowest_global_id = src_global_ids[curr_cell_to_vertex[0]];
293 for (size_t j = 1; j < curr_num_vertices; ++j) {
294 if (src_global_ids[curr_cell_to_vertex[j]] < lowest_global_id) {
295 lowest_global_id = src_global_ids[curr_cell_to_vertex[j]];
296 lowest_global_id_idx = j;
297 }
298 }
299 }
300
301 // get the mask and the source coordinates of the source vertices required
302 // for the current target point
303 for (size_t j = 0, l = lowest_global_id_idx; j < curr_num_vertices;
304 ++j, ++total_num_weights, ++l) {
305
306 if (l == curr_num_vertices) l = 0;
307
308 size_t curr_vertex_idx = curr_cell_to_vertex[l];
309 src_points[total_num_weights] = curr_vertex_idx;
310 for (size_t k = 0; k < 3; ++k)
311 src_coord_buffer[j][k] = src_field_coordinates[curr_vertex_idx][k];
312 if (src_field_mask != NULL)
313 mask_buffer[j] = src_field_mask[curr_vertex_idx];
314 }
315
316 enum yac_cell_type cell_type =
318 src_edge_types, curr_cell_to_edge, curr_num_vertices);
319
320 // compute the weights
321 if (compute_weights(tgt_coords[reorder_idx[i]], curr_num_vertices,
322 (yac_const_coordinate_pointer)src_coord_buffer,
323 mask_buffer, curr_weights, cell_type)) {
324
325 // if weight computation was successful
326 num_weights_per_tgt[i] = curr_num_vertices;
327 ++i;
328 } else {
329
330 // if no weights could be computed
331 total_num_weights -= curr_num_vertices;
332 result_count--;
333 src_field_cells[i] = src_field_cells[result_count];
334 size_t temp_reorder_idx = reorder_idx[i];
335 reorder_idx[i] = reorder_idx[result_count];
336 reorder_idx[result_count] = temp_reorder_idx;
337 }
338 }
339 if (src_field_location == YAC_LOC_CELL) {
340 free((void*)src_field_cell_to_vertex);
341 free((void*)src_field_cell_to_vertex_offsets);
342 }
343
344 // move the non-interpolated target points to the end
345 for (size_t i = 0; i < count; ++i) src_field_cells[reorder_idx[i]] = i;
346 yac_quicksort_index_size_t_size_t(src_field_cells, count, tgt_points);
347
348 free(tgt_coords);
349 free(mask_buffer);
350 free(src_coord_buffer);
351 free(size_t_buffer);
352
353 struct remote_points tgts = {
354 .data =
356 interp_grid, tgt_points, result_count),
357 .count = result_count};
358 struct remote_point * srcs =
360 interp_grid, 0, src_points, total_num_weights);
361
362 // store weights
364 weights, &tgts, num_weights_per_tgt, srcs, w);
365
366 free(tgts.data);
367 free(srcs);
368 free(w);
369 free(num_weights_per_tgt);
370 free(src_points);
371
372 return result_count;
373}
374
376 double tgt_coords[3], size_t num_vertices,
377 yac_const_coordinate_pointer src_coords, int * src_mask, double * weights,
378 enum yac_cell_type cell_type) {
379
380 UNUSED(tgt_coords);
381 UNUSED(cell_type);
382 UNUSED(src_coords);
383
384 size_t num_unmasked_points = 0;
385
386 // if we have a source mask, check whether any points is masked
387 if (src_mask != NULL) {
388 for (size_t i = 0; i < num_vertices; ++i)
389 if (src_mask[i]) num_unmasked_points++;
390 if (num_unmasked_points == 0) return 0;
391
392 double weight = 1.0 / (double)num_unmasked_points;
393 for (size_t i = 0; i < num_vertices; ++i)
394 weights[i] = (src_mask[i])?weight:0.0;
395
396 } else {
397 double weight = 1.0 / (double)num_vertices;
398 for (size_t i = 0; i < num_vertices; ++i) weights[i] = weight;
399 }
400 return 1;
401}
402
404 double tgt_coords[3], size_t num_vertices,
405 yac_const_coordinate_pointer src_coords, int * src_mask, double * weights,
406 enum yac_cell_type cell_type) {
407
408 UNUSED(tgt_coords);
409 UNUSED(cell_type);
410 UNUSED(src_coords);
411
412 // if we have a source mask, check whether any points is masked
413 if (src_mask != NULL)
414 for (size_t i = 0; i < num_vertices; ++i)
415 if (!src_mask[i]) return 0;
416
417 double weight = 1.0 / (double)num_vertices;
418 for (size_t i = 0; i < num_vertices; ++i) weights[i] = weight;
419
420 return 1;
421}
422
424 double tgt_coords[3], size_t num_vertices,
425 yac_const_coordinate_pointer src_coords, int * src_mask, double * weights,
426 enum yac_cell_type cell_type) {
427
428 UNUSED(cell_type);
429
430 // if there is a source mask, check if there are unmasked vertices
431 if (src_mask != NULL) {
432 int has_unmasked = 0;
433 for (size_t i = 0; i < num_vertices; ++i) has_unmasked |= src_mask[i];
434 if (!has_unmasked) return 0;
435 }
436
437 if (src_mask != NULL) {
438 for (size_t i = 0; i < num_vertices; ++i) {
439
440 if (src_mask[i]) {
441
442 double distance =
443 get_vector_angle(tgt_coords, (double*)(src_coords[i]));
444
445 // if the target and source point are nearly identical
446 if (distance < yac_angle_tol) {
447 for (size_t j = 0; j < num_vertices; ++j) weights[j] = 0.0;
448 weights[i] = 1.0;
449 return 1;
450 }
451
452 weights[i] = 1.0 / distance;
453 } else {
454 weights[i] = 0.0;
455 }
456 }
457 } else {
458 for (size_t i = 0; i < num_vertices; ++i) {
459
460 double distance =
461 get_vector_angle(tgt_coords, (double*)(src_coords[i]));
462
463 // if the target and source point are nearly identical
464 if (distance < yac_angle_tol) {
465 for (size_t j = 0; j < num_vertices; ++j) weights[j] = 0.0;
466 weights[i] = 1.0;
467 return 1;
468 }
469
470 weights[i] = 1.0 / distance;
471 }
472 }
473
474 // compute scaling factor for the weights
475 double inv_distance_sum = 0.0;
476 for (size_t i = 0; i < num_vertices; ++i)
477 inv_distance_sum += weights[i];
478 double scale = 1.0 / inv_distance_sum;
479
480 for (size_t i = 0; i < num_vertices; ++i) weights[i] *= scale;
481
482 return 1;
483}
484
486 double tgt_coords[3], size_t num_vertices,
487 yac_const_coordinate_pointer src_coords, int * src_mask, double * weights,
488 enum yac_cell_type cell_type) {
489
490 UNUSED(cell_type);
491
492 for (size_t i = 0; i < num_vertices; ++i) {
493
494 double distance =
495 get_vector_angle(tgt_coords, (double*)(src_coords[i]));
496
497 // if the target and source point are nearly identical
498 if (distance < yac_angle_tol) {
499 if ((src_mask != NULL) && !src_mask[i]) return 0;
500 for (size_t j = 0; j < num_vertices; ++j) weights[j] = 0.0;
501 weights[i] = 1.0;
502 return 1;
503 }
504
505 weights[i] = 1.0 / distance;
506 }
507
508 // if there is a source mask, check if there are masked vertices
509 // (we do this here because there may be a matching source point
510 // that is not masked)
511 if (src_mask != NULL)
512 for (size_t i = 0; i < num_vertices; ++i) if(!src_mask[i]) return 0;
513
514 // compute scaling factor for the weights
515 double inv_distance_sum = 0.0;
516 for (size_t i = 0; i < num_vertices; ++i)
517 inv_distance_sum += weights[i];
518 double scale = 1.0 / inv_distance_sum;
519
520 for (size_t i = 0; i < num_vertices; ++i) weights[i] *= scale;
521
522 return 1;
523}
524
525// compute the spherical barycentric coordinates of the given vertices with
526// respect to the given triangle
528 double * barycentric_coords, size_t triangle_indices[3],
530 char const * caller) {
531
532 double A[3][3];
533 lapack_int n = 3, nrhs = 1, lda = n, ldx = n, ipiv[3];
534 for (int i = 0; i < 3; ++i)
535 memcpy(A[i], grid_coords[triangle_indices[i]], sizeof(*grid_coords));
536
537 // for a vertex v the spherical barycentric coordinates b are defined as
538 // follows
539 // A * b = v
540 // where: A is the matrix consisting of the vertex coordinates of the three
541 // corners of the triangle
542 // we compute b by solving this linear system using LAPACK
544 !LAPACKE_dgesv(
545 LAPACK_COL_MAJOR, n, nrhs, &A[0][0], lda, ipiv, barycentric_coords, ldx),
546 "ERROR(%s::compute_sb_coords): "
547 "internal error (could not solve linear 3x3 system)\n"
548 "(vector: (% .6e;% .6e;% .6e)\n"
549 " triangle: ((% .6e;% .6e;% .6e),\n"
550 " (% .6e;% .6e;% .6e),\n"
551 " (% .6e;% .6e;% .6e))",
552 caller, barycentric_coords[0], barycentric_coords[1], barycentric_coords[2],
553 grid_coords[triangle_indices[0]][0],
554 grid_coords[triangle_indices[0]][1],
555 grid_coords[triangle_indices[0]][2],
556 grid_coords[triangle_indices[1]][0],
557 grid_coords[triangle_indices[1]][1],
558 grid_coords[triangle_indices[1]][2],
559 grid_coords[triangle_indices[2]][0],
560 grid_coords[triangle_indices[2]][1],
561 grid_coords[triangle_indices[2]][2])
562}
563
564// returns 0 if edge_direction_vec points south; 1 otherwise
565static inline int get_lat_edge_ordering(double const * a, double const * b) {
566
567 return (a[0] * b[1] - a[1] * b[0]) < 0.0;
568}
569
572 double lon[2], double lat[2], int reorder[4]) {
573
574 // determine whether the lat neighbour to vertex 0 is at position 1 or 3
575 int lat_neigh_offset =
576 (fabs(coords[0][2] - coords[1][2]) <
577 fabs(coords[0][2] - coords[3][2]))?1:3;
578 // get the index of the coord which is closest to the equator
579 // (the one with the lower absolut z coordinate)
580 int closest_to_equator_idx =
581 (fabs(coords[0][2]) < fabs(coords[2][2]))?0:2;
582 int upper_edge_idx = ((coords[0][2]) > coords[2][2])?0:2;
583 int lower_edge_idx = upper_edge_idx^2;
584 int upper_edge_is_closer_to_pole =
585 closest_to_equator_idx == upper_edge_idx;
586 int closest_to_equator_edge_ordering =
588 coords[closest_to_equator_idx],
589 coords[(closest_to_equator_idx+lat_neigh_offset)%4]);
590 int cell_ordering =
591 closest_to_equator_edge_ordering ^ upper_edge_is_closer_to_pole;
592
593 XYZtoLL(
594 coords[closest_to_equator_idx], &lon[closest_to_equator_edge_ordering],
595 &lat[upper_edge_is_closer_to_pole]);
596 double dummy;
597 XYZtoLL(
598 coords[(closest_to_equator_idx + lat_neigh_offset)%4],
599 &lon[closest_to_equator_edge_ordering^1], &dummy);
600 lat[!upper_edge_is_closer_to_pole] =
601 M_PI_2 - acos(coords[closest_to_equator_idx ^ 2][2]);
602
603 reorder[cell_ordering] = lower_edge_idx;
604 reorder[cell_ordering^1] = (lower_edge_idx+lat_neigh_offset)%4;
605 reorder[2+cell_ordering] = upper_edge_idx;
606 reorder[2+(cell_ordering^1)] = (upper_edge_idx+lat_neigh_offset)%4;
607
608 if (lon[1] < lon[0]) lon[1] += 2.0 * M_PI;
609
610 YAC_ASSERT_F(((lon[0] - lon[1]) != 0.0) && ((lat[0] - lat[1]) != 0.0),
611 "ERROR(get_cell_lon_lat_bounds): internal error\n"
612 "lon[0] = %e lon[1] = %e lat[0] = %e lat[1] = %e\n"
613 "cell coords: ((% .4e; % .4e; % .4e),\n"
614 " (% .4e; % .4e; % .4e),\n"
615 " (% .4e; % .4e; % .4e),\n"
616 " (% .4e; % .4e; % .4e)",
617 lon[0], lon[1], lat[0], lat[1],
618 coords[0][0], coords[0][1], coords[0][2],
619 coords[1][0], coords[1][1], coords[1][2],
620 coords[2][0], coords[2][1], coords[2][2],
621 coords[3][0], coords[3][1], coords[3][2]);
622}
623
625 double point_coord[3], double cell_lon[2], double cell_lat[2],
626 double * point_lon, double * point_lat) {
627
628 UNUSED(cell_lat);
629
630 double lon, lat;
631 XYZtoLL(point_coord, &lon, &lat);
632
633 // adjust target point lon to source cell lon
634 if (lon < cell_lon[0]) {
635 while (fabs(cell_lon[0] - lon) > M_PI) lon += 2.0 * M_PI;
636 } else {
637 while (fabs(lon - cell_lon[1]) > M_PI) lon -= 2.0 * M_PI;
638 }
639
640 *point_lon = lon;
641 *point_lat = lat;
642}
643
645 double point_lon, double point_lat, double cell_lon[2], double cell_lat[2]) {
646
647 return ((cell_lat[1] - cell_lat[0]) * (point_lat - cell_lat[0]) -
648 (cell_lat[1] - cell_lat[0]) * (point_lon - cell_lon[0])) > 0.0;
649}
650
652 double tgt_coords[3],
653 yac_const_coordinate_pointer src_coords, double * weights) {
654
655 // get lon lat bounds of the cell and the target point
656 double src_lon[2], src_lat[2], tgt_lon, tgt_lat;
657 int src_reorder[4];
658 get_cell_lon_lat_bounds(src_coords, src_lon, src_lat, src_reorder);
659 get_point_lon_lat(tgt_coords, src_lon, src_lat, &tgt_lon, &tgt_lat);
660
661 int triangle_idx =
662 determine_triangle_idx(tgt_lon, tgt_lat, src_lon, src_lat);
663
664 if (triangle_idx) {
665
666 double w[2];
667 w[0] = (tgt_lat - src_lat[1]) / (src_lat[0] - src_lat[1]);
668 w[1] = ((src_lat[1] - src_lat[0]) * (tgt_lon - src_lon[0])) /
669 ((src_lon[0] - src_lon[1]) * (src_lat[0] - src_lat[1]));
670
671 weights[src_reorder[0]] = w[0];
672 weights[src_reorder[2]] = w[1];
673 weights[src_reorder[3]] = 1.0 - (w[0] + w[1]);
674 weights[src_reorder[1]] = 0.0;
675 } else {
676
677 double w[2];
678 w[0] = (tgt_lon - src_lon[1]) / (src_lon[0] - src_lon[1]);
679 w[1] = ((src_lat[1] - src_lat[0]) * (tgt_lon - src_lon[1]) +
680 (src_lon[0] - src_lon[1]) * (tgt_lat - src_lat[1])) /
681 ((src_lat[0] - src_lat[1]) * (src_lon[0] - src_lon[1]));
682
683 weights[src_reorder[0]] = w[0];
684 weights[src_reorder[1]] = w[1];
685 weights[src_reorder[2]] = 1.0 - (w[0] + w[1]);
686 weights[src_reorder[3]] = 0.0;
687 }
688}
689
691 double tgt_coords[3], size_t num_vertices,
692 yac_const_coordinate_pointer src_coords, int * src_mask, double * weights,
693 enum yac_cell_type cell_type) {
694
695 // if all source points are masked
696 if (src_mask != NULL) {
697 size_t i;
698 for (i = 0; i < num_vertices; ++i) if (src_mask[i] != 0) break;
699 if (i == num_vertices) return 0;
700 }
701
702 double const tol = 1e-9;
703
705 (cell_type == YAC_LON_LAT_CELL) ||
706 (cell_type == YAC_GREAT_CIRCLE_CELL),
707 "ERROR(compute_weights_bary_yes): barycentric coordinates "
708 "are only supported for great circle edge cells and lon lat cells")
709
710 if (cell_type == YAC_LON_LAT_CELL) {
711
712 // compute weights
713 compute_weights_bary_reg(tgt_coords, src_coords, weights);
714
715 // apply mask handling
716 if (src_mask != NULL) {
717 double weight_sum = 1.0;
718
719 // check if any of the source points is masked
720 for (int i = 0; i < 4; ++i) if (!src_mask[i]) {
721 weight_sum -= weights[i];
722 weights[i] = 0.0;
723 }
724
725 // if all relevant points are masked
726 if (weight_sum < tol) return 0;
727
728 // if only some of the relevant points are masked
729 if (weight_sum < 1.0) {
730 double scale = 1.0 / weight_sum;
731 for (int i = 0; i < 4; ++i) weights[i] *= scale;
732 }
733 }
734
735 return 1;
736
737 } else {
738
739 size_t corner_indices[num_vertices];
740 size_t triangle_indices[num_vertices-2][3];
741
742 for (size_t i = 0; i < num_vertices; ++i) corner_indices[i] = i;
743
744 // triangulate source polygon
745 if (num_vertices > 3) {
747 corner_indices, num_vertices, 0, triangle_indices);
748 } else {
749 for (size_t i = 0; i < 3; ++i) triangle_indices[0][i] = i;
750 }
751
752 // find the best matching triangle
753 double min_barycentric_coord = -DBL_MAX;
754 double barycentric_coords[3];
755 size_t match_index = SIZE_MAX;
756
757 for (size_t i = 0; i < num_vertices - 2; ++i) {
758
759 double temp_barycentric_coords[3];
760 memcpy(temp_barycentric_coords, tgt_coords, 3 * sizeof(double));
761
762 // compute barycentric coordinates for the current triangle
764 temp_barycentric_coords, triangle_indices[i], src_coords,
765 "compute_weights_bary_yes");
766
767 double curr_min_barycentric_coord =
768 MIN(temp_barycentric_coords[0],
769 MIN(temp_barycentric_coords[1],
770 temp_barycentric_coords[2]));
771
772 if (curr_min_barycentric_coord > min_barycentric_coord) {
773 min_barycentric_coord = curr_min_barycentric_coord;
774 match_index = i;
775 for (int j = 0; j < 3; ++j)
776 barycentric_coords[j] = MAX(0.0, temp_barycentric_coords[j]);
777 }
778 }
779
780 // initialise weights
781 if (num_vertices > 3)
782 for (size_t j = 0; j < num_vertices; ++j) weights[j] = 0.0;
783
784 // apply mask
785 if (src_mask != NULL)
786 for (int j = 0; j < 3; ++j)
787 if (src_mask[triangle_indices[match_index][j]] == 0)
788 barycentric_coords[j] = 0.0;
789
790 double weight_sum = 0.0;
791 for (int j = 0; j < 3; ++j) {
792 if (barycentric_coords[j] < 1e-4) barycentric_coords[j] = 0.0;
793 else weight_sum += barycentric_coords[j];
794 }
795
796 if (weight_sum < tol) return 0;
797
798 double scale = 1.0 / weight_sum;
799
800 for (int j = 0; j < 3; ++j)
801 weights[triangle_indices[match_index][j]] =
802 barycentric_coords[j] * scale;
803
804 return 1;
805 }
806}
807
809 double tgt_coords[3], size_t num_vertices,
810 yac_const_coordinate_pointer src_coords, int * src_mask, double * weights,
811 enum yac_cell_type cell_type) {
812
813 // if all source points are masked
814 if (src_mask != NULL) {
815 size_t i;
816 for (i = 0; i < num_vertices; ++i) if (src_mask[i] != 0) break;
817 if (i == num_vertices) return 0;
818 }
819
820 double const tol = 1e-9;
821
823 (cell_type == YAC_LON_LAT_CELL) || (cell_type == YAC_GREAT_CIRCLE_CELL),
824 "ERROR(compute_weights_bary_no): barycentric coordinates "
825 "are only supported for great circle edge cells and lon lat cells")
826
827 if (cell_type == YAC_LON_LAT_CELL) {
828
829 // compute weights
830 compute_weights_bary_reg(tgt_coords, src_coords, weights);
831
832 for (int i = 0; i < 4; ++i) if (weights[i] < tol) weights[i] = 0.0;
833
834 // check if any of the source points is masked
835 if (src_mask != NULL)
836 for (int i = 0; i < 4; ++i)
837 if (!src_mask[i] && (weights[i] != 0.0))
838 return 0;
839 return 1;
840
841 } else {
842
843 size_t corner_indices[num_vertices];
844 size_t triangle_indices[num_vertices-2][3];
845
846 for (size_t i = 0; i < num_vertices; ++i) corner_indices[i] = i;
847
848 // triangulate source polygon
849 if (num_vertices > 3) {
851 corner_indices, num_vertices, 0, triangle_indices);
852 } else {
853 for (size_t i = 0; i < 3; ++i) triangle_indices[0][i] = i;
854 }
855
856 // find the best matching triangle
857 double min_barycentric_coord = -DBL_MAX;
858 double barycentric_coords[3];
859 size_t match_index = SIZE_MAX;
860
861 for (size_t i = 0; i < num_vertices - 2; ++i) {
862
863 double temp_barycentric_coords[3];
864 memcpy(temp_barycentric_coords, tgt_coords, 3 * sizeof(double));
865
866 // compute barycentric coordinates for the current triangle
868 temp_barycentric_coords, triangle_indices[i], src_coords,
869 "compute_weights_bary_no");
870
871 double curr_min_barycentric_coord =
872 MIN(temp_barycentric_coords[0],
873 MIN(temp_barycentric_coords[1],
874 temp_barycentric_coords[2]));
875
876 if (curr_min_barycentric_coord > min_barycentric_coord) {
877 min_barycentric_coord = curr_min_barycentric_coord;
878 match_index = i;
879 for (int j = 0; j < 3; ++j)
880 barycentric_coords[j] = MAX(0.0, temp_barycentric_coords[j]);
881 }
882 }
883
884 // initialise weights
885 if (num_vertices > 3)
886 for (size_t j = 0; j < num_vertices; ++j) weights[j] = 0.0;
887
888 // apply mask
889 if (src_mask != NULL)
890 for (int j = 0; j < 3; ++j)
891 if (!src_mask[triangle_indices[match_index][j]] &&
892 (barycentric_coords[j] >= 1e-4)) return 0;
893
894 double weight_sum = 0.0;
895 for (int j = 0; j < 3; ++j) {
896 if (barycentric_coords[j] < 1e-4) barycentric_coords[j] = 0.0;
897 else weight_sum += barycentric_coords[j];
898 }
899
900 if (weight_sum < tol) return 0;
901
902 double scale = 1.0 / weight_sum;
903
904 for (int j = 0; j < 3; ++j)
905 weights[triangle_indices[match_index][j]] =
906 barycentric_coords[j] * scale;
907
908 return 1;
909 }
910}
911
913 enum yac_interp_avg_weight_type weight_type, int partial_coverage) {
914
919 "ERROR(select_compute_weight_routine): invalid weight type")
920
921 switch(weight_type) {
923 return (partial_coverage)?compute_weights_avg_yes:compute_weights_avg_no;
925 return (partial_coverage)?compute_weights_dist_yes:compute_weights_dist_no;
927 default:
928 return (partial_coverage)?compute_weights_bary_yes:compute_weights_bary_no;
929 };
930}
931
934 int partial_coverage) {
935
936 struct interp_method_avg * method = xmalloc(1 * sizeof(*method));
937
939 method->compute_weights =
941
942 return (struct interp_method*)method;
943}
944
945static void delete_avg(struct interp_method * method) {
946 free(method);
947}
int yac_point_in_cell(double point_coords[3], struct yac_grid_cell cell)
static double const tol
enum yac_interp_ncc_weight_type weight_type
#define UNUSED(x)
Definition core.h:73
int const * const_int_pointer
size_t const *const const_size_t_pointer
yac_int const * const_yac_int_pointer
void yac_triangulate_cell_indices(size_t const *corner_indices, size_t num_corners, size_t start_corner, size_t(*triangle_indices)[3])
Definition grid_cell.c:144
#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 void XYZtoLL(double const p_in[], double *lon, double *lat)
Definition geometry.h:304
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
yac_cell_type
Definition grid_cell.h:26
@ YAC_LAT_CELL
Definition grid_cell.h:28
@ YAC_LON_LAT_CELL
Definition grid_cell.h:27
@ YAC_GREAT_CIRCLE_CELL
Definition grid_cell.h:29
@ YAC_MIXED_CELL
Definition grid_cell.h:30
yac_edge_type
Definition grid_cell.h:12
@ YAC_GREAT_CIRCLE_EDGE
great circle
Definition grid_cell.h:13
@ YAC_LAT_CIRCLE_EDGE
latitude circle
Definition grid_cell.h:14
void yac_interp_grid_do_points_search(struct yac_interp_grid *interp_grid, yac_coordinate_pointer search_coords, size_t count, size_t *src_cells)
size_t yac_interp_grid_get_num_src_fields(struct yac_interp_grid *interp_grid)
const_int_pointer yac_interp_grid_get_src_field_mask(struct yac_interp_grid *interp_grid, size_t src_field_idx)
void yac_interp_grid_get_aux_grid_src(struct yac_interp_grid *interp_grid, size_t *cells, size_t count, size_t **vertex_to_cell, size_t **vertex_to_cell_offsets, int **num_cells_per_vertex)
const_yac_int_pointer yac_interp_grid_get_src_field_global_ids(struct yac_interp_grid *interp_grid, size_t src_field_idx)
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)
yac_const_coordinate_pointer yac_interp_grid_get_src_field_coords(struct yac_interp_grid *interp_grid, size_t src_field_idx)
void yac_interp_grid_get_tgt_coordinates(struct yac_interp_grid *interp_grid, size_t *tgt_points, size_t count, yac_coordinate_pointer tgt_coordinates)
struct yac_const_basic_grid_data * yac_interp_grid_get_basic_grid_data_src(struct yac_interp_grid *interp_grid)
static int compute_weights_avg_no(double tgt_coords[3], size_t num_vertices, yac_const_coordinate_pointer src_coords, int *src_mask, double *weights, enum yac_cell_type cell_type)
static int compute_weights_avg_yes(double tgt_coords[3], size_t num_vertices, yac_const_coordinate_pointer src_coords, int *src_mask, double *weights, enum yac_cell_type cell_type)
static int check_src_field_cell(double *point, size_t field_cell, size_t cell_size, size_t const *vertex_to_cell, size_t const *vertex_to_cell_offsets, yac_const_coordinate_pointer field_coordinates, struct yac_grid_cell *cell_buffer)
static struct interp_method_vtable interp_method_avg_vtable
static void get_point_lon_lat(double point_coord[3], double cell_lon[2], double cell_lat[2], double *point_lon, double *point_lat)
int(* func_compute_weights)(double[3], size_t, yac_const_coordinate_pointer, int *, double *, enum yac_cell_type cell_type)
struct interp_method * yac_interp_method_avg_new(enum yac_interp_avg_weight_type weight_type, int partial_coverage)
static func_compute_weights select_compute_weight_routine(enum yac_interp_avg_weight_type weight_type, int partial_coverage)
static int compute_weights_dist_no(double tgt_coords[3], size_t num_vertices, yac_const_coordinate_pointer src_coords, int *src_mask, double *weights, enum yac_cell_type cell_type)
static int compute_weights_bary_no(double tgt_coords[3], size_t num_vertices, yac_const_coordinate_pointer src_coords, int *src_mask, double *weights, enum yac_cell_type cell_type)
static void compute_barycentric_coords(double *barycentric_coords, size_t triangle_indices[3], yac_const_coordinate_pointer grid_coords, char const *caller)
static int determine_triangle_idx(double point_lon, double point_lat, double cell_lon[2], double cell_lat[2])
#define IS_LON_LAT(x)
static int compute_weights_dist_yes(double tgt_coords[3], size_t num_vertices, yac_const_coordinate_pointer src_coords, int *src_mask, double *weights, enum yac_cell_type cell_type)
static void delete_avg(struct interp_method *method)
static int get_lat_edge_ordering(double const *a, double const *b)
static size_t do_search_avg(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 get_cell_lon_lat_bounds(yac_const_coordinate_pointer coords, double lon[2], double lat[2], int reorder[4])
static enum yac_cell_type determine_cell_type(enum yac_edge_type const *edge_types, size_t const *edge_indices, size_t num_edges)
static int compute_weights_bary_yes(double tgt_coords[3], size_t num_vertices, yac_const_coordinate_pointer src_coords, int *src_mask, double *weights, enum yac_cell_type cell_type)
static void compute_weights_bary_reg(double tgt_coords[3], yac_const_coordinate_pointer src_coords, double *weights)
yac_interp_avg_weight_type
@ YAC_INTERP_AVG_DIST
@ YAC_INTERP_AVG_ARITHMETIC
@ YAC_INTERP_AVG_BARY
static void compute_weights(struct tgt_point_search_data *tgt_point_data, size_t num_tgt_points, struct edge_interp_data *edge_data, size_t num_edges, struct triangle_interp_data *triangle_data, size_t num_triangles, struct weight_vector_data **weights, size_t **num_weights_per_tgt, size_t *total_num_weights)
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)
yac_location
Definition location.h:12
@ YAC_LOC_CORNER
Definition location.h:15
@ YAC_LOC_CELL
Definition location.h:14
#define xrealloc(ptr, size)
Definition ppm_xfuncs.h:67
#define xmalloc(size)
Definition ppm_xfuncs.h:66
struct interp_method_vtable * vtable
func_compute_weights compute_weights
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
const_size_t_pointer cell_to_vertex_offsets
const_size_t_pointer cell_to_vertex
const const_int_pointer num_vertices_per_cell
const_size_t_pointer cell_to_edge
const_size_t_pointer cell_to_edge_offsets
const_yac_edge_type_pointer edge_type
size_t num_corners
Definition grid_cell.h:21
enum yac_edge_type * edge_type
Definition grid_cell.h:20
size_t array_size
Definition grid_cell.h:22
double(* coordinates_xyz)[3]
Definition grid_cell.h:19
#define MIN(a, b)
#define MAX(a, b)
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 YAC_ASSERT(exp, msg)
Definition yac_assert.h:16
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