YAC 3.20.0
Yet Another Coupler
Loading...
Searching...
No Matches
interp_method_conserv.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
16#include "parameter/param_int.h"
20#include "clipping.h"
21#include "area.h"
22#include "float.h"
23#include "yac_mpi_common.h"
24
25#define AREA_TOL_FACTOR (1e-6)
26
27static size_t do_search_conserv_1st_order(struct interp_method * method,
28 struct yac_interp_grid * interp_grid,
29 size_t * tgt_points, size_t count,
30 struct yac_interp_weights * weights,
31 int * interpolation_complete);
32static size_t do_search_conserv_2nd_order(struct interp_method * method,
33 struct yac_interp_grid * interp_grid,
34 size_t * tgt_points, size_t count,
35 struct yac_interp_weights * weights,
36 int * interpolation_complete);
37static void delete_conserv(struct interp_method * method);
38
39static struct interp_method_vtable
43
44static struct interp_method_vtable
48
56
62
68
71 size_t n;
72};
73
75 struct {
76 size_t local_id;
78 } src, tgt;
79 double norm_area;
80 double area;
81 double barycenter[3];
83};
84
86 struct yac_const_basic_grid_data * basic_grid_data) {
87
88 int max_num_vertices_per_cell = 0;
89 for (size_t i = 0; i < basic_grid_data->count[YAC_LOC_CELL]; ++i)
90 if (basic_grid_data->num_vertices_per_cell[i] >
91 max_num_vertices_per_cell)
92 max_num_vertices_per_cell =
93 basic_grid_data->num_vertices_per_cell[i];
94 return max_num_vertices_per_cell;
95}
96
97static void get_cell_buffers(
98 struct yac_interp_grid * interp_grid, size_t max_num_src_per_tgt,
99 struct yac_grid_cell * tgt_grid_cell, struct yac_grid_cell ** src_grid_cells) {
100
101 struct yac_const_basic_grid_data * src_basic_grid_data =
103 struct yac_const_basic_grid_data * tgt_basic_grid_data =
105
106 *src_grid_cells = xmalloc(max_num_src_per_tgt * sizeof(**src_grid_cells));
107 enum yac_edge_type * edge_type_buffer;
108 double (*coordinates_xyz_buffer)[3];
109
110 // prepare source grid cell buffer
111 {
112 int max_num_vertices_per_cell =
113 MAX(get_max_num_vertices_per_cell(src_basic_grid_data),
114 get_max_num_vertices_per_cell(tgt_basic_grid_data));
115
116 edge_type_buffer =
117 xmalloc((max_num_src_per_tgt + 1) * (size_t)max_num_vertices_per_cell *
118 sizeof(*edge_type_buffer));
119 coordinates_xyz_buffer =
120 xmalloc((max_num_src_per_tgt + 1) * (size_t)max_num_vertices_per_cell *
121 sizeof(*coordinates_xyz_buffer));
122
123 tgt_grid_cell->coordinates_xyz = coordinates_xyz_buffer;
124 tgt_grid_cell->edge_type = edge_type_buffer;
125 tgt_grid_cell->array_size = max_num_vertices_per_cell;
126 for (size_t i = 0; i < max_num_src_per_tgt; ++i) {
127 (*src_grid_cells)[i].coordinates_xyz =
128 coordinates_xyz_buffer + (i + 1) * max_num_vertices_per_cell;
129 (*src_grid_cells)[i].edge_type =
130 edge_type_buffer + (i + 1) * max_num_vertices_per_cell;
131 (*src_grid_cells)[i].array_size = max_num_vertices_per_cell;
132 }
133 }
134}
135
137 struct yac_interp_grid * interp_grid,
138 struct yac_grid_cell * tgt_grid_cell, struct yac_grid_cell * src_grid_cell) {
139
140 struct yac_const_basic_grid_data * src_basic_grid_data =
142 struct yac_const_basic_grid_data * tgt_basic_grid_data =
144
145 int max_num_vertices_per_cell =
146 MAX(get_max_num_vertices_per_cell(src_basic_grid_data),
147 get_max_num_vertices_per_cell(tgt_basic_grid_data));
148
149 enum yac_edge_type * edge_type_buffer =
150 xmalloc(2 * (size_t)max_num_vertices_per_cell *
151 sizeof(*edge_type_buffer));
152 yac_coordinate_pointer coordinates_xyz_buffer =
153 xmalloc(2 * (size_t)max_num_vertices_per_cell *
154 sizeof(*coordinates_xyz_buffer));
155
156 tgt_grid_cell->coordinates_xyz = coordinates_xyz_buffer;
157 tgt_grid_cell->edge_type = edge_type_buffer;
158 tgt_grid_cell->array_size = max_num_vertices_per_cell;
159
160 src_grid_cell->coordinates_xyz =
161 coordinates_xyz_buffer + max_num_vertices_per_cell;
162 src_grid_cell->edge_type =
163 edge_type_buffer + max_num_vertices_per_cell;
164 src_grid_cell->array_size = max_num_vertices_per_cell;
165}
166
168 struct yac_const_basic_grid_data * tgt_basic_grid_data, size_t tgt_cell,
169 struct yac_const_basic_grid_data * src_basic_grid_data, size_t src_count,
170 size_t * src_cells, struct yac_grid_cell tgt_grid_cell_buffer,
171 struct yac_grid_cell * src_grid_cell_buffer,
172 double * weights, size_t * num_weights, int partial_coverage,
174 int enforced_conserv) {
175
177 tgt_basic_grid_data, tgt_cell, &tgt_grid_cell_buffer);
178 for (size_t i = 0; i < src_count; ++i)
180 src_basic_grid_data, src_cells[i], src_grid_cell_buffer + i);
181
182 double * area = weights;
184 src_count, src_grid_cell_buffer, tgt_grid_cell_buffer, area);
185
186 size_t num_valid_weights = 0;
187 for (size_t i = 0; i < src_count; ++i) {
188
189 if (area[i] > 0.0) {
190 if (i != num_valid_weights) {
191 area[num_valid_weights] = area[i];
192 src_cells[num_valid_weights] = src_cells[i];
193 }
194 ++num_valid_weights;
195 }
196 }
197 *num_weights = num_valid_weights;
198 if (num_valid_weights == 0) return 0;
199
200 double tgt_cell_area = yac_grid_cell_area(tgt_grid_cell_buffer);
201 double norm_factor;
202
203 switch(normalisation) {
205 "invalid normalisation option in conservative remapping")
207 norm_factor = 1.0 / tgt_cell_area;
208 break;
210 double fracarea = 0.0;
211 for (size_t i = 0; i < num_valid_weights; ++i) fracarea += area[i];
212 norm_factor = 1.0 / fracarea;
213 break;
214 }
215 };
216
217 if (partial_coverage) {
218 for (size_t i = 0; i < num_valid_weights; ++i) weights[i] *= norm_factor;
219 return 1;
220 } else {
221 double tgt_cell_area_diff = tgt_cell_area;
222 double area_tol = tgt_cell_area * AREA_TOL_FACTOR;
223 for (size_t i = 0; i < num_valid_weights; ++i) {
224 double curr_area = area[i];
225 tgt_cell_area_diff -= curr_area;
226 weights[i] = curr_area * norm_factor;
227 }
228 int successful = fabs(tgt_cell_area_diff) <= area_tol;
229 if (successful && enforced_conserv)
230 yac_correct_weights(num_valid_weights, weights);
231 return successful;
232 }
233}
234
235static size_t do_search_conserv_1st_order (struct interp_method * method,
236 struct yac_interp_grid * interp_grid,
237 size_t * tgt_points, size_t count,
238 struct yac_interp_weights * weights,
239 int * interpolation_complete) {
240
241 if (*interpolation_complete) return 0;
242
243 struct interp_method_conserv * method_conserv =
244 (struct interp_method_conserv *)method;
245
247
249
251
252 size_t * src_cells = NULL;
253 size_t * num_src_per_tgt = xmalloc(count * sizeof(*num_src_per_tgt));
254
255 // search matching cells
257 interp_grid, tgt_points, count, &src_cells, num_src_per_tgt);
258
259 // we did a search on the interp_grid, therefore we have to re-get the basic
260 // grid data
261 struct yac_const_basic_grid_data * tgt_basic_grid_data =
263 struct yac_const_basic_grid_data * src_basic_grid_data =
265
266 size_t total_num_weights = 0;
267 size_t max_num_src_per_tgt = 0;
268 for (size_t i = 0; i < count; ++i) {
269 size_t curr_num_src_per_tgt = num_src_per_tgt[i];
270 if (curr_num_src_per_tgt > max_num_src_per_tgt)
271 max_num_src_per_tgt = curr_num_src_per_tgt;
272 total_num_weights += num_src_per_tgt[i];
273 }
274
275 // to ensure that the interpolation always procduces the same result, we
276 // sort the source cells for each target point by their global ids
277 {
278 yac_int * temp_src_global_ids =
279 xmalloc(max_num_src_per_tgt * sizeof(*temp_src_global_ids));
280
281 for (size_t i = 0, offset = 0; i < count; ++i) {
282
283 size_t curr_num_src_per_tgt = num_src_per_tgt[i];
284 size_t * curr_src_cells = src_cells + offset;
285 offset += curr_num_src_per_tgt;
286
287 for (size_t j = 0; j < curr_num_src_per_tgt; ++j)
288 temp_src_global_ids[j] =
289 src_basic_grid_data->ids[YAC_LOC_CELL][curr_src_cells[j]];
290
292 temp_src_global_ids, curr_num_src_per_tgt, curr_src_cells);
293 }
294
295 free(temp_src_global_ids);
296 }
297
298 double * w = xmalloc(total_num_weights * sizeof(*w));
299 size_t result_count = 0;
300 size_t * failed_tgt = xmalloc(count * sizeof(*failed_tgt));
301 total_num_weights = 0;
302
303 int partial_coverage = method_conserv->partial_coverage;
304 enum yac_interp_method_conserv_normalisation normalisation =
305 method_conserv->normalisation;
306 int enforced_conserv = method_conserv->enforced_conserv;
307
308 struct yac_grid_cell tgt_grid_cell;
309 struct yac_grid_cell * src_grid_cells;
311 interp_grid, max_num_src_per_tgt, &tgt_grid_cell, &src_grid_cells);
312
313 // compute overlaps
314 for (size_t i = 0, offset = 0, result_offset = 0; i < count; ++i) {
315
316 size_t curr_src_count = num_src_per_tgt[i];
317 size_t curr_tgt_point = tgt_points[i];
318 size_t num_weights;
319
320 // if weight computation was successful
322 tgt_basic_grid_data, curr_tgt_point,
323 src_basic_grid_data, curr_src_count, src_cells + offset,
324 tgt_grid_cell, src_grid_cells, w + result_offset, &num_weights,
325 partial_coverage, normalisation, enforced_conserv)) {
326
327 if (offset != result_offset) {
328
329 memmove(
330 src_cells + result_offset, src_cells + offset,
331 num_weights * sizeof(*src_cells));
332 }
333 tgt_points[result_count] = curr_tgt_point;
334 num_src_per_tgt[result_count] = num_weights;
335 result_count++;
336 result_offset += num_weights;
337 total_num_weights += num_weights;
338 } else {
339 failed_tgt[i - result_count] = curr_tgt_point;
340 }
341
342 offset += curr_src_count;
343 }
344
346 free(tgt_grid_cell.edge_type);
347 free(tgt_grid_cell.coordinates_xyz);
348 free(src_grid_cells);
349
350 if (result_count != count)
351 memcpy(tgt_points + result_count, failed_tgt,
352 (count - result_count) * sizeof(*tgt_points));
353 free(failed_tgt);
354
355 struct remote_points tgts = {
356 .data =
358 interp_grid, tgt_points, result_count),
359 .count = result_count};
360 struct remote_point * srcs =
362 interp_grid, 0, src_cells, total_num_weights);
363
364 // store weights
366 weights, &tgts, num_src_per_tgt, srcs, w);
367
368 free(tgts.data);
369 free(srcs);
370 free(src_cells);
371 free(num_src_per_tgt);
372 free(w);
373
374 return result_count;
375}
376
377static int
378compare_supermesh_cell_src_local_ids(const void * a, const void * b) {
379
380 struct supermesh_cell * a_ = (struct supermesh_cell *)a;
381 struct supermesh_cell * b_ = (struct supermesh_cell *)b;
382
383 int ret = (a_->src.local_id > b_->src.local_id) -
384 (a_->src.local_id < b_->src.local_id);
385 if (ret) return ret;
386 return (a_->tgt.global_id > b_->tgt.global_id) -
387 (a_->tgt.global_id < b_->tgt.global_id);
388}
389
390static int
391compare_supermesh_cell_tgt_local_ids(const void * a, const void * b) {
392
393 struct supermesh_cell * a_ = (struct supermesh_cell *)a;
394 struct supermesh_cell * b_ = (struct supermesh_cell *)b;
395
396 int ret = (a_->tgt.local_id > b_->tgt.local_id) -
397 (a_->tgt.local_id < b_->tgt.local_id);
398 if (ret) return ret;
399 return (a_->src.global_id > b_->src.global_id) -
400 (a_->src.global_id < b_->src.global_id);
401}
402
404 double * src_cell_centroid, struct weight_vector_3d * G_i,
405 struct weight_vector_data_3d * buffer) {
406
407 // This routine computes: (I_3 - C_i * C_i^-1) * G_i
408 //
409 // O(g_i) = g_i - C_i * (C_i^-1 * g_i)
410 // where: C_i is the centeroid of a source cell
411 // g_i is the gradient of the source field in C_i
412 // O(g_i) is the projection of g_i into the plane perpendicular to C_i
413 // g_i = G_i * f
414 // where: G_i is the weight matrix to compute g_i
415 // f is the source field vector
416 // => O(g_i) = (I_3 - C_i * C_i^-1) * G_i * f
417 // where: I_3 is the identity matrix of size 3 x 3
418 //
419 // M = I_3 - C_i * C_i^-1
420
421 double M[3][3];
422 for (size_t k = 0; k < 3; ++k)
423 for (size_t l = 0; l < 3; ++l)
424 M[k][l] = - src_cell_centroid[k] * src_cell_centroid[l];
425 for (size_t k = 0; k < 3; ++k)
426 M[k][k] += 1.0;
427
428 struct weight_vector_data_3d * G_i_data = G_i->data;
429
430 size_t N = G_i->n;
431 for (size_t i = 0; i < N; ++i) {
432 buffer[i].local_id = G_i_data[i].local_id;
433 buffer[i].global_id = G_i_data[i].global_id;
434 for (size_t j = 0; j < 3; ++j) buffer[i].weight[j] = 0.0;
435 }
436
437 for (size_t n = 0; n < N; ++n)
438 for (size_t i = 0; i < 3; ++i)
439 for (size_t j = 0; j < 3; ++j)
440 buffer[n].weight[i] += G_i_data[n].weight[j] * M[i][j];
441
442 memcpy(G_i->data, buffer, N * sizeof(*buffer));
443}
444
446 void const * a, void const * b) {
447
448 struct weight_vector_data const * weight_a =
449 (struct weight_vector_data const *)a;
450 struct weight_vector_data const * weight_b =
451 (struct weight_vector_data const *)b;
452
453 int ret = weight_a->global_id - weight_b->global_id;
454 if (ret) return ret;
455 double abs_weight_a = fabs(weight_a->weight);
456 double abs_weight_b = fabs(weight_b->weight);
457 ret = (abs_weight_a > abs_weight_b) - (abs_weight_a < abs_weight_b);
458 if (ret) return ret;
459 return (weight_a->weight > weight_b->weight) -
460 (weight_a->weight < weight_b->weight);
461}
462
464 void const * a, void const * b) {
465
466 struct weight_vector_data const * weight_a =
467 (struct weight_vector_data const *)a;
468 struct weight_vector_data const * weight_b =
469 (struct weight_vector_data const *)b;
470
471 return weight_a->global_id - weight_b->global_id;
472}
473
475 struct weight_vector_data * weights, size_t * n) {
476
477 size_t n_ = *n;
478
479 if (n_ <= 1) return;
480
481 // sort weights by global_id then by weight
482 qsort(weights, n_, sizeof(*weights), compare_weight_vector_data_weight);
483
484 size_t new_n = 1;
485 struct weight_vector_data * prev_weight_data = weights;
486 struct weight_vector_data * curr_weight_data = weights + 1;
487 for (size_t i = 1; i < n_; ++i, ++curr_weight_data) {
488
489 // if both weights refer to the same source point (by global_id)
490 if (!compare_weight_vector_data(prev_weight_data, curr_weight_data)) {
491 prev_weight_data->weight += curr_weight_data->weight;
492 } else {
493 ++new_n;
494 ++prev_weight_data;
495 *prev_weight_data = *curr_weight_data;
496 }
497 }
498
499 n_ = new_n;
500 new_n = 0;
501
502 // check for zero-weights
503 for (size_t i = 0; i < n_; ++i) {
504
505 if (weights[i].weight == 0.0) continue;
506 if (i != new_n) weights[new_n] = weights[i];
507 ++new_n;
508 }
509
510 *n = new_n;
511}
512
514 struct supermesh_cell * super_cell, struct weight_vector_data * weights) {
515
516 weights[0].weight = super_cell->norm_area;
517 weights[0].global_id = super_cell->src.global_id;
518 weights[0].local_id = super_cell->src.local_id;
519
520 struct weight_vector_3d * src_cell_gradient = super_cell->src_cell_gradient;
521
522 size_t N = src_cell_gradient->n;
523 // in case we have no gradient for the current supermesh cell,
524 // we assume a constant field across the whole associated source cell
525 if (N > 0) {
526 struct weight_vector_data_3d * gradient_weights = src_cell_gradient->data - 1;
527 double * overlap_barycenter = super_cell->barycenter;
528
529 for (size_t n = 1; n <= N; ++n) {
530 weights[n].weight =
531 (gradient_weights[n].weight[0] * overlap_barycenter[0] +
532 gradient_weights[n].weight[1] * overlap_barycenter[1] +
533 gradient_weights[n].weight[2] * overlap_barycenter[2]) *
534 super_cell->norm_area;
535 weights[n].global_id = gradient_weights[n].global_id;
536 weights[n].local_id = gradient_weights[n].local_id;
537 }
538 }
539
540 return 1 + N;
541}
542
544 struct yac_const_basic_grid_data * grid_data, size_t cell_idx,
545 double barycenter[3]) {
546
547 size_t num_vertices = grid_data->num_vertices_per_cell[cell_idx];
548 size_t const * vertices =
549 grid_data->cell_to_vertex + grid_data->cell_to_vertex_offsets[cell_idx];
550
551 barycenter[0] = 0.0;
552 barycenter[1] = 0.0;
553 barycenter[2] = 0.0;
554
555 for (size_t i = 0; i < num_vertices; ++i) {
556 double const * curr_vertex_coordinate =
557 grid_data->vertex_coordinates[vertices[i]];
558 barycenter[0] += curr_vertex_coordinate[0];
559 barycenter[1] += curr_vertex_coordinate[1];
560 barycenter[2] += curr_vertex_coordinate[2];
561 }
562 normalise_vector(barycenter);
563}
564
566 struct yac_interp_grid * interp_grid, size_t * tgt_points, size_t count,
567 struct supermesh_cell ** super_cells_, size_t * num_super_cells,
568 int * interp_fail_flag, size_t ** src_cells, size_t * num_src_cells,
570 int partial_coverage) {
571
573 (normalisation == YAC_INTERP_CONSERV_DESTAREA) ||
574 (normalisation == YAC_INTERP_CONSERV_FRACAREA),
575 "invalid normalisation option in conservative remapping")
576
577 size_t * num_src_per_tgt = xmalloc(count * sizeof(*num_src_per_tgt));
578
579 // search for all source cell overlapping with the the target cells
581 interp_grid, tgt_points, count, src_cells, num_src_per_tgt);
582
583 // determine the number of unique matching source cells
584 size_t total_num_overlaps = 0;
585 for (size_t i = 0; i < count; ++i) total_num_overlaps += num_src_per_tgt[i];
586 yac_quicksort_index_size_t_int(*src_cells, total_num_overlaps, NULL);
587 *num_src_cells = total_num_overlaps;
588 yac_remove_duplicates_size_t(*src_cells, num_src_cells);
589
590 size_t * num_tgt_per_src =
591 xrealloc(num_src_per_tgt, *num_src_cells * sizeof(*num_tgt_per_src));
592
593 // for some required source cells we may have not all required supermesh cells
594 // in that case we have to find the respective target cells and compute the
595 // missing supermesh cells from them
596 size_t * tgt_cells = NULL;
598 interp_grid, *src_cells, *num_src_cells, &tgt_cells, num_tgt_per_src);
599
600 total_num_overlaps = 0;
601 for (size_t i = 0; i < *num_src_cells; ++i)
602 total_num_overlaps += num_tgt_per_src[i];
603
604 struct supermesh_cell * super_cells =
605 xmalloc(total_num_overlaps * sizeof(*super_cells));
606
607 struct yac_const_basic_grid_data * src_basic_grid_data =
609 struct yac_const_basic_grid_data * tgt_basic_grid_data =
611
612 for (size_t i = 0, j = 0; i < *num_src_cells; ++i) {
613
614 size_t curr_num_overlaps = num_tgt_per_src[i];
615 size_t curr_src_cell = (*src_cells)[i];
616 yac_int curr_src_global_id =
617 src_basic_grid_data->ids[YAC_LOC_CELL][curr_src_cell];
618
619 for (size_t k = 0; k < curr_num_overlaps; ++k, ++j) {
620
621 size_t curr_tgt_cell = tgt_cells[j];
622 struct supermesh_cell * curr_super_cell = super_cells + j;
623 curr_super_cell->src.local_id = curr_src_cell;
624 curr_super_cell->src.global_id = curr_src_global_id;
625 curr_super_cell->tgt.local_id = curr_tgt_cell;
626 curr_super_cell->tgt.global_id =
627 tgt_basic_grid_data->ids[YAC_LOC_CELL][curr_tgt_cell];
628 }
629 }
630 free(tgt_cells);
631 free(num_tgt_per_src);
632
633 // sort supermesh_cell first by local ids of the target cells and
634 // second by global cell id
635 qsort(super_cells, total_num_overlaps, sizeof(*super_cells),
637
638 struct yac_grid_cell tgt_grid_cell;
639 struct yac_grid_cell src_grid_cell;
640 get_cell_buffers_(interp_grid, &tgt_grid_cell, &src_grid_cell);
641
642 src_basic_grid_data = yac_interp_grid_get_basic_grid_data_src(interp_grid);
643 tgt_basic_grid_data = yac_interp_grid_get_basic_grid_data_tgt(interp_grid);
644
645 // For all supermesh cells compute the area and normalised area.
646 // Additionally, remove all empty supermesh cells.
647 size_t new_num_super_cells = 0;
648 size_t tgt_idx = 0;
649 for (size_t i = 0, j = 0; i < total_num_overlaps;) {
650
651 // get information about the current target cell
652 size_t curr_tgt_cell = super_cells[i].tgt.local_id;
654 tgt_basic_grid_data, curr_tgt_cell, &tgt_grid_cell);
655 double curr_tgt_cell_coverage = 0.0;
656
657 // for all supermesh cells overlapping with the current target cell
658 for (;(i < total_num_overlaps) &&
659 (super_cells[i].tgt.local_id == curr_tgt_cell); ++i) {
660
661 // get the current source cell
663 src_basic_grid_data, super_cells[i].src.local_id, &src_grid_cell);
664
665 // compute area of the current supermesh cell
666 double super_cell_area;
667 double barycenter[3];
669 1, &src_grid_cell, tgt_grid_cell, &super_cell_area, &barycenter);
670
671 // if there is an overlap between the current source and target cell
672 if (super_cell_area > 0.0) {
673
674 super_cells[new_num_super_cells].src = super_cells[i].src;
675 super_cells[new_num_super_cells].tgt = super_cells[i].tgt;
676 super_cells[new_num_super_cells].area = super_cell_area;
677 memcpy(super_cells[new_num_super_cells].barycenter, barycenter,
678 3 * sizeof(double));
679 super_cells[new_num_super_cells].src_cell_gradient = NULL;
680 ++new_num_super_cells;
681
682 curr_tgt_cell_coverage += super_cell_area;
683 }
684 }
685
686 double curr_tgt_cell_area = yac_grid_cell_area(tgt_grid_cell);
687
688 // if there was an overlap
689 if (new_num_super_cells != j) {
690
691 double norm_factor;
692 switch (normalisation) {
694 "invalid normalisation option in conservative remapping")
696 norm_factor = 1.0 / curr_tgt_cell_area;
697 break;
699 norm_factor = 1.0 / curr_tgt_cell_coverage;
700 break;
701 }
702 // compute normalised area
703 for (; j < new_num_super_cells; ++j)
704 super_cells[j].norm_area = super_cells[j].area * norm_factor;
705 }
706
707
708 // for target cell that do not overlap with any source cell
709 while ((tgt_idx < count) && (tgt_points[tgt_idx] < curr_tgt_cell))
710 interp_fail_flag[tgt_idx++] = 1;
711
712 if ((tgt_idx < count) && (tgt_points[tgt_idx] == curr_tgt_cell)) {
713
714 double area_tol = curr_tgt_cell_area * AREA_TOL_FACTOR;
715
716 if (partial_coverage) {
717 interp_fail_flag[tgt_idx] = curr_tgt_cell_coverage < area_tol;
718 } else {
719 interp_fail_flag[tgt_idx] =
720 fabs(curr_tgt_cell_area - curr_tgt_cell_coverage) > area_tol;
721 }
722 ++tgt_idx;
723 }
724 }
725 // for all remaining target cell that do not overlap with any source cell
726 for (; tgt_idx < count; ++tgt_idx) interp_fail_flag[tgt_idx] = 1;
727 *num_super_cells = new_num_super_cells;
728 *super_cells_ =
729 xrealloc(super_cells, new_num_super_cells * sizeof(*super_cells));
731 free(tgt_grid_cell.coordinates_xyz);
732 free(tgt_grid_cell.edge_type);
733}
734
736 struct yac_interp_grid * interp_grid,
737 size_t * src_cells, int * skip_src_cell, size_t num_src_cells,
738 struct supermesh_cell * super_cells, size_t num_super_cells) {
739
740 yac_coordinate_pointer src_cell_centroids =
741 xmalloc(num_src_cells * sizeof(*src_cell_centroids));
742
743 // sort supermesh cells first by source local id and second by
744 // target global id
745 qsort(super_cells, num_super_cells, sizeof(*super_cells),
747
748 struct yac_grid_cell src_grid_cell, dummy;
749 get_cell_buffers_(interp_grid, &src_grid_cell, &dummy);
750
751 struct yac_const_basic_grid_data * src_basic_grid_data =
753
754 // compute centroids of source cells
755 // C_i = N(S_(U_k) (A_k*C_k))
756 // where: N(C) = C*(C*C)^-0.5 // normalisation
757 // U_k all supermesh cells overlaping with the respective source cell
758 // A_k area of supermesh cell
759 // C_k barycenter of supermesh cell (normalisation of the sum of all
760 // vertices of the cell)
761 for (size_t i = 0, offset = 0; i < num_src_cells; ++i) {
762
763 if (skip_src_cell[i]) continue;
764
765 size_t curr_src_cell = src_cells[i];
766
767 struct supermesh_cell * curr_super_cells = super_cells + offset;
768 size_t curr_num_super_cells = offset;
769 while ((offset < num_super_cells) &&
770 (super_cells[offset].src.local_id == curr_src_cell)) ++offset;
771 curr_num_super_cells = offset - curr_num_super_cells;
772
773 double src_cell_centroid[3] = {0.0, 0.0, 0.0};
774
775 if (curr_num_super_cells > 0) {
776 for (size_t j = 0; j < curr_num_super_cells; ++j) {
777
778 double super_cell_area = curr_super_cells[j].area;
779 double * super_cell_barycenter = curr_super_cells[j].barycenter;
780 src_cell_centroid[0] += super_cell_area * super_cell_barycenter[0];
781 src_cell_centroid[1] += super_cell_area * super_cell_barycenter[1];
782 src_cell_centroid[2] += super_cell_area * super_cell_barycenter[2];
783 }
784 } else {
785
786 // In case an unmasked source cell is not covered by any unmasked target
787 // cell (curr_num_super_cells == 0) its centroid is only used to compute
788 // the gradiants of its neighbour cells. In that case a rough estimate
789 // of its centroid (computed here) is sufficient.
791 src_basic_grid_data, curr_src_cell, &src_grid_cell);
792 for (size_t j = 0; j < src_grid_cell.num_corners; ++j) {
793 src_cell_centroid[0] += src_grid_cell.coordinates_xyz[j][0];
794 src_cell_centroid[1] += src_grid_cell.coordinates_xyz[j][1];
795 src_cell_centroid[2] += src_grid_cell.coordinates_xyz[j][2];
796 }
797 }
798
799 normalise_vector(src_cell_centroid);
800 src_cell_centroids[i][0] = src_cell_centroid[0];
801 src_cell_centroids[i][1] = src_cell_centroid[1];
802 src_cell_centroids[i][2] = src_cell_centroid[2];
803
804 }
805 free(src_grid_cell.coordinates_xyz);
806 free(src_grid_cell.edge_type);
807
808 return src_cell_centroids;
809}
810
812 struct yac_interp_grid * interp_grid, size_t * src_cells,
813 yac_coordinate_pointer src_cell_centroids, int * skip_src_cell,
814 size_t num_src_cells, size_t * src_cell_neighbours) {
815
816 struct weight_vector_3d * src_cell_gradients =
817 xmalloc(num_src_cells * sizeof(*src_cell_gradients));
818
819 struct yac_const_basic_grid_data * src_basic_grid_data =
821
822 size_t total_num_gradient_weights = 0;
823 size_t max_num_neigh_per_src = 0;
824 for (size_t i = 0; i < num_src_cells; ++i) {
825 src_cell_gradients[i].data = NULL;
826 src_cell_gradients[i].n = 0;
827 size_t curr_num_neigh =
828 src_basic_grid_data->num_vertices_per_cell[src_cells[i]];
829 total_num_gradient_weights += curr_num_neigh + 1;
830 if (max_num_neigh_per_src < curr_num_neigh)
831 max_num_neigh_per_src = curr_num_neigh;
832 }
833 struct weight_vector_data_3d * weight_vector_data_buffer =
834 (total_num_gradient_weights > 0)?
835 (xmalloc(total_num_gradient_weights *
836 sizeof(*weight_vector_data_buffer))):NULL;
837 for (size_t i = 0; i < total_num_gradient_weights; ++i)
838 for (size_t j = 0; j < 3; ++j)
839 weight_vector_data_buffer[i].weight[j] = 0.0;
840
841 struct weight_vector_data_3d * orth_buffer =
842 xmalloc((max_num_neigh_per_src + 1) * sizeof(*orth_buffer));
843
844 // compute gradient in the centroid for each source cell
845 // g_i = O_i(g'_i)
846 // where: O_i(g) = g - C_i*(C_i*g) // makes g orthogonal to C_i
847 // g'_i = (A_(C_k))^-1 * S_ijk(((f_j + f_k) * 0.5 - f_i) *
848 // (C_j x C_k) * |C_j x C_k|^-1 *
849 // asin(|C_j x C_k|))
850 // where: g'_i is the estimated centroid gradient
851 // A_(C_k) is the area of the cell generated by connecting the
852 // barycenters of all neighbour cells
853 // S_ijk is the sum of all edges of the previously described cell in
854 // counterclockwise order
855 // f_i, f_j, and f_k are the mean values of the field over the area of
856 // the respective source cell area
857 // asin(|C_j x C_k|) / |C_j x C_k| ~ 1.0
858 // => g'_i = S_ijk(((f_j + f_k) * 0.5 - f_i) * (C_j x C_k)) / A_(C_k)
859 //
860 // g_i = G_i * f
861 // G_i = S_ijk(((I_j + I_k) * 0.5 - I_i) * (C_j x C_k)) / A_(C_k)
862 // where: G_i is the gradient weight matrix
863 // I_x is a vector of the same size as f, which is all zero except at
864 // position x, where it is one
865 // f is the source field vector
866 for (size_t i = 0, offset = 0, weight_vector_data_buffer_offset = 0;
867 i < num_src_cells; ++i) {
868
869 size_t curr_num_neigh =
870 src_basic_grid_data->num_vertices_per_cell[src_cells[i]];
871 size_t * curr_neighs = src_cell_neighbours + offset;
872 offset += curr_num_neigh;
873 struct weight_vector_3d * G_i = src_cell_gradients + i;
874 G_i->data = weight_vector_data_buffer + weight_vector_data_buffer_offset;
875
876 if (skip_src_cell[i]) continue;
877
878 weight_vector_data_buffer_offset += curr_num_neigh + 1;
879 G_i->n = curr_num_neigh + 1;
880 G_i->data[0].local_id = src_cells[i];
881 G_i->data[0].global_id =
882 src_basic_grid_data->ids[YAC_LOC_CELL][src_cells[i]];
883 for (size_t j = 0; j < curr_num_neigh; ++j) {
884 size_t curr_neigh = curr_neighs[j];
885 // if the current edge has a neighbour
886 if (curr_neigh != SIZE_MAX) {
887 G_i->data[j+1].local_id = curr_neigh;
888 G_i->data[j+1].global_id =
889 src_basic_grid_data->ids[YAC_LOC_CELL][curr_neigh];
890 } else {
891 // if the current edge has no neighbour, use current cell instead
892 G_i->data[j+1].local_id = G_i->data[0].local_id;
893 G_i->data[j+1].global_id = G_i->data[0].global_id;
894 }
895 }
896
897 // area of the polygon that is formed by connecting the barycenters of
898 // the neighbouring cells
899 double A_C_k = 0.0;
900
901 struct yac_grid_cell centroid_triangle = {
902 .coordinates_xyz = (double[3][3]){{0}},
903 .edge_type =
905 .num_corners = 3, .array_size = 0};
906 centroid_triangle.coordinates_xyz[0][0] = src_cell_centroids[i][0];
907 centroid_triangle.coordinates_xyz[0][1] = src_cell_centroids[i][1];
908 centroid_triangle.coordinates_xyz[0][2] = src_cell_centroids[i][2];
909
910 double edge_direction = 0.0;
911
912 // We split the cell that is comprised of the barycenters of the edge
913 // neigbours into triangles, which has the centroid of the current cell
914 // as one corner. The sum of the areas of these triangles is A_C_K.
915 for (size_t j = 0; j < curr_num_neigh; ++j) {
916
917 size_t neigh_idx[2] = {j + 1, (j+1)%curr_num_neigh+1};
918 size_t neigh_local_ids[2] =
919 {G_i->data[neigh_idx[0]].local_id,
920 G_i->data[neigh_idx[1]].local_id};
921
922 if (neigh_local_ids[0] == neigh_local_ids[1]) continue;
923
924 double neigh_cell_barycenters[2][3];
926 src_basic_grid_data, neigh_local_ids[0], neigh_cell_barycenters[0]);
928 src_basic_grid_data, neigh_local_ids[1], neigh_cell_barycenters[1]);
929
930 centroid_triangle.coordinates_xyz[1][0] = neigh_cell_barycenters[0][0];
931 centroid_triangle.coordinates_xyz[1][1] = neigh_cell_barycenters[0][1];
932 centroid_triangle.coordinates_xyz[1][2] = neigh_cell_barycenters[0][2];
933 centroid_triangle.coordinates_xyz[2][0] = neigh_cell_barycenters[1][0];
934 centroid_triangle.coordinates_xyz[2][1] = neigh_cell_barycenters[1][1];
935 centroid_triangle.coordinates_xyz[2][2] = neigh_cell_barycenters[1][2];
936
937 A_C_k += yac_grid_cell_area(centroid_triangle);
938
939 // C_j x C_k
940 double C_j_x_C_k[3];
942 neigh_cell_barycenters[0], neigh_cell_barycenters[1], C_j_x_C_k);
943
944 double curr_edge_direction =
945 C_j_x_C_k[0] * centroid_triangle.coordinates_xyz[0][0] +
946 C_j_x_C_k[1] * centroid_triangle.coordinates_xyz[0][1] +
947 C_j_x_C_k[2] * centroid_triangle.coordinates_xyz[0][2];
948
949 if (fabs(curr_edge_direction) > fabs(edge_direction))
950 edge_direction = curr_edge_direction;
951
952 // -I_i * (C_j x C_k)
953 G_i->data[0].weight[0] -= C_j_x_C_k[0];
954 G_i->data[0].weight[1] -= C_j_x_C_k[1];
955 G_i->data[0].weight[2] -= C_j_x_C_k[2];
956
957 for (size_t l = 0; l < 3; ++l) C_j_x_C_k[l] *= 0.5;
958
959 // 0.5 * I_j * (C_j x C_k)
960 G_i->data[neigh_idx[0]].weight[0] += C_j_x_C_k[0];
961 G_i->data[neigh_idx[0]].weight[1] += C_j_x_C_k[1];
962 G_i->data[neigh_idx[0]].weight[2] += C_j_x_C_k[2];
963
964 // 0.5 * I_k * (C_j x C_k)
965 G_i->data[neigh_idx[1]].weight[0] += C_j_x_C_k[0];
966 G_i->data[neigh_idx[1]].weight[1] += C_j_x_C_k[1];
967 G_i->data[neigh_idx[1]].weight[2] += C_j_x_C_k[2];
968 } // curr_num_neigh
969
970 // if the neighbours were ordered in the wrong direction
971 if (edge_direction > 0.0)
972 for (size_t j = 0; j <= curr_num_neigh; ++j)
973 for (size_t k = 0; k < 3; ++k)
974 G_i->data[j].weight[k] *= -1.0;
975
976 double inv_A_C_K = (A_C_k > YAC_AREA_TOL)?(1.0/A_C_k):0.0;
977 // ((I_j + I_k) * 0.5 - I_i) * (C_j x C_k) / A_(C_k)
978 for (size_t k = 0; k <= curr_num_neigh; ++k)
979 for (size_t l = 0; l < 3; ++l)
980 G_i->data[k].weight[l] *= inv_A_C_K;
981
983 src_cell_centroids[i], G_i, orth_buffer);
984 } // num_src_cells
985 free(orth_buffer);
986
987 return src_cell_gradients;
988}
989
991 size_t * tgt_cells, int * interp_fail_flag, size_t num_tgt_cells,
992 struct supermesh_cell * super_cells, size_t num_super_cells,
993 size_t ** src_per_tgt, double ** weights, size_t * num_src_per_tgt) {
994
995 size_t num_interpolated_tgt = 0;
996
997 // sort supermesh cells first by target local id and second by
998 // source global id
999 qsort(super_cells, num_super_cells, sizeof(*super_cells),
1001
1002 size_t max_num_weights_per_tgt = 0;
1003 size_t max_num_total_weights = 0;
1004
1005 // count maximum number of weights
1006 for (size_t i = 0, j = 0; i < num_tgt_cells; ++i) {
1007
1008 if (interp_fail_flag[i]) continue;
1009
1010 size_t curr_tgt_cell = tgt_cells[i];
1011 size_t curr_num_weights = 0;
1012
1013 // skip supermesh cells not overlapping with current target cell
1014 while ((j < num_super_cells) &&
1015 (super_cells[j].tgt.local_id < curr_tgt_cell)) ++j;
1016
1017 // for all supermesh cells overlapping with the current target cell
1018 while ((j < num_super_cells) &&
1019 (super_cells[j].tgt.local_id == curr_tgt_cell))
1020 curr_num_weights += 1 + super_cells[j++].src_cell_gradient->n;
1021
1022 max_num_total_weights += curr_num_weights;
1023 if (max_num_weights_per_tgt < curr_num_weights)
1024 max_num_weights_per_tgt = curr_num_weights;
1025 num_interpolated_tgt++;
1026 }
1027
1028 struct weight_vector_data * weight_buffer =
1029 xmalloc(max_num_weights_per_tgt * sizeof(*weight_buffer));
1030 *weights = xmalloc(max_num_total_weights * sizeof(**weights));
1031 *src_per_tgt = xmalloc(max_num_total_weights * sizeof(**src_per_tgt));
1032
1033 // sort all target points that can be interpolated to the beginning of the
1034 // tgt_cells array
1035 yac_quicksort_index_int_size_t(interp_fail_flag, num_tgt_cells, tgt_cells);
1036 yac_quicksort_index_size_t_int(tgt_cells, num_interpolated_tgt, NULL);
1037
1038 // compute 2nd order weights
1039 // f_j = SUM(f_k') / A_j
1040 // f_k' = A_k*(f_i + g_i * C_k)
1041 //
1042 // f_k' = A_k * (I_i + C_k * G_i) * f
1043 // where: I_i is a vector of the same length as f, that is all 0.0 except at
1044 // position i, where it is 1.0
1045 // f is the source field vector
1046 // => f_k' / A_j = M_k * f
1047 // where: M_k = A_k / A_j * (I_i + C_k * G_i)
1048 // => f_j = SUM(M_k) * f
1049 // f_j = M_j * f
1050 // where: M_j = SUM(M_k)
1051 size_t w_idx = 0;
1052 for (size_t i = 0, j = 0; i < num_interpolated_tgt; ++i) {
1053
1054 size_t curr_tgt_cell = tgt_cells[i];
1055
1056 // skip supermesh cells not overlapping with current target cell
1057 while ((j < num_super_cells) &&
1058 (super_cells[j].tgt.local_id != curr_tgt_cell)) ++j;
1059
1060 size_t weight_buffer_offset = 0;
1061
1062 // for all supermesh cells overlapping with the current target cell
1063 while ((j < num_super_cells) &&
1064 (super_cells[j].tgt.local_id == curr_tgt_cell)) {
1065
1066 size_t num_weights =
1068 super_cells + j, weight_buffer + weight_buffer_offset);
1069 weight_buffer_offset += num_weights;
1070 ++j;
1071 }
1072
1073 // compact weights and sort them by global_id
1074 compact_weight_vector_data(weight_buffer, &weight_buffer_offset);
1075
1076 num_src_per_tgt[i] = weight_buffer_offset;
1077
1078 for (size_t k = 0; k < weight_buffer_offset; ++k, ++w_idx) {
1079 (*weights)[w_idx] = weight_buffer[k].weight;
1080 (*src_per_tgt)[w_idx] = weight_buffer[k].local_id;
1081 }
1082 }
1083 free(weight_buffer);
1084
1085 return num_interpolated_tgt;
1086}
1087
1088static size_t do_search_conserv_2nd_order (struct interp_method * method,
1089 struct yac_interp_grid * interp_grid,
1090 size_t * tgt_points, size_t count,
1091 struct yac_interp_weights * weights,
1092 int * interpolation_complete) {
1093
1094 if (*interpolation_complete) return 0;
1095
1096 struct interp_method_conserv * method_conserv =
1097 (struct interp_method_conserv *)method;
1098
1099 CHECK_SRC_FIELD_COUNT_SINGLE(interp_grid)
1100
1102
1104
1105 // sort target points
1106 yac_quicksort_index_size_t_int(tgt_points, count, NULL);
1107
1108 int * interp_fail_flag = xmalloc(count * sizeof(*interp_fail_flag));
1109 struct supermesh_cell * super_cells = NULL;
1110 size_t num_super_cells = 0;
1111 size_t * src_cells = NULL;
1112 size_t num_src_cells = 0;
1113
1114 // compute the overlaps between the target cells and the source grid
1116 interp_grid, tgt_points, count, &super_cells, &num_super_cells,
1117 interp_fail_flag, &src_cells, &num_src_cells,
1118 method_conserv->normalisation, method_conserv->partial_coverage);
1119
1120 size_t total_num_src_cell_neighbours = 0;
1121 struct yac_const_basic_grid_data * src_basic_grid_data =
1123 for (size_t i = 0; i < num_src_cells; ++i)
1124 total_num_src_cell_neighbours +=
1125 src_basic_grid_data->num_vertices_per_cell[src_cells[i]];
1126 size_t * src_cell_neighbours =
1127 xmalloc(total_num_src_cell_neighbours * sizeof(*src_cell_neighbours));
1128
1129 // get the neighbours for all source cells overlapping with a target cell
1131 interp_grid, src_cells, num_src_cells, src_cell_neighbours);
1132
1133 const_int_pointer src_cell_mask =
1134 yac_interp_grid_get_src_field_mask(interp_grid, 0);
1135 int * skip_src_cell = xmalloc(num_src_cells * sizeof(*skip_src_cell));
1136
1137 // check whether any required source cell or any of its neighbours is masked
1138 // out in the field mask (deactivate respective cells)
1139 if (src_cell_mask != NULL) {
1140 for (size_t i = 0, offset = 0; i < num_src_cells; ++i) {
1141 size_t curr_src_cell = src_cells[i];
1142 if ((skip_src_cell[i] = !src_cell_mask[curr_src_cell])) continue;
1143 size_t * curr_neighbours = src_cell_neighbours + offset;
1144 size_t curr_num_neigh =
1145 src_basic_grid_data->num_vertices_per_cell[curr_src_cell];
1146 offset += curr_num_neigh;
1147 for (size_t j = 0; j < curr_num_neigh; ++j)
1148 if ((curr_neighbours[j] != SIZE_MAX) &&
1149 (!src_cell_mask[curr_neighbours[j]]))
1150 curr_neighbours[j] = SIZE_MAX;
1151 }
1152 } else {
1153 memset(skip_src_cell, 0, num_src_cells * sizeof(*skip_src_cell));
1154 }
1155
1156 // compute the centroids of all required source cells
1157 yac_coordinate_pointer src_cell_centroids =
1158 compute_src_cell_centroids(interp_grid, src_cells, skip_src_cell,
1159 num_src_cells, super_cells, num_super_cells);
1160
1161 // compute the gradients weights for the source cells
1162 struct weight_vector_3d * src_cell_gradients =
1164 interp_grid, src_cells, src_cell_centroids,
1165 skip_src_cell, num_src_cells, src_cell_neighbours);
1166 free(src_cell_neighbours);
1167 free(src_cell_centroids);
1168
1169 // sort supermesh cells by local src id
1170 qsort(super_cells, num_super_cells, sizeof(*super_cells),
1172 for (size_t i = 0, j = 0; i < num_src_cells; ++i) {
1173 size_t curr_src_cell = src_cells[i];
1174 struct weight_vector_3d * curr_src_cell_gradient = src_cell_gradients + i;
1175 // there should not be any supercell whose source cell is not in the list of
1176 // required source cells
1177 YAC_ASSERT(
1178 (j >= num_super_cells) ||
1179 (super_cells[j].src.local_id >= curr_src_cell), "internal error");
1180 while ((j < num_super_cells) &&
1181 (super_cells[j].src.local_id == curr_src_cell)) {
1182 super_cells[j++].src_cell_gradient = curr_src_cell_gradient;
1183 }
1184 }
1185 free(skip_src_cell);
1186 free(src_cells);
1187
1188 size_t * src_per_tgt = NULL;
1189 double * w = NULL;
1190 size_t * num_src_per_tgt = xmalloc(count * sizeof(*num_src_per_tgt));
1191
1192 // compute the weights for the target points
1193 size_t num_interpolated_tgt =
1195 tgt_points, interp_fail_flag, count, super_cells, num_super_cells,
1196 &src_per_tgt, &w, num_src_per_tgt);
1197 if (num_src_cells > 0) free(src_cell_gradients->data);
1198 free(src_cell_gradients);
1199 free(super_cells);
1200 free(interp_fail_flag);
1201
1202 size_t total_num_weights = 0;
1203 for (size_t i = 0; i < num_interpolated_tgt; ++i)
1204 total_num_weights += num_src_per_tgt[i];
1205
1206 struct remote_points tgts = {
1207 .data =
1209 interp_grid, tgt_points, num_interpolated_tgt),
1210 .count = num_interpolated_tgt};
1211 struct remote_point * srcs =
1213 interp_grid, 0, src_per_tgt, total_num_weights);
1214
1215 // store weights
1217 weights, &tgts, num_src_per_tgt, srcs, w);
1218
1219 free(tgts.data);
1220 free(srcs);
1221 free(w);
1222 free(num_src_per_tgt);
1223 free(src_per_tgt);
1224
1225 return num_interpolated_tgt;
1226}
1227
1229 int order, int enforced_conserv, int partial_coverage,
1230 enum yac_interp_method_conserv_normalisation normalisation) {
1231
1232 struct interp_method_conserv * method = xmalloc(1 * sizeof(*method));
1233
1234 YAC_ASSERT(
1235 (enforced_conserv != 1) || (order == 1),
1236 "interp_method_conserv only "
1237 "supports enforced_conserv with first order conservative remapping")
1238 YAC_ASSERT(
1239 (order == 1) || (order == 2), "invalid order")
1240
1241 method->vtable =
1242 (order == 1)?
1246 method->normalisation = normalisation;
1248
1249 return (struct interp_method*)method;
1250}
1251
1252static void delete_conserv(struct interp_method * method) {
1253 free(method);
1254}
1255
1256// --- Modular config struct and vtable for CONSERVATIVE method ---
1257
1272
1275 free(config);
1276}
1277
1279 const struct yac_interp_method_config *config) {
1282 xmalloc(sizeof(*copy));
1283 copy->base.vtable = config_conserv->base.vtable;
1284 copy->base.root_param_cache = NULL;
1285 copy->config = config_conserv->config;
1286 return (struct yac_interp_method_config *)copy;
1287}
1288
1290 void const *a_, void const *b_) {
1292 // Compare conservative interpolation parameters in order of significance
1293 // 1. Order of the conservative method (1=first order, 2=second order)
1294 CHECK_INT(config.order);
1295 // 2. Enforced conservation flag (0=off, 1=on)
1296 // If true, weights are scaled to sum to 1.0 (only for first order)
1297 CHECK_INT(config.enforced_conserv);
1298 // 3. Partial coverage flag (0=off, 1=on)
1299 // If false, target cells not fully covered by source cells are
1300 // not interpolated
1301 CHECK_INT(config.partial_coverage);
1302 // 4. Area normalisation method (destarea, fracarea, ...)
1303 // See SCRIP documentation for details
1304 CHECK_ENUM(config.normalisation);
1305 return 0;
1306}
1307
1308// Returns the MPI pack size for a conserv config
1310 struct yac_interp_method_config const *config, MPI_Comm comm) {
1311 UNUSED(config);
1312 int int_pack_size;
1313 yac_mpi_call(MPI_Pack_size(1, MPI_INT, comm, &int_pack_size), comm);
1314 // order (int), enforced_conserv (int), partial_coverage (int),
1315 // normalisation (int)
1316 return 4 * (size_t)int_pack_size;
1317}
1318
1319// Packs a conserv config into a buffer
1321 struct yac_interp_method_config const *config,
1322 void *buffer, int buffer_size, int *position, MPI_Comm comm) {
1325 MPI_Pack(
1326 &config_conserv->config.order, 1, MPI_INT, buffer, buffer_size, position,
1327 comm), comm);
1329 MPI_Pack(
1330 &config_conserv->config.enforced_conserv, 1, MPI_INT, buffer, buffer_size,
1331 position, comm), comm);
1333 MPI_Pack(
1334 &config_conserv->config.partial_coverage, 1, MPI_INT, buffer, buffer_size,
1335 position, comm), comm);
1336 int normalisation = (int)config_conserv->config.normalisation;
1338 MPI_Pack(
1339 &normalisation, 1, MPI_INT, buffer, buffer_size, position, comm), comm);
1340}
1341
1342// Gets interpolation method typed_config_hcsbb_get_type
1346
1348 struct yac_interp_method_config const *config) {
1349 const struct yac_interp_method_config_conserv *config_conserv =
1352 config_conserv->config.order,
1353 config_conserv->config.enforced_conserv,
1354 config_conserv->config.partial_coverage,
1355 config_conserv->config.normalisation);
1356}
1357
1359 struct yac_interp_method_config const *config) {
1360 struct yac_interp_method_config_conserv *config_conserv =
1362
1363 enum {
1364 ORDER_HAS_DEFAULT = 1,
1365 ORDER_IS_DEFINED = 1,
1366 ENFORCED_CONSERV_HAS_DEFAULT = 1,
1367 ENFORCED_CONSERV_IS_DEFINED = 1,
1368 PARTIAL_COVERAGE_HAS_DEFAULT = 1,
1369 PARTIAL_COVERAGE_IS_DEFINED = 1,
1370 NORMALISATION_HAS_DEFAULT = 1,
1371 NORMALISATION_IS_DEFINED = 1,
1372 };
1373
1374 int const order_min_value = 1;
1375 int const order_max_value = 2;
1376
1377 struct yac_param *param_order =
1379 "order",
1380 &config_conserv->config.order,
1382 order_min_value, order_max_value,
1383 ORDER_HAS_DEFAULT, ORDER_IS_DEFINED);
1384
1385 struct yac_param *param_enforced_conserv =
1387 "enforced_conservation",
1388 &config_conserv->config.enforced_conserv,
1390 ENFORCED_CONSERV_HAS_DEFAULT, ENFORCED_CONSERV_IS_DEFINED);
1391
1392 struct yac_param *param_partial_coverage =
1394 "partial_coverage",
1395 &config_conserv->config.partial_coverage,
1397 PARTIAL_COVERAGE_HAS_DEFAULT, PARTIAL_COVERAGE_IS_DEFINED);
1398
1400 normalisation_enum_table,
1403
1404 struct yac_param *param_normalisation =
1406 "normalisation",
1407 (int *)&config_conserv->config.normalisation,
1409 normalisation_enum_table, normalisation_enum_table_size,
1410 NORMALISATION_HAS_DEFAULT, NORMALISATION_IS_DEFINED);
1411
1412 struct yac_param *root_param_array[] = {
1413 param_order,
1414 param_enforced_conserv,
1415 param_partial_coverage,
1416 param_normalisation
1417 };
1418 enum {
1419 ROOT_PARAM_ARRAY_SIZE =
1420 sizeof(root_param_array) / sizeof(root_param_array[0])
1421 };
1422
1423 return yac_param_struct_new(
1424 "conservative", root_param_array, ROOT_PARAM_ARRAY_SIZE);
1425}
1426
1437
1439 struct yac_interp_method_config_conserv *config_conserv =
1440 xmalloc(sizeof(*config_conserv));
1442 config_conserv->base.root_param_cache = NULL;
1443 config_conserv->config = (struct yac_interp_method_conserv_config){
1448 };
1449 return (struct yac_interp_method_config *)config_conserv;
1450}
1451
1452// Unpacks a conserv config from a buffer
1454 void *buffer, int buffer_size, int *position, MPI_Comm comm) {
1455 struct yac_interp_method_config_conserv *config_conserv =
1456 xmalloc(sizeof(*config_conserv));
1458 config_conserv->base.root_param_cache = NULL;
1460 MPI_Unpack(
1461 buffer, buffer_size, position, &config_conserv->config.order, 1, MPI_INT,
1462 comm), comm);
1464 MPI_Unpack(
1465 buffer, buffer_size, position, &config_conserv->config.enforced_conserv, 1,
1466 MPI_INT, comm), comm);
1468 MPI_Unpack(
1469 buffer, buffer_size, position, &config_conserv->config.partial_coverage, 1,
1470 MPI_INT, comm), comm);
1471 int normalisation;
1473 MPI_Unpack(
1474 buffer, buffer_size, position, &normalisation, 1, MPI_INT, comm), comm);
1475 config_conserv->config.normalisation =
1476 (enum yac_interp_method_conserv_normalisation)normalisation;
1477 return (struct yac_interp_method_config *)config_conserv;
1478}
#define YAC_ASSERT(exp, msg)
double yac_grid_cell_area(struct yac_grid_cell cell)
Area calculation of a spherical cell.
Definition area.c:269
Structs and interfaces for area calculations.
#define YAC_AREA_TOL
Definition area.h:18
static int edge_direction(double *a, double *b)
void yac_correct_weights(size_t nSourceCells, double *weight)
correct interpolation weights
Definition clipping.c:1430
void yac_compute_overlap_info(size_t N, struct yac_grid_cell *source_cell, struct yac_grid_cell target_cell, double *overlap_areas, double(*overlap_barycenters)[3])
calculates partial areas for all overlapping parts of the source cells with arbitrary target cells,...
Definition clipping.c:119
void yac_compute_overlap_areas(size_t N, struct yac_grid_cell *source_cell, struct yac_grid_cell target_cell, double *partial_areas)
calculates partial areas for all overlapping parts of the source cells with arbitrary target cells,...
Definition clipping.c:274
void yac_compute_overlap_buf_free()
Definition clipping.c:88
#define UNUSED(x)
Definition core.h:72
void yac_const_basic_grid_data_get_grid_cell(struct yac_const_basic_grid_data *grid_data, size_t cell_idx, struct yac_grid_cell *buffer_cell)
Definition dist_grid.c:2418
int const * const_int_pointer
static void crossproduct_kahan(double const a[], double const b[], double cross[])
Definition geometry.h:405
static void normalise_vector(double v[])
Definition geometry.h:743
yac_edge_type
Definition grid_cell.h:12
@ YAC_GREAT_CIRCLE_EDGE
great circle
Definition grid_cell.h:13
#define DEF_NAME_TYPE_PAIR(NAME, TYPE)
#define DEF_NAME_TYPE_PAIRS(NAME,...)
void yac_interp_grid_do_cell_search_tgt(struct yac_interp_grid *interp_grid, size_t *src_cells, size_t count, size_t **tgt_cells, size_t *num_tgt_per_src)
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_src_cell_neighbours(struct yac_interp_grid *interp_grid, size_t *src_cells, size_t count, size_t *neighbours)
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)
struct yac_const_basic_grid_data * yac_interp_grid_get_basic_grid_data_tgt(struct yac_interp_grid *interp_grid)
void yac_interp_grid_do_cell_search_src(struct yac_interp_grid *interp_grid, size_t *tgt_cells, size_t count, size_t **src_cells, size_t *num_src_per_tgt)
struct yac_const_basic_grid_data * yac_interp_grid_get_basic_grid_data_src(struct yac_interp_grid *interp_grid)
yac_interpolation_list
@ YAC_CONSERVATIVE
Conservative remapping (area/flux conserving)
#define DEF_INTERP_METHOD_CONFIG_COMPARE_TYPE(TYPE)
#define DEF_INTERP_METHOD_CONFIG_TYPE(TYPE)
static void delete_conserv(struct interp_method *method)
static struct yac_param * config_conserv_get_param(struct yac_interp_method_config const *config)
static void get_cell_buffers_(struct yac_interp_grid *interp_grid, struct yac_grid_cell *tgt_grid_cell, struct yac_grid_cell *src_grid_cell)
static size_t config_conserv_get_pack_size(struct yac_interp_method_config const *config, MPI_Comm comm)
struct yac_interp_method_config * yac_interp_method_config_conserv_unpack(void *buffer, int buffer_size, int *position, MPI_Comm comm)
Unpacks a conservative interpolation method configuration from a buffer.
static int config_conserv_compare(void const *a_, void const *b_)
static struct yac_interp_method_config * config_conserv_copy(const struct yac_interp_method_config *config)
static void config_conserv_pack(struct yac_interp_method_config const *config, void *buffer, int buffer_size, int *position, MPI_Comm comm)
static size_t compute_2nd_order_weights(size_t *tgt_cells, int *interp_fail_flag, size_t num_tgt_cells, struct supermesh_cell *super_cells, size_t num_super_cells, size_t **src_per_tgt, double **weights, size_t *num_src_per_tgt)
static struct interp_method * config_conserv_generate(struct yac_interp_method_config const *config)
static size_t do_search_conserv_1st_order(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 yac_coordinate_pointer compute_src_cell_centroids(struct yac_interp_grid *interp_grid, size_t *src_cells, int *skip_src_cell, size_t num_src_cells, struct supermesh_cell *super_cells, size_t num_super_cells)
static void get_cell_buffers(struct yac_interp_grid *interp_grid, size_t max_num_src_per_tgt, struct yac_grid_cell *tgt_grid_cell, struct yac_grid_cell **src_grid_cells)
#define AREA_TOL_FACTOR
static void compute_cell_barycenter(struct yac_const_basic_grid_data *grid_data, size_t cell_idx, double barycenter[3])
static void compact_weight_vector_data(struct weight_vector_data *weights, size_t *n)
static struct interp_method_vtable interp_method_conserv_2nd_order_vtable
static enum yac_interpolation_list config_conserv_get_type()
static struct yac_interp_method_config_vtable yac_interp_method_config_vtable_conserv
struct interp_method * yac_interp_method_conserv_new(int order, int enforced_conserv, int partial_coverage, enum yac_interp_method_conserv_normalisation normalisation)
static int get_max_num_vertices_per_cell(struct yac_const_basic_grid_data *basic_grid_data)
static void compute_super_cells(struct yac_interp_grid *interp_grid, size_t *tgt_points, size_t count, struct supermesh_cell **super_cells_, size_t *num_super_cells, int *interp_fail_flag, size_t **src_cells, size_t *num_src_cells, enum yac_interp_method_conserv_normalisation normalisation, int partial_coverage)
static int compare_supermesh_cell_tgt_local_ids(const void *a, const void *b)
static void orthogonalise_weight_vector(double *src_cell_centroid, struct weight_vector_3d *G_i, struct weight_vector_data_3d *buffer)
struct yac_interp_method_config * yac_interp_method_config_default_conserv_new(void)
Creates a conservative interpolation method configuration with default parameters.
static struct interp_method_vtable interp_method_conserv_1st_order_vtable
static void config_conserv_delete(struct yac_interp_method_config *config)
static int compare_supermesh_cell_src_local_ids(const void *a, const void *b)
static size_t do_search_conserv_2nd_order(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 size_t compute_2nd_order_tgt_cell_weights(struct supermesh_cell *super_cell, struct weight_vector_data *weights)
static int compare_weight_vector_data_weight(void const *a, void const *b)
static int compare_weight_vector_data(void const *a, void const *b)
static struct weight_vector_3d * compute_src_cell_gradients(struct yac_interp_grid *interp_grid, size_t *src_cells, yac_coordinate_pointer src_cell_centroids, int *skip_src_cell, size_t num_src_cells, size_t *src_cell_neighbours)
static int compute_1st_order_weights(struct yac_const_basic_grid_data *tgt_basic_grid_data, size_t tgt_cell, struct yac_const_basic_grid_data *src_basic_grid_data, size_t src_count, size_t *src_cells, struct yac_grid_cell tgt_grid_cell_buffer, struct yac_grid_cell *src_grid_cell_buffer, double *weights, size_t *num_weights, int partial_coverage, enum yac_interp_method_conserv_normalisation normalisation, int enforced_conserv)
#define YAC_INTERP_CONSERV_NORMALISATION_DEFAULT
#define YAC_INTERP_CONSERV_ENFORCED_CONSERV_DEFAULT
#define YAC_INTERP_CONSERV_PARTIAL_COVERAGE_DEFAULT
#define YAC_INTERP_CONSERV_ORDER_DEFAULT
yac_interp_method_conserv_normalisation
@ YAC_INTERP_CONSERV_DESTAREA
@ YAC_INTERP_CONSERV_FRACAREA
#define CHECK_TGT_FIELD_LOCATION_CELL(INTERP_GRID)
#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_CELL
Definition location.h:14
Definition __init__.py:1
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:150
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:139
struct yac_param * yac_param_int_new(const char *name, int *value_ptr, int default_value, int value_min, int value_max, int has_default, int is_defined)
Create an int parameter.
Definition param_int.c:154
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 xrealloc(ptr, size)
Definition ppm_xfuncs.h:67
#define xmalloc(size)
Definition ppm_xfuncs.h:66
enum yac_interp_method_conserv_normalisation normalisation
struct interp_method_vtable * vtable
size_t(* do_search)(struct interp_method *method, struct yac_interp_grid *grid, size_t *tgt_points, size_t count, struct yac_interp_weights *weights, int *interpolation_complete)
information (global id and location) about a point that
structure containing the information (global id and location)
struct remote_point * data
struct weight_vector_3d * src_cell_gradient
struct supermesh_cell::@25 src
struct supermesh_cell::@25 tgt
struct weight_vector_data_3d * data
const const_int_pointer num_vertices_per_cell
const const_yac_int_pointer ids[3]
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
Concrete implementation of yac_interp_method_config for the conservative method.
struct yac_interp_method_config base
‍base config object, must be first entry
struct yac_interp_method_conserv_config config
‍method-specific configuration
void(* delete)(struct yac_interp_method_config *config)
struct yac_interp_method_config_vtable const * vtable
enum yac_interp_method_conserv_normalisation normalisation
static struct yac_interp_method_config * config
#define N
double * buffer
#define MAX(a, b)
void yac_quicksort_index_yac_int_size_t(yac_int *a, size_t n, size_t *idx)
void yac_quicksort_index_int_size_t(int *a, size_t n, size_t *idx)
static void yac_remove_duplicates_size_t(size_t *array, size_t *n)
Definition utils_core.h:100
void yac_quicksort_index_size_t_int(size_t *a, size_t n, int *idx)
#define YAC_UNREACHABLE_DEFAULT(msg)
Definition yac_assert.h:56
#define yac_mpi_call(call, comm)
YAC_INT yac_int
Definition yac_types.h:15
double(* yac_coordinate_pointer)[3]
Definition yac_types.h:21