YetAnotherCoupler 3.2.0_a
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 <string.h>
11
13#include "interp_method_ncc.h"
14
15static size_t do_search_ncc(struct interp_method * method,
16 struct yac_interp_grid * interp_grid,
17 size_t * tgt_points, size_t count,
18 struct yac_interp_weights * weights);
19static void delete_ncc(struct interp_method * method);
20
21typedef int (*func_compute_weights)(
22 double[3], size_t, yac_const_coordinate_pointer, int *, double *);
23
24static struct interp_method_vtable
28
34
35// determines for a given coordinate which corner of a specific
36// cell is the closest one
38 struct yac_const_basic_grid_data * grid_data, size_t cell,
39 double const coord[3]) {
40
41 size_t const * cell_to_vertex =
42 grid_data->cell_to_vertex + grid_data->cell_to_vertex_offsets[cell];
43 yac_const_coordinate_pointer corner_coords =
44 grid_data->vertex_coordinates;
45 size_t num_vertices = grid_data->num_vertices_per_cell[cell];
46 yac_int const * vertex_ids = grid_data->ids[YAC_LOC_CORNER];
47
48 double min_distance = DBL_MAX;
49 size_t min_vertex = SIZE_MAX;
50 yac_int min_vertex_id = XT_INT_MAX;
51
52 for (size_t i = 0; i < num_vertices; ++i) {
53 size_t curr_vertex = cell_to_vertex[i];
54 double curr_distance =
55 get_vector_angle(coord, corner_coords[curr_vertex]);
56 if (curr_distance < min_distance) {
57 min_distance = curr_distance;
58 min_vertex = curr_vertex;
59 min_vertex_id = vertex_ids[curr_vertex];
60 } else if ((curr_distance == min_distance) &&
61 (vertex_ids[curr_vertex] < min_vertex_id)) {
62
63 min_vertex = curr_vertex;
64 min_vertex_id = vertex_ids[curr_vertex];
65 }
66 }
67 return min_vertex;
68}
69
70static size_t do_search_ncc (struct interp_method * method,
71 struct yac_interp_grid * interp_grid,
72 size_t * tgt_points, size_t count,
73 struct yac_interp_weights * weights) {
74
75 struct interp_method_ncc * method_ncc = (struct interp_method_ncc *)method;
76
78 yac_interp_grid_get_num_src_fields(interp_grid) == 1,
79 "ERROR(do_search_ncc): invalid number of source fields")
80
83 "ERROR(do_search_ncc): unsupported source field location type "
84 "(has to be CELL)")
85
86 // get coordinates of target points
87 yac_coordinate_pointer tgt_coords = xmalloc(count * sizeof(*tgt_coords));
89 interp_grid, tgt_points, count, tgt_coords);
90
91 size_t * size_t_buffer = xmalloc(3 * count * sizeof(*size_t_buffer));
92 size_t * src_cells = size_t_buffer;
93 size_t * src_corners = src_cells;
94 size_t * reorder_idx = size_t_buffer + count;
95 size_t * interp_flag = size_t_buffer + 2 * count;
96
97 // get matching source cells for all target points
99 interp_grid, tgt_coords, count, src_cells);
100
101 // sort target points, for which we found a source cell, to the beginning of
102 // the array
103 for (size_t i = 0; i < count; ++i) reorder_idx[i] = i;
104 yac_quicksort_index_size_t_size_t(src_cells, count, reorder_idx);
105
106 size_t result_count = 0;
107 for (result_count = 0; result_count < count; ++result_count)
108 if (src_cells[result_count] == SIZE_MAX) break;
109 for (size_t i = result_count; i < count; ++i)
110 interp_flag[reorder_idx[i]] = SIZE_MAX;
111
112 // for each target point find the closest corner of its source cell
113 {
114 struct yac_const_basic_grid_data * src_grid_data =
116 for (size_t i = 0; i < result_count; ++i)
117 src_corners[i] =
119 src_grid_data, src_cells[i], tgt_coords[reorder_idx[i]]);
120 }
121
122 // sort source corners
124 src_corners, result_count, reorder_idx);
125
126 // count number of unique source corners
127 size_t num_unique_src_corners = 0;
128 for (size_t i = 0, prev_src_corner = SIZE_MAX; i < result_count; ++i) {
129 size_t curr_src_corner = src_corners[i];
130 if (prev_src_corner != curr_src_corner) {
131 prev_src_corner = curr_src_corner;
132 ++num_unique_src_corners;
133 }
134 }
135
136 // count number of target points per unique source corner and
137 // remove duplicated corners
138 size_t * num_tgt_per_corner =
139 xcalloc(num_unique_src_corners, sizeof(*num_tgt_per_corner));
140 num_unique_src_corners = 0;
141 for (size_t i = 0, prev_src_corner = SIZE_MAX; i < result_count; ++i) {
142 size_t curr_src_corner = src_corners[i];
143 if (prev_src_corner != curr_src_corner) {
144 prev_src_corner = curr_src_corner;
145 src_corners[num_unique_src_corners] = curr_src_corner;
146 ++num_unique_src_corners;
147 }
148 num_tgt_per_corner[num_unique_src_corners-1]++;
149 }
150
151 // get all source cells associated with each unique source corner;
152 // results cells for each corner are sorted by their global id
153 size_t * src_corner_cells;
154 size_t * num_cells_per_corner =
155 xmalloc(num_unique_src_corners * sizeof(*num_cells_per_corner));
157 interp_grid, src_corners, num_unique_src_corners, &src_corner_cells,
158 num_cells_per_corner);
159
160 // get maximum number of source cells per target
161 size_t max_num_cell_per_corner = 0;
162 size_t total_num_weights = 0;
163 for (size_t i = 0; i < num_unique_src_corners; ++i) {
164 if (max_num_cell_per_corner < num_cells_per_corner[i])
165 max_num_cell_per_corner = num_cells_per_corner[i];
166 total_num_weights += num_cells_per_corner[i] * num_tgt_per_corner[i];
167 }
168
169 yac_const_coordinate_pointer src_field_coordinates =
171 const_int_pointer src_field_mask =
173
174 yac_coordinate_pointer src_coord_buffer =
175 xmalloc(max_num_cell_per_corner * sizeof(*src_coord_buffer));
176 int * mask_buffer =
177 (src_field_mask != NULL)?
178 xmalloc(max_num_cell_per_corner * sizeof(*mask_buffer)):NULL;
179 double * w = xmalloc(total_num_weights * sizeof(*w));
180 size_t * src_points = xmalloc(total_num_weights * sizeof(*src_points));
181 size_t * num_weights_per_tgt =
182 xmalloc(result_count * sizeof(*num_weights_per_tgt));
183
184 // for each target point, extract relevant source data and compute the weights
185 // based on that
187 total_num_weights = 0;
188 result_count = 0;
189 for (size_t i = 0, l = 0, src_corner_cell_offset = 0;
190 i < num_unique_src_corners; ++i) {
191
192 size_t curr_num_cells = num_cells_per_corner[i];
193
194 const_size_t_pointer curr_src_corner_cells =
195 src_corner_cells + src_corner_cell_offset;
196 src_corner_cell_offset += curr_num_cells;
197
198 // get field coordinates and mask values for current source cells
199 for (size_t j = 0; j < curr_num_cells; ++j) {
200 size_t const curr_src_cell = curr_src_corner_cells[j];
201 for (size_t k = 0; k < 3; ++k)
202 src_coord_buffer[j][k] = src_field_coordinates[curr_src_cell][k];
203 if (src_field_mask != NULL)
204 mask_buffer[j] = src_field_mask[curr_src_cell];
205 }
206
207 for (size_t j = 0; j < num_tgt_per_corner[i]; ++j, ++l) {
208
209 // compute weights
210 if (compute_weights(
211 tgt_coords[reorder_idx[l]], curr_num_cells,
212 (yac_const_coordinate_pointer)src_coord_buffer,
213 mask_buffer, w + total_num_weights)) {
214
215 interp_flag[reorder_idx[l]] = result_count;
216 memcpy(
217 src_points + total_num_weights, curr_src_corner_cells,
218 curr_num_cells * sizeof(*src_points));
219 num_weights_per_tgt[result_count] = curr_num_cells;
220 total_num_weights += curr_num_cells;
221 result_count++;
222 } else {
223 interp_flag[reorder_idx[l]] = SIZE_MAX;
224 }
225 }
226 }
227
228 free(num_cells_per_corner);
229
230 // move target points for which the interpolation failed to the end of
231 // the array while keeping the origin order for the remaining target points
232 yac_quicksort_index_size_t_size_t(interp_flag, count, tgt_points);
233
234 free(tgt_coords);
235 free(mask_buffer);
236 free(src_coord_buffer);
237 free(size_t_buffer);
238
239 struct remote_points tgts = {
240 .data =
242 interp_grid, tgt_points, result_count),
243 .count = result_count};
244 struct remote_point * srcs =
246 interp_grid, 0, src_points, total_num_weights);
247
248 // store weights
250 weights, &tgts, num_weights_per_tgt, srcs, w);
251
252 free(tgts.data);
253 free(srcs);
254 free(w);
255 free(num_weights_per_tgt);
256 free(src_points);
257
258 return result_count;
259}
260
262 double tgt_coords[3], size_t num_src,
263 yac_const_coordinate_pointer src_coords, int * src_mask, double * weights) {
264
265 UNUSED(src_coords);
266
267 size_t num_unmasked_points = 0;
268
269 // if we have a source mask, check whether any points is masked
270 if (src_mask != NULL) {
271 for (size_t i = 0; i < num_src; ++i)
272 if (src_mask[i]) num_unmasked_points++;
273 if (num_unmasked_points == 0) return 0;
274
275 double weight = 1.0 / (double)num_unmasked_points;
276 for (size_t i = 0; i < num_src; ++i)
277 weights[i] = (src_mask[i])?weight:0.0;
278
279 } else {
280 double weight = 1.0 / (double)num_src;
281 for (size_t i = 0; i < num_src; ++i) weights[i] = weight;
282 }
283 return 1;
284}
285
287 double tgt_coords[3], size_t num_src,
288 yac_const_coordinate_pointer src_coords, int * src_mask, double * weights) {
289
290 UNUSED(src_coords);
291
292 // if we have a source mask, check whether any points is masked
293 if (src_mask != NULL)
294 for (size_t i = 0; i < num_src; ++i)
295 if (!src_mask[i]) return 0;
296
297 double weight = 1.0 / (double)num_src;
298 for (size_t i = 0; i < num_src; ++i) weights[i] = weight;
299
300 return 1;
301}
302
304 double tgt_coords[3], size_t num_src,
305 yac_const_coordinate_pointer src_coords, int * src_mask, double * weights) {
306
307 // if there is a source mask, check if there are unmasked vertices
308 if (src_mask != NULL) {
309 int has_unmasked = 0;
310 for (size_t i = 0; i < num_src; ++i) has_unmasked |= src_mask[i];
311 if (!has_unmasked) return 0;
312 }
313
314 if (src_mask != NULL) {
315 for (size_t i = 0; i < num_src; ++i) {
316
317 if (src_mask[i]) {
318
319 double distance =
320 get_vector_angle(tgt_coords, (double*)(src_coords[i]));
321
322 // if the target and source point are nearly identical
323 if (distance < yac_angle_tol) {
324 for (size_t j = 0; j < num_src; ++j) weights[j] = 0.0;
325 weights[i] = 1.0;
326 return 1;
327 }
328
329 weights[i] = 1.0 / distance;
330 } else {
331 weights[i] = 0.0;
332 }
333 }
334 } else {
335 for (size_t i = 0; i < num_src; ++i) {
336
337 double distance =
338 get_vector_angle(tgt_coords, (double*)(src_coords[i]));
339
340 // if the target and source point are nearly identical
341 if (distance < yac_angle_tol) {
342 for (size_t j = 0; j < num_src; ++j) weights[j] = 0.0;
343 weights[i] = 1.0;
344 return 1;
345 }
346
347 weights[i] = 1.0 / distance;
348 }
349 }
350
351 // compute scaling factor for the weights
352 double inv_distance_sum = 0.0;
353 for (size_t i = 0; i < num_src; ++i)
354 inv_distance_sum += weights[i];
355 double scale = 1.0 / inv_distance_sum;
356
357 for (size_t i = 0; i < num_src; ++i) weights[i] *= scale;
358
359 return 1;
360}
361
363 double tgt_coords[3], size_t num_src,
364 yac_const_coordinate_pointer src_coords, int * src_mask, double * weights) {
365
366 for (size_t i = 0; i < num_src; ++i) {
367
368 double distance =
369 get_vector_angle(tgt_coords, (double*)(src_coords[i]));
370
371 // if the target and source point are nearly identical
372 if (distance < yac_angle_tol) {
373 if ((src_mask != NULL) && !src_mask[i]) return 0;
374 for (size_t j = 0; j < num_src; ++j) weights[j] = 0.0;
375 weights[i] = 1.0;
376 return 1;
377 }
378
379 weights[i] = 1.0 / distance;
380 }
381
382 // if there is a source mask, check if there are masked vertices
383 // (we do this here because there may be a matching source point
384 // that is not masked)
385 if (src_mask != NULL)
386 for (size_t i = 0; i < num_src; ++i) if(!src_mask[i]) return 0;
387
388 // compute scaling factor for the weights
389 double inv_distance_sum = 0.0;
390 for (size_t i = 0; i < num_src; ++i)
391 inv_distance_sum += weights[i];
392 double scale = 1.0 / inv_distance_sum;
393
394 for (size_t i = 0; i < num_src; ++i) weights[i] *= scale;
395
396 return 1;
397}
398
400 enum yac_interp_ncc_weight_type weight_type, int partial_coverage) {
401
403 (weight_type == YAC_INTERP_NCC_AVG) ||
404 (weight_type == YAC_INTERP_NCC_DIST),
405 "ERROR(select_compute_weight_routine): invalid weight type")
406
407 switch(weight_type) {
408 case(YAC_INTERP_NCC_AVG):
409 return
412 default:
413 return
415 };
416}
417
419 enum yac_interp_ncc_weight_type weight_type,
420 int partial_coverage) {
421
422 struct interp_method_ncc * method = xmalloc(1 * sizeof(*method));
423
425 method->compute_weights =
426 select_compute_weight_routine(weight_type, partial_coverage);
427
428 return (struct interp_method*)method;
429}
430
431static void delete_ncc(struct interp_method * method) {
432 free(method);
433}
#define UNUSED(x)
Definition core.h:71
size_t const *const const_size_t_pointer
int const *const const_int_pointer
#define yac_angle_tol
Definition geometry.h:34
static double get_vector_angle(double const a[3], double const b[3])
Definition geometry.h:364
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)
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_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)
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)
struct interp_method * yac_interp_method_ncc_new(enum yac_interp_ncc_weight_type weight_type, int partial_coverage)
static size_t get_closest_src_corner(struct yac_const_basic_grid_data *grid_data, size_t cell, double const coord[3])
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 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 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)
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)
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
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
@ YAC_LOC_CELL
Definition location.h:14
#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)
struct remote_point * data
const_int_pointer num_vertices_per_cell
const_size_t_pointer cell_to_vertex_offsets
const_size_t_pointer cell_to_vertex
const_yac_int_pointer ids[3]
yac_const_coordinate_pointer vertex_coordinates
void yac_quicksort_index_size_t_size_t(size_t *a, size_t n, size_t *idx)
#define YAC_ASSERT(exp, msg)
Definition yac_assert.h:15
Xt_int yac_int
Definition yac_types.h:15
double const (*const yac_const_coordinate_pointer)[3]
Definition yac_types.h:20
double(* yac_coordinate_pointer)[3]
Definition yac_types.h:19