YAC 3.21.0
Yet Another Coupler
Loading...
Searching...
No Matches
interp_method_ncc.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 <limits.h>
11#include <string.h>
12
20#include "instrument_internal.h"
21#include "yac_mpi_common.h"
22
23static size_t do_search_ncc(struct interp_method * method,
24 struct yac_interp_grid * interp_grid,
25 size_t * tgt_points, size_t count,
26 struct yac_interp_weights * weights,
27 int * interpolation_compelte);
28static void delete_ncc(struct interp_method * method);
29
30typedef int (*func_compute_weights)(
31 double[3], size_t, yac_const_coordinate_pointer, int *, double *);
32
33static struct interp_method_vtable
37
43
44// determines for a given coordinate which corner of a specific
45// cell is the closest one
47 struct yac_const_basic_grid_data * grid_data, size_t cell,
48 double const coord[3]) {
49
50 size_t const * cell_to_vertex =
51 grid_data->cell_to_vertex + grid_data->cell_to_vertex_offsets[cell];
52 yac_const_coordinate_pointer corner_coords =
53 grid_data->vertex_coordinates;
54 size_t num_vertices = grid_data->num_vertices_per_cell[cell];
55 yac_int const * vertex_ids = grid_data->ids[YAC_LOC_CORNER];
56
57 double min_distance = DBL_MAX;
58 size_t min_vertex = SIZE_MAX;
59 yac_int min_vertex_id = YAC_INT_MAX;
60
61 for (size_t i = 0; i < num_vertices; ++i) {
62 size_t curr_vertex = cell_to_vertex[i];
63 double curr_distance =
64 get_vector_angle(coord, corner_coords[curr_vertex]);
65 if (curr_distance < min_distance) {
66 min_distance = curr_distance;
67 min_vertex = curr_vertex;
68 min_vertex_id = vertex_ids[curr_vertex];
69 } else if ((curr_distance == min_distance) &&
70 (vertex_ids[curr_vertex] < min_vertex_id)) {
71
72 min_vertex = curr_vertex;
73 min_vertex_id = vertex_ids[curr_vertex];
74 }
75 }
76 return min_vertex;
77}
78
79static size_t do_search_ncc (struct interp_method * method,
80 struct yac_interp_grid * interp_grid,
81 size_t * tgt_points, size_t count,
82 struct yac_interp_weights * weights,
83 int * interpolation_complete) {
84
85 if (*interpolation_complete) return 0;
86
87 YAC_INSTRUMENT_START(YAC_INSTR_INTERP_SEARCH_NCC);
88
89 struct interp_method_ncc * method_ncc = (struct interp_method_ncc *)method;
90
92
94
95 // get coordinates of target points
96 yac_coordinate_pointer tgt_coords = xmalloc(count * sizeof(*tgt_coords));
98 interp_grid, tgt_points, count, tgt_coords);
99
100 size_t * size_t_buffer = xmalloc(3 * count * sizeof(*size_t_buffer));
101 size_t * src_cells = size_t_buffer;
102 size_t * src_corners = src_cells;
103 size_t * reorder_idx = size_t_buffer + count;
104 size_t * interp_flag = size_t_buffer + 2 * count;
105
106 // get matching source cells for all target points
108 interp_grid, tgt_coords, count, src_cells);
109
110 // sort target points, for which we found a source cell, to the beginning of
111 // the array
112 for (size_t i = 0; i < count; ++i) reorder_idx[i] = i;
113 yac_quicksort_index_size_t_size_t(src_cells, count, reorder_idx);
114
115 size_t result_count = 0;
116 for (result_count = 0; result_count < count; ++result_count)
117 if (src_cells[result_count] == SIZE_MAX) break;
118 for (size_t i = result_count; i < count; ++i)
119 interp_flag[reorder_idx[i]] = SIZE_MAX;
120
121 // for each target point find the closest corner of its source cell
122 {
123 struct yac_const_basic_grid_data * src_grid_data =
125 for (size_t i = 0; i < result_count; ++i)
126 src_corners[i] =
128 src_grid_data, src_cells[i], tgt_coords[reorder_idx[i]]);
129 }
130
131 // sort source corners
133 src_corners, result_count, reorder_idx);
134
135 // count number of unique source corners
136 size_t num_unique_src_corners = 0;
137 for (size_t i = 0, prev_src_corner = SIZE_MAX; i < result_count; ++i) {
138 size_t curr_src_corner = src_corners[i];
139 if (prev_src_corner != curr_src_corner) {
140 prev_src_corner = curr_src_corner;
141 ++num_unique_src_corners;
142 }
143 }
144
145 // count number of target points per unique source corner and
146 // remove duplicated corners
147 size_t * num_tgt_per_corner =
148 xcalloc(num_unique_src_corners, sizeof(*num_tgt_per_corner));
149 num_unique_src_corners = 0;
150 for (size_t i = 0, prev_src_corner = SIZE_MAX; i < result_count; ++i) {
151 size_t curr_src_corner = src_corners[i];
152 if (prev_src_corner != curr_src_corner) {
153 prev_src_corner = curr_src_corner;
154 src_corners[num_unique_src_corners] = curr_src_corner;
155 ++num_unique_src_corners;
156 }
157 num_tgt_per_corner[num_unique_src_corners-1]++;
158 }
159
160 // get all source cells associated with each unique source corner;
161 // results cells for each corner are sorted by their global id
162 size_t * src_corner_cells = NULL;
163 size_t * num_cells_per_corner =
164 xmalloc(num_unique_src_corners * sizeof(*num_cells_per_corner));
166 interp_grid, src_corners, num_unique_src_corners, &src_corner_cells,
167 num_cells_per_corner);
168
169 // get maximum number of source cells per target
170 size_t max_num_cell_per_corner = 0;
171 size_t total_num_weights = 0;
172 for (size_t i = 0; i < num_unique_src_corners; ++i) {
173 if (max_num_cell_per_corner < num_cells_per_corner[i])
174 max_num_cell_per_corner = num_cells_per_corner[i];
175 total_num_weights += num_cells_per_corner[i] * num_tgt_per_corner[i];
176 }
177
178 yac_const_coordinate_pointer src_field_coordinates =
180 const_int_pointer src_field_mask =
182
183 yac_coordinate_pointer src_coord_buffer =
184 xmalloc(max_num_cell_per_corner * sizeof(*src_coord_buffer));
185 int * mask_buffer =
186 (src_field_mask != NULL)?
187 xmalloc(max_num_cell_per_corner * sizeof(*mask_buffer)):NULL;
188 double * w = xmalloc(total_num_weights * sizeof(*w));
189 size_t * src_points = xmalloc(total_num_weights * sizeof(*src_points));
190 size_t * num_weights_per_tgt =
191 xmalloc(result_count * sizeof(*num_weights_per_tgt));
192
193 // for each target point, extract relevant source data and compute the weights
194 // based on that
195 func_compute_weights compute_weights = method_ncc->compute_weights;
196 total_num_weights = 0;
197 result_count = 0;
198 for (size_t i = 0, l = 0, src_corner_cell_offset = 0;
199 i < num_unique_src_corners; ++i) {
200
201 size_t curr_num_cells = num_cells_per_corner[i];
202
203 const_size_t_pointer curr_src_corner_cells =
204 src_corner_cells + src_corner_cell_offset;
205 src_corner_cell_offset += curr_num_cells;
206
207 // get field coordinates and mask values for current source cells
208 for (size_t j = 0; j < curr_num_cells; ++j) {
209 size_t const curr_src_cell = curr_src_corner_cells[j];
210 for (size_t k = 0; k < 3; ++k)
211 src_coord_buffer[j][k] = src_field_coordinates[curr_src_cell][k];
212 if (src_field_mask != NULL)
213 mask_buffer[j] = src_field_mask[curr_src_cell];
214 }
215
216 for (size_t j = 0; j < num_tgt_per_corner[i]; ++j, ++l) {
217
218 // compute weights
219 if (compute_weights(
220 tgt_coords[reorder_idx[l]], curr_num_cells,
221 (yac_const_coordinate_pointer)src_coord_buffer,
222 mask_buffer, w + total_num_weights)) {
223
224 interp_flag[reorder_idx[l]] = result_count;
225 memcpy(
226 src_points + total_num_weights, curr_src_corner_cells,
227 curr_num_cells * sizeof(*src_points));
228 num_weights_per_tgt[result_count] = curr_num_cells;
229 total_num_weights += curr_num_cells;
230 result_count++;
231 } else {
232 interp_flag[reorder_idx[l]] = SIZE_MAX;
233 }
234 }
235 }
236
237 free(src_corner_cells);
238 free(num_tgt_per_corner);
239 free(num_cells_per_corner);
240
241 // move target points for which the interpolation failed to the end of
242 // the array while keeping the origin order for the remaining target points
243 yac_quicksort_index_size_t_size_t(interp_flag, count, tgt_points);
244
245 free(tgt_coords);
246 free(mask_buffer);
247 free(src_coord_buffer);
248 free(size_t_buffer);
249
250 struct remote_points tgts = {
251 .data =
253 interp_grid, tgt_points, result_count),
254 .count = result_count};
255 struct remote_point * srcs =
257 interp_grid, 0, src_points, total_num_weights);
258
259 // store weights
261 weights, &tgts, num_weights_per_tgt, srcs, w);
262
263 free(tgts.data);
264 free(srcs);
265 free(w);
266 free(num_weights_per_tgt);
267 free(src_points);
268
269 YAC_INSTRUMENT_STOP(YAC_INSTR_INTERP_SEARCH_NCC);
270
271 return result_count;
272}
273
275 double tgt_coords[3], size_t num_src,
276 yac_const_coordinate_pointer src_coords, int * src_mask, double * weights) {
277
278 UNUSED(tgt_coords);
279 UNUSED(src_coords);
280
281 size_t num_unmasked_points = 0;
282
283 // if we have a source mask, check whether any points is masked
284 if (src_mask != NULL) {
285 for (size_t i = 0; i < num_src; ++i)
286 if (src_mask[i]) num_unmasked_points++;
287 if (num_unmasked_points == 0) return 0;
288
289 double weight = 1.0 / (double)num_unmasked_points;
290 for (size_t i = 0; i < num_src; ++i)
291 weights[i] = (src_mask[i])?weight:0.0;
292
293 } else {
294 double weight = 1.0 / (double)num_src;
295 for (size_t i = 0; i < num_src; ++i) weights[i] = weight;
296 }
297 return 1;
298}
299
301 double tgt_coords[3], size_t num_src,
302 yac_const_coordinate_pointer src_coords, int * src_mask, double * weights) {
303
304 UNUSED(tgt_coords);
305 UNUSED(src_coords);
306
307 // if we have a source mask, check whether any points is masked
308 if (src_mask != NULL)
309 for (size_t i = 0; i < num_src; ++i)
310 if (!src_mask[i]) return 0;
311
312 double weight = 1.0 / (double)num_src;
313 for (size_t i = 0; i < num_src; ++i) weights[i] = weight;
314
315 return 1;
316}
317
319 double tgt_coords[3], size_t num_src,
320 yac_const_coordinate_pointer src_coords, int * src_mask, double * weights) {
321
322 // if there is a source mask, check if there are unmasked vertices
323 if (src_mask != NULL) {
324 int has_unmasked = 0;
325 for (size_t i = 0; i < num_src; ++i) has_unmasked |= src_mask[i];
326 if (!has_unmasked) return 0;
327 }
328
329 if (src_mask != NULL) {
330 for (size_t i = 0; i < num_src; ++i) {
331
332 if (src_mask[i]) {
333
334 double distance =
335 get_vector_angle(tgt_coords, (double*)(src_coords[i]));
336
337 // if the target and source point are nearly identical
338 if (distance < yac_angle_tol) {
339 for (size_t j = 0; j < num_src; ++j) weights[j] = 0.0;
340 weights[i] = 1.0;
341 return 1;
342 }
343
344 weights[i] = 1.0 / distance;
345 } else {
346 weights[i] = 0.0;
347 }
348 }
349 } else {
350 for (size_t i = 0; i < num_src; ++i) {
351
352 double distance =
353 get_vector_angle(tgt_coords, (double*)(src_coords[i]));
354
355 // if the target and source point are nearly identical
356 if (distance < yac_angle_tol) {
357 for (size_t j = 0; j < num_src; ++j) weights[j] = 0.0;
358 weights[i] = 1.0;
359 return 1;
360 }
361
362 weights[i] = 1.0 / distance;
363 }
364 }
365
366 // compute scaling factor for the weights
367 double inv_distance_sum = 0.0;
368 for (size_t i = 0; i < num_src; ++i)
369 inv_distance_sum += weights[i];
370 double scale = 1.0 / inv_distance_sum;
371
372 for (size_t i = 0; i < num_src; ++i) weights[i] *= scale;
373
374 return 1;
375}
376
378 double tgt_coords[3], size_t num_src,
379 yac_const_coordinate_pointer src_coords, int * src_mask, double * weights) {
380
381 for (size_t i = 0; i < num_src; ++i) {
382
383 double distance =
384 get_vector_angle(tgt_coords, (double*)(src_coords[i]));
385
386 // if the target and source point are nearly identical
387 if (distance < yac_angle_tol) {
388 if ((src_mask != NULL) && !src_mask[i]) return 0;
389 for (size_t j = 0; j < num_src; ++j) weights[j] = 0.0;
390 weights[i] = 1.0;
391 return 1;
392 }
393
394 weights[i] = 1.0 / distance;
395 }
396
397 // if there is a source mask, check if there are masked vertices
398 // (we do this here because there may be a matching source point
399 // that is not masked)
400 if (src_mask != NULL)
401 for (size_t i = 0; i < num_src; ++i) if(!src_mask[i]) return 0;
402
403 // compute scaling factor for the weights
404 double inv_distance_sum = 0.0;
405 for (size_t i = 0; i < num_src; ++i)
406 inv_distance_sum += weights[i];
407 double scale = 1.0 / inv_distance_sum;
408
409 for (size_t i = 0; i < num_src; ++i) weights[i] *= scale;
410
411 return 1;
412}
413
415 enum yac_interp_ncc_weight_type weight_type, int partial_coverage) {
416
419 (weight_type == YAC_INTERP_NCC_DIST), "invalid weight type")
420
421 switch(weight_type) {
422 case(YAC_INTERP_NCC_AVG):
423 return
426 default:
427 return
429 };
430}
431
434 int partial_coverage) {
435
436 struct interp_method_ncc * method = xmalloc(1 * sizeof(*method));
437
439 method->compute_weights =
441
442 return (struct interp_method*)method;
443}
444
445static void delete_ncc(struct interp_method * method) {
446 free(method);
447}
448
449// --- Modular config struct and vtable for NCC method ---
450
465
468 free(config);
469}
470
472 const struct yac_interp_method_config *config) {
474 struct yac_interp_method_config_ncc *copy =
475 xmalloc(sizeof(*copy));
476 copy->base.vtable = config_ncc->base.vtable;
477 copy->base.root_param_cache = NULL;
478 copy->config = config_ncc->config;
479 return (struct yac_interp_method_config *)copy;
480}
481
483 void const *a_, void const *b_) {
485 // Compare nearest corner cells interpolation options:
486 // 1. weight_type: averaging/weighting method
487 CHECK_ENUM(config.weight_type);
488 // 2. partial_coverage: allow partial source cell coverage
489 CHECK_INT(config.partial_coverage);
490 return 0;
491}
492
493// Gets interpolation method typed_config_hcsbb_get_type
497
499 struct yac_interp_method_config const *config) {
500 const struct yac_interp_method_config_ncc *config_ncc =
501 (const struct yac_interp_method_config_ncc *)config;
503 config_ncc->config.weight_type,
504 config_ncc->config.partial_coverage);
505}
506
508 struct yac_interp_method_config const *config) {
509 struct yac_interp_method_config_ncc *config_ncc =
511
512 enum {
513 WEIGHTED_HAS_DEFAULT = 1,
514 WEIGHTED_IS_DEFINED = 1,
515 PARTIAL_COVERAGE_HAS_DEFAULT = 1,
516 PARTIAL_COVERAGE_IS_DEFINED = 1,
517 };
518
520 weighted_enum_table,
522 DEF_NAME_TYPE_PAIR(distance_weighted, YAC_INTERP_NCC_DIST))
523
524 struct yac_param *weighted_param =
526 "weighted",
527 (int *)&config_ncc->config.weight_type,
529 weighted_enum_table, weighted_enum_table_size,
530 WEIGHTED_HAS_DEFAULT, WEIGHTED_IS_DEFINED);
531
532 struct yac_param *partial_coverage_param =
534 "partial_coverage",
535 &config_ncc->config.partial_coverage,
537 PARTIAL_COVERAGE_HAS_DEFAULT, PARTIAL_COVERAGE_IS_DEFINED);
538
539 struct yac_param *root_param_array[] = {
540 weighted_param,
541 partial_coverage_param
542 };
543 enum {
544 ROOT_PARAM_ARRAY_SIZE =
545 sizeof(root_param_array) / sizeof(root_param_array[0])
546 };
547
549 "ncc", root_param_array, ROOT_PARAM_ARRAY_SIZE);
550}
551
560
562 struct yac_interp_method_config_ncc *config_ncc = xmalloc(sizeof(*config_ncc));
564 config_ncc->base.root_param_cache = NULL;
565 config_ncc->config = (struct yac_interp_method_ncc_config){
567 .partial_coverage = YAC_INTERP_NCC_PARTIAL_COVERAGE_DEFAULT,
568 };
569 return (struct yac_interp_method_config *)config_ncc;
570}
#define YAC_ASSERT(exp, msg)
#define UNUSED(x)
Definition core.h:72
int const * const_int_pointer
size_t const *const const_size_t_pointer
#define yac_angle_tol
Definition geometry.h:26
static double get_vector_angle(double const a[3], double const b[3])
Definition geometry.h:472
#define DEF_NAME_TYPE_PAIR(NAME, TYPE)
#define DEF_NAME_TYPE_PAIRS(NAME,...)
#define YAC_INSTRUMENT_START(ID)
Enter an instrumented region.
#define YAC_INSTRUMENT_STOP(ID)
Exit an instrumented region entered with YAC_INSTRUMENT_START(ID).
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)
const_int_pointer yac_interp_grid_get_src_field_mask(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)
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_src_corner_cells(struct yac_interp_grid *interp_grid, size_t *src_corners, size_t count, size_t **src_cells, size_t *num_cells_per_corner)
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)
yac_interpolation_list
@ YAC_NEAREST_CORNER_CELLS
Nearest-corner-cell interpolation.
#define DEF_INTERP_METHOD_CONFIG_COMPARE_TYPE(TYPE)
#define DEF_INTERP_METHOD_CONFIG_TYPE(TYPE)
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)
static int compute_weights_dist_no(double tgt_coords[3], size_t num_src, yac_const_coordinate_pointer src_coords, int *src_mask, double *weights)
static void delete_ncc(struct interp_method *method)
static int compute_weights_avg_yes(double tgt_coords[3], size_t num_src, yac_const_coordinate_pointer src_coords, int *src_mask, double *weights)
static struct yac_param * config_ncc_get_param(struct yac_interp_method_config const *config)
struct yac_interp_method_config * yac_interp_method_config_default_ncc_new(void)
Creates a nearest-corner-cells interpolation method configuration with default parameters.
static struct yac_interp_method_config_vtable yac_interp_method_config_vtable_ncc
struct interp_method * yac_interp_method_ncc_new(enum yac_interp_ncc_weight_type weight_type, int partial_coverage)
static int config_ncc_compare(void const *a_, void const *b_)
static size_t do_search_ncc(struct interp_method *method, struct yac_interp_grid *interp_grid, size_t *tgt_points, size_t count, struct yac_interp_weights *weights, int *interpolation_compelte)
static void config_ncc_delete(struct yac_interp_method_config *config)
static size_t get_closest_src_corner(struct yac_const_basic_grid_data *grid_data, size_t cell, double const coord[3])
static struct interp_method * config_ncc_generate(struct yac_interp_method_config const *config)
static func_compute_weights select_compute_weight_routine(enum yac_interp_ncc_weight_type weight_type, int partial_coverage)
static struct interp_method_vtable interp_method_ncc_vtable
int(* func_compute_weights)(double[3], size_t, yac_const_coordinate_pointer, int *, double *)
static enum yac_interpolation_list config_ncc_get_type()
static struct yac_interp_method_config * config_ncc_copy(const struct yac_interp_method_config *config)
static int compute_weights_avg_no(double tgt_coords[3], size_t num_src, yac_const_coordinate_pointer src_coords, int *src_mask, double *weights)
static int compute_weights_dist_yes(double tgt_coords[3], size_t num_src, yac_const_coordinate_pointer src_coords, int *src_mask, double *weights)
#define YAC_INTERP_NCC_PARTIAL_COVERAGE_DEFAULT
#define YAC_INTERP_NCC_WEIGHT_TYPE_DEFAULT
yac_interp_ncc_weight_type
@ YAC_INTERP_NCC_DIST
distance weighted average of n source points
@ YAC_INTERP_NCC_AVG
average of n source points
#define CHECK_SRC_FIELD_COUNT_SINGLE(INTERP_GRID)
#define CHECK_SRC_FIELD_LOCATION_CELL(INTERP_GRID)
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_LOC_CORNER
Definition location.h:15
struct yac_param * yac_param_bool_new(const char *name, int *value_ptr, int default_value, int has_default, int is_defined)
Create a bool parameter (backed by int)
Definition param_bool.c:159
struct yac_param * yac_param_enum_new(const char *name, int *value_ptr, int default_value, struct yac_name_type_pair const *enum_table, size_t enum_table_size, int has_default, int is_defined)
Create a new enum parameter for configuration.
Definition param_enum.c:148
struct yac_param * yac_param_struct_new(const char *name, struct yac_param **subparams, size_t subparam_count)
Create a new struct parameter with a given name and subparameters.
#define xcalloc(nmemb, size)
Definition ppm_xfuncs.h:64
#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
Concrete implementation of yac_interp_method_config for the NCC method.
struct yac_interp_method_config base
‍base config object, must be first entry
struct yac_interp_method_ncc_config config
‍method-specific configuration
void(* delete)(struct yac_interp_method_config *config)
struct yac_interp_method_config_vtable const * vtable
enum yac_interp_ncc_weight_type weight_type
int * cell_to_vertex
static struct yac_interp_method_config * config
void yac_quicksort_index_size_t_size_t(size_t *a, size_t n, size_t *idx)
double const (* yac_const_coordinate_pointer)[3]
Definition yac_types.h:22
YAC_INT yac_int
Definition yac_types.h:15
double(* yac_coordinate_pointer)[3]
Definition yac_types.h:21