YetAnotherCoupler 3.5.2
Loading...
Searching...
No Matches
interp_method_nnn.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_nnn.h"
15#include "yac_mpi_internal.h"
16
17static size_t do_search_nnn(struct interp_method * method,
18 struct yac_interp_grid * interp_grid,
19 size_t * tgt_points, size_t count,
20 struct yac_interp_weights * weights);
21static size_t do_search_1nn(struct interp_method * method,
22 struct yac_interp_grid * interp_grid,
23 size_t * tgt_points, size_t count,
24 struct yac_interp_weights * weights);
25static size_t do_search_zero(struct interp_method * method,
26 struct yac_interp_grid * interp_grid,
27 size_t * tgt_points, size_t count,
28 struct yac_interp_weights * weights);
29static void delete_nnn(struct interp_method * method);
30
31static struct interp_method_vtable
41
43
46 double[3], yac_coordinate_pointer, size_t const, double *, double const);
47 size_t n;
49 double scale;
50};
51
53
56 struct yac_interp_weights * weights, struct remote_points * tgts,
57 struct remote_point * srcs);
59};
60
65
67 double tgt_coord[3], yac_coordinate_pointer src_coords, size_t const n,
68 double * weights, double const dummy) {
69
70 UNUSED(tgt_coord);
71 UNUSED(src_coords);
72 UNUSED(dummy);
73
74 double weight = 1.0 / (double)n;
75 for (size_t i = 0; i < n; ++i) weights[i] = weight;
76}
77
79 double tgt_coord[3], yac_coordinate_pointer src_coords, size_t const n,
80 double * weights, double const dummy) {
81
82 UNUSED(dummy);
83
84 for (size_t i = 0; i < n; ++i) {
85
86 double distance = get_vector_angle(tgt_coord, (double*)(src_coords[i]));
87
88 // if the target and source point are nearly identical
89 if (distance < yac_angle_tol) {
90 for (size_t j = 0; j < n; ++j) weights[j] = 0.0;
91 weights[i] = 1.0;
92 return;
93 }
94
95 weights[i] = 1.0 / distance;
96 }
97
98 // compute scaling factor for the weights
99 double inv_distance_sum = 0.0;
100 for (size_t i = 0; i < n; ++i) inv_distance_sum += weights[i];
101 double scale = 1.0 / inv_distance_sum;
102
103 for (size_t i = 0; i < n; ++i) weights[i] *= scale;
104}
105
107 double tgt_coord[3], yac_coordinate_pointer src_coords, size_t const n,
108 double * weights, double const gauss_scale) {
109
110 for (size_t i = 0; i < n; ++i) {
111
112 double distance = get_vector_angle(tgt_coord, src_coords[i]);
113
114 // if the target and source point are nearly identical
115 if (distance < yac_angle_tol) {
116 for (size_t j = 0; j < n; ++j) weights[j] = 0.0;
117 weights[i] = 1.0;
118 return;
119 }
120 weights[i] = distance * distance;
121 }
122
123 // a) compute sum of source point distances
124 double src_distances_sum = 0.0;
125 double src_distances_count = 0.5 * (double)(n * n - n);
126 for (size_t i = 0; i < n-1; ++i)
127 for (size_t j = i + 1; j < n; ++j)
128 src_distances_sum += get_vector_angle(src_coords[i], src_coords[j]);
129
130 // b) C = -1 / (c * d_mean^2)
131 double src_distances_mean = src_distances_sum / src_distances_count;
132 double scale = -1.0 / (gauss_scale * src_distances_mean * src_distances_mean);
133
134 // c) calculate weights
135 // w_i = e^(-d_i^2/(c*s^2))
136 // w_i = e^(C * d_i^2)
137 double weights_sum = 0.0;
138 for (size_t i = 0; i < n; ++i) {
139 weights[i] = exp(scale * weights[i]);
140 weights_sum += weights[i];
141 }
142
143 // If the sum of the weights is very low, which can happen in case
144 // the target point is very far away from the group of source points.
145 if (fabs(weights_sum) < 1e-9) {
146
147 // Due to limited accuracy the exact contribution of each source
148 // point cannot be computed. Therefore, the normalisation would
149 // generate NaN's. Hence we fall back to inverse distance weighted
150 // averge for this target point.
152 tgt_coord, src_coords, n, weights, gauss_scale);
153 return;
154 }
155
156 // d) scale weights such that SUM(w_i) == 1
157 for (size_t i = 0; i < n; ++i) weights[i] /= weights_sum;
158}
159
160static void inverse(double * A, size_t n) {
161
162// LAPACKE_dsytrf_work and LAPACKE_dsytri might not be available (see yac_lapack_interface.h).
163#ifdef YAC_LAPACK_NO_DSYTR
164 lapack_int ipiv[n+1];
165 double work[n*n];
166
167 for (size_t i = 0; i < n+1; ++i) ipiv[i] = 0;
168 for (size_t i = 0; i < n*n; ++i) work[i] = 0;
169
171 !LAPACKE_dgetrf(
172 LAPACK_COL_MAJOR, (lapack_int) n, (lapack_int) n,
173 A, (lapack_int) n, ipiv), "internal ERROR: dgetrf")
174
176 !LAPACKE_dgetri_work(
177 LAPACK_COL_MAJOR, (lapack_int) n, A, (lapack_int) n,
178 ipiv, work, (lapack_int) (n * n)), "internal ERROR: dgetri")
179#else
180 lapack_int ipiv[n];
181 double work[n];
182
184 !LAPACKE_dsytrf_work(
185 LAPACK_COL_MAJOR, 'L', (lapack_int) n , A,
186 (lapack_int) n, ipiv, work, (lapack_int) n), "internal ERROR: dsytrf")
187
189 !LAPACKE_dsytri_work(
190 LAPACK_COL_MAJOR, 'L', (lapack_int) n , A,
191 (lapack_int) n, ipiv, work), "internal ERROR: dsytri")
192
193 for (size_t i = 0; i < n; ++i)
194 for (size_t j = i + 1; j < n; ++j)
195 A[j*n+i] = A[i*n+j];
196#endif
197}
198
200 double tgt_coord[3], yac_coordinate_pointer src_coords, size_t const n,
201 double * weights, double const rbf_scale) {
202
203 double A[n][n];
204 double a[n];
205
206 double sum_d = 0.0, scale_d = 1.0;
207
208 // compute distance matrix for all found source points
209 for (size_t i = 0; i < n; ++i) A[i][i] = 0.0;
210 for (size_t i = 0; i < n - 1; ++i) {
211 for (size_t j = i + 1; j < n; ++j) {
212 double d = get_vector_angle(src_coords[i], src_coords[j]);
213 A[i][j] = d;
214 A[j][i] = d;
215 sum_d += d;
216 }
217 }
218
219 // compute and apply scale factor for distance matrix
220 if (sum_d > 0.0)
221 scale_d = ((double)((n - 1) * n)) / (2.0 * sum_d);
222 scale_d /= rbf_scale;
223
224 double sq_scale_d = scale_d * scale_d;
225
226 // compute matrix A[n][n]
227 // with A = rbf(A)
228 // rbf(a) => Radial basis function
229 for (size_t i = 0; i < n; ++i) {
230 for (size_t j = 0; j < n; ++j) {
231 double d = A[i][j];
232 // gauß rbf kernel
233 A[i][j] = exp(-1.0 * d * d * sq_scale_d);
234 }
235 }
236
237 // compute inverse of A
238 inverse(&A[0][0], n);
239
240 // compute a[NUM_NEIGH]
241 // with a_i = rbf(d(x_i, y))
242 // x => vector containing the coordinates of the
243 // n nearest neighbours of the current
244 // target point
245 // y => coordinates of target point
246 // d(a, b) => great circle distance between point a and b
247 // rbf(a) => Radial basis function
248 for (size_t i = 0; i < n; ++i) {
249 double d = get_vector_angle(tgt_coord, src_coords[i]);
250 // gauß rbf kernel
251 a[i] = exp(-1.0 * d * d * sq_scale_d);
252 }
253
254 // compute weights
255 // with w_i = SUM(A_inv[i][j]*a[j]) // j = 0..n-1
256 for (size_t i = 0; i < n; ++i) {
257 weights[i] = 0.0;
258 for (size_t j = 0; j < n; ++j) weights[i] += A[i][j] * a[j];
259 }
260}
261
262static size_t do_search_nnn (struct interp_method * method,
263 struct yac_interp_grid * interp_grid,
264 size_t * tgt_points, size_t count,
265 struct yac_interp_weights * weights) {
266
267 struct interp_method_nnn * method_nnn = (struct interp_method_nnn *)method;
268
270 yac_interp_grid_get_num_src_fields(interp_grid) == 1,
271 "ERROR(do_search_nnn): invalid number of source fields")
272
273 // get coordinates of target points
274 yac_coordinate_pointer tgt_coords = xmalloc(count * sizeof(*tgt_coords));
276 interp_grid, tgt_points, count, tgt_coords);
277
278 size_t n = method_nnn->n;
279
280 size_t * size_t_buffer = xmalloc((2 * n + 1) * count * sizeof(*size_t_buffer));
281 size_t * src_points = size_t_buffer;
282 size_t * src_points_reorder = size_t_buffer + n * count;
283 size_t * reorder_idx = size_t_buffer + 2 * n * count;
284 int * fail_flag = xmalloc(count * sizeof(*fail_flag));
285
286 // search for the n nearest source points
288 interp_grid, tgt_coords, count, n, src_points,
289 method_nnn->max_search_distance);
290
291 size_t result_count = 0;
292
293 // check for which cells the search was successful
294 for (size_t i = 0, k = 0; i < count; ++i) {
295 int flag = 0;
296 for (size_t j = 0; j < n; ++j, ++k) flag |= src_points[k] == SIZE_MAX;
297 result_count += !(size_t)(fail_flag[i] = flag);
298 reorder_idx[i] = i;
299 }
300
301 // sort target points, for which the search was successful to the beginning of
302 // the array
303 for (size_t i = 0; i < count; ++i) reorder_idx[i] = i;
304 yac_quicksort_index_int_size_t(fail_flag, count, reorder_idx);
305 free(fail_flag);
306
307 void (*compute_weights)(
308 double[3], yac_coordinate_pointer, size_t, double *, double const) =
309 method_nnn->compute_weights;
310 double scale = method_nnn->scale;
311 double * w = xmalloc(n * result_count * sizeof(*w));
312 size_t * num_weights_per_tgt =
313 xmalloc(result_count * sizeof(*num_weights_per_tgt));
314 yac_coordinate_pointer src_coord_buffer = xmalloc(n * sizeof(*src_coord_buffer));
315 yac_const_coordinate_pointer src_field_coordinates =
317
318 // compute the weights
319 for (size_t i = 0; i < result_count; ++i) {
320 size_t curr_reorder_idx = reorder_idx[i];
321 for (size_t j = 0; j < n; ++j) {
322 size_t curr_src_point = src_points[curr_reorder_idx * n + j];
323 memcpy(src_coord_buffer[j], src_field_coordinates[curr_src_point],
324 3 * sizeof(double));
325 src_points_reorder[i * n + j] = curr_src_point;
326 }
327
329 tgt_coords[curr_reorder_idx], src_coord_buffer, n, w + i * n, scale);
330 num_weights_per_tgt[i] = n;
331 }
332
333 // move the non-interpolated target points to the end
334 for (size_t i = 0; i < count; ++i) src_points[reorder_idx[i]] = i;
335 yac_quicksort_index_size_t_size_t(src_points, count, tgt_points);
336
337 free(src_coord_buffer);
338 free(tgt_coords);
339
340 struct remote_point * srcs =
342 interp_grid, 0, src_points_reorder, result_count * n);
343
344 struct remote_points tgts = {
345 .data =
347 interp_grid, tgt_points, result_count),
348 .count = result_count};
349
350 // store weights
352 weights, &tgts, num_weights_per_tgt, srcs, w);
353
354 free(size_t_buffer);
355 free(tgts.data);
356 free(srcs);
357 free(w);
358 free(num_weights_per_tgt);
359
360 return result_count;
361}
362
363static size_t do_search_1nn(struct interp_method * method,
364 struct yac_interp_grid * interp_grid,
365 size_t * tgt_points, size_t count,
366 struct yac_interp_weights * weights) {
367
369 yac_interp_grid_get_num_src_fields(interp_grid) == 1,
370 "ERROR(do_search_1nn): invalid number of source fields")
371
372 // get coordinates of target points
373 yac_coordinate_pointer tgt_coords = xmalloc(count * sizeof(*tgt_coords));
375 interp_grid, tgt_points, count, tgt_coords);
376
377 size_t * src_points = xmalloc(count * sizeof(*src_points));
378
379 // search for the nearest source points
381 interp_grid, tgt_coords, count, 1, src_points,
382 ((struct interp_method_1nn *)method)->max_search_distance);
383
384 // move the non-interpolated target points to the end
385 // (source points == SIZE_MAX if no source point was found)
386 yac_quicksort_index_size_t_size_t(src_points, count, tgt_points);
387 free(tgt_coords);
388
389 // count the number of target points for which we found a source point
390 size_t result_count = 0;
391 for (; (result_count < count) && (src_points[result_count] != SIZE_MAX);
392 ++result_count);
393
394 struct remote_point * srcs =
396 interp_grid, 0, src_points, result_count);
397
398 struct remote_points tgts = {
399 .data =
401 interp_grid, tgt_points, result_count),
402 .count = result_count};
403
404 // store weights
405 ((struct interp_method_1nn *)method)->interp_weights_add(
406 weights, &tgts, srcs);
407
408 free(src_points);
409 free(tgts.data);
410 free(srcs);
411
412 return result_count;
413}
414
416 struct yac_interp_weights * weights, struct remote_points * tgts,
417 struct remote_point src) {
418
419 size_t * num_src_per_tgt = xmalloc(tgts->count * sizeof(*num_src_per_tgt));
420 double * w = xmalloc(tgts->count * sizeof(*w));
421 struct remote_point * srcs = xmalloc(tgts->count * sizeof(*srcs));
422
423 for (size_t i = 0; i < tgts->count; ++i) {
424 num_src_per_tgt[i] = 1;
425 w[i] = 0.0;
426 srcs[i] = src;
427 }
428
429 yac_interp_weights_add_wsum(weights, tgts, num_src_per_tgt, srcs, w);
430
431 free(srcs);
432 free(w);
433 free(num_src_per_tgt);
434}
435
436static size_t do_search_zero(struct interp_method * method,
437 struct yac_interp_grid * interp_grid,
438 size_t * tgt_points, size_t count,
439 struct yac_interp_weights * weights) {
440
442 yac_interp_grid_get_num_src_fields(interp_grid) == 1,
443 "ERROR(do_search_zero): invalid number of source fields")
444
445 UNUSED(method);
446
447 // get global ids of all valid local source points
448 size_t * src_points, src_count;
449 yac_interp_grid_get_src_points(interp_grid, 0, &src_points, &src_count);
450 yac_int * src_global_ids = xmalloc(src_count * sizeof(*src_global_ids));
451 if (src_count > 0)
453 interp_grid, src_points, src_count, 0, src_global_ids);
454 free(src_points);
455
456 // determine smallest global id of all unmasked source points in the
457 // local data
458 yac_int min_src_global_id = XT_INT_MAX;
459 for (size_t i = 0; i < src_count; ++i)
460 if (src_global_ids[i] < min_src_global_id)
461 min_src_global_id = src_global_ids[i];
462 free(src_global_ids);
463
464 // determine smallest global id of all unmasked source points in the
465 // global data
466 MPI_Comm comm = yac_interp_grid_get_MPI_Comm(interp_grid);
468 MPI_Allreduce(
469 MPI_IN_PLACE, &min_src_global_id, 1, yac_int_dt, MPI_MIN, comm), comm);
471 min_src_global_id != XT_INT_MAX,
472 "ERROR(do_search_zero): unable to find unmasked source points");
473
474 // get the local id of the source point with the smallest global ids
475 // (add it to the local data if it does not yet exist there)
476 size_t min_src_local_id;
478 interp_grid, 0, &min_src_global_id, 1, &min_src_local_id);
479
480 struct remote_point * src =
482 interp_grid, 0, &min_src_local_id, 1);
483
484 struct remote_points tgts = {
485 .data =
487 interp_grid, tgt_points, count),
488 .count = count};
489
490 // store weights
491 interp_weights_add_zero(weights, &tgts, *src);
492
493 free(tgts.data);
494 free(src);
495
496 return count;
497}
498
500
502 (config.max_search_distance >= 0.0) &&
503 (config.max_search_distance <= M_PI),
504 "ERROR(yac_interp_method_nnn_new): "
505 "unsupported value for max_search_distance (%lf), has to be in [0.0,PI]",
506 config.max_search_distance)
507
508 if (config.type == YAC_INTERP_NNN_ZERO) {
509
511 config.n == 1,
512 "ERROR(yac_interp_method_nnn_new): n != 1 does not make sense for zero")
514 config.max_search_distance == 0.0, "ERROR(yac_interp_method_nnn_new): "
515 "max_search_distance != 0.0 does not make sense for zero")
516
517 struct interp_method_zero * method = xmalloc(1 * sizeof(*method));
519 return (struct interp_method*)method;
520 }
521
522 double max_search_distance =
523 (config.max_search_distance == 0.0)?M_PI:config.max_search_distance;
524
525 if (config.n == 1) {
526
527 struct interp_method_1nn * method = xmalloc(1 * sizeof(*method));
531 return (struct interp_method*)method;
532 }
533
534 struct interp_method_nnn * method = xmalloc(1 * sizeof(*method));
535
537
539 method->n = config.n;
540
542 (config.type == YAC_INTERP_NNN_AVG) ||
543 (config.type == YAC_INTERP_NNN_DIST) ||
544 (config.type == YAC_INTERP_NNN_GAUSS) ||
545 (config.type == YAC_INTERP_NNN_RBF),
546 "ERROR(yac_interp_method_nnn_new): invalid NNN type")
547
548 switch (config.type) {
549 case(YAC_INTERP_NNN_AVG):
551 config.n >= 1,
552 "ERROR(yac_interp_method_nnn_new): n needs to be at least 1 for "
553 "distance weighted average")
554 method->scale = 0.0;
556 break;
559 config.n >= 2,
560 "ERROR(yac_interp_method_nnn_new): n needs to be at least 2 for "
561 "distance weighted average")
562 method->scale = 0.0;
564 break;
567 config.n >= 2,
568 "ERROR(yac_interp_method_nnn_new): n needs to be at least 2 for gauss")
569 method->scale = config.data.gauss_scale;
571 break;
572 default:
573 case(YAC_INTERP_NNN_RBF):
575 config.n >= 2,
576 "ERROR(yac_interp_method_nnn_new): n needs to be at least 2 for RBF")
577 method->scale = config.data.rbf_scale;
579 break;
580 };
581
582 return (struct interp_method*)method;
583}
584
585static void delete_nnn(struct interp_method * method) {
586 free(method);
587}
#define UNUSED(x)
Definition core.h:73
#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
size_t yac_interp_grid_get_num_src_fields(struct yac_interp_grid *interp_grid)
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
struct remote_point * yac_interp_grid_get_src_remote_points(struct yac_interp_grid *interp_grid, size_t src_field_idx, size_t *src_points, size_t count)
void yac_interp_grid_do_nnn_search_src(struct yac_interp_grid *interp_grid, yac_coordinate_pointer search_coords, size_t count, size_t n, size_t *src_points, double max_search_distance)
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)
void yac_interp_grid_get_src_global_ids(struct yac_interp_grid *interp_grid, size_t *src_points, size_t count, size_t src_field_idx, yac_int *src_global_ids)
void yac_interp_grid_src_global_to_local(struct yac_interp_grid *interp_grid, size_t src_field_idx, yac_int *src_global_ids, size_t count, size_t *src_local_ids)
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 void compute_weights_gauss(double tgt_coord[3], yac_coordinate_pointer src_coords, size_t const n, double *weights, double const gauss_scale)
static size_t do_search_nnn(struct interp_method *method, struct yac_interp_grid *interp_grid, size_t *tgt_points, size_t count, struct yac_interp_weights *weights)
static void compute_weights_rbf(double tgt_coord[3], yac_coordinate_pointer src_coords, size_t const n, double *weights, double const rbf_scale)
static size_t do_search_zero(struct interp_method *method, struct yac_interp_grid *interp_grid, size_t *tgt_points, size_t count, struct yac_interp_weights *weights)
static void delete_nnn(struct interp_method *method)
static struct interp_method_vtable interp_method_1nn_vtable
static void compute_weights_dist(double tgt_coord[3], yac_coordinate_pointer src_coords, size_t const n, double *weights, double const dummy)
static void interp_weights_add_zero(struct yac_interp_weights *weights, struct remote_points *tgts, struct remote_point src)
static struct interp_method_vtable interp_method_zero_vtable
static void inverse(double *A, size_t n)
static size_t do_search_1nn(struct interp_method *method, struct yac_interp_grid *interp_grid, size_t *tgt_points, size_t count, struct yac_interp_weights *weights)
static struct interp_method_vtable interp_method_nnn_vtable
struct interp_method * yac_interp_method_nnn_new(struct yac_nnn_config config)
static void compute_weights_avg(double tgt_coord[3], yac_coordinate_pointer src_coords, size_t const n, double *weights, double const dummy)
@ YAC_INTERP_NNN_GAUSS
distance with Gauss weights of n source points
@ YAC_INTERP_NNN_RBF
radial basis functions
@ YAC_INTERP_NNN_AVG
average of n source points
@ YAC_INTERP_NNN_DIST
distance weighted average of n source points
@ YAC_INTERP_NNN_ZERO
all weights are set to zero
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_direct(struct yac_interp_weights *weights, struct remote_points *tgts, struct remote_point *srcs)
Definition __init__.py:1
#define xmalloc(size)
Definition ppm_xfuncs.h:66
void(* interp_weights_add)(struct yac_interp_weights *weights, struct remote_points *tgts, struct remote_point *srcs)
struct interp_method_vtable * vtable
void(* compute_weights)(double[3], yac_coordinate_pointer, size_t const, double *, double const)
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)
struct interp_method_vtable * vtable
information (global id and location) about a point that
structure containing the information (global id and location)
struct remote_point * data
union yac_nnn_config::@21 data
enum yac_interp_nnn_weight_type type
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 YAC_ASSERT(exp, msg)
Definition yac_assert.h:16
#define yac_mpi_call(call, comm)
Xt_int yac_int
Definition yac_types.h:15
double const (* yac_const_coordinate_pointer)[3]
Definition yac_types.h:20
#define yac_int_dt
Definition yac_types.h:16
double(* yac_coordinate_pointer)[3]
Definition yac_types.h:19