YAC 3.7.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
14#include "clipping.h"
15#include "area.h"
16#include "float.h"
17
18#define AREA_TOL_FACTOR (1e-6)
19
20static size_t do_search_conserv_1st_order(struct interp_method * method,
21 struct yac_interp_grid * interp_grid,
22 size_t * tgt_points, size_t count,
23 struct yac_interp_weights * weights,
24 int * interpolation_complete);
25static size_t do_search_conserv_2nd_order(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,
29 int * interpolation_complete);
30static void delete_conserv(struct interp_method * method);
31
32static struct interp_method_vtable
36
37static struct interp_method_vtable
41
49
55
61
64 size_t n;
65};
66
68 struct {
69 size_t local_id;
71 } src, tgt;
72 double norm_area;
73 double area;
74 double barycenter[3];
76};
77
79 struct yac_const_basic_grid_data * basic_grid_data) {
80
81 int max_num_vertices_per_cell = 0;
82 for (size_t i = 0; i < basic_grid_data->count[YAC_LOC_CELL]; ++i)
83 if (basic_grid_data->num_vertices_per_cell[i] >
84 max_num_vertices_per_cell)
85 max_num_vertices_per_cell =
86 basic_grid_data->num_vertices_per_cell[i];
87 return max_num_vertices_per_cell;
88}
89
90static void get_cell_buffers(
91 struct yac_interp_grid * interp_grid, size_t max_num_src_per_tgt,
92 struct yac_grid_cell * tgt_grid_cell, struct yac_grid_cell ** src_grid_cells) {
93
94 struct yac_const_basic_grid_data * src_basic_grid_data =
96 struct yac_const_basic_grid_data * tgt_basic_grid_data =
98
99 *src_grid_cells = xmalloc(max_num_src_per_tgt * sizeof(**src_grid_cells));
100 enum yac_edge_type * edge_type_buffer;
101 double (*coordinates_xyz_buffer)[3];
102
103 // prepare source grid cell buffer
104 {
105 int max_num_vertices_per_cell =
106 MAX(get_max_num_vertices_per_cell(src_basic_grid_data),
107 get_max_num_vertices_per_cell(tgt_basic_grid_data));
108
109 edge_type_buffer =
110 xmalloc((max_num_src_per_tgt + 1) * (size_t)max_num_vertices_per_cell *
111 sizeof(*edge_type_buffer));
112 coordinates_xyz_buffer =
113 xmalloc((max_num_src_per_tgt + 1) * (size_t)max_num_vertices_per_cell *
114 sizeof(*coordinates_xyz_buffer));
115
116 tgt_grid_cell->coordinates_xyz = coordinates_xyz_buffer;
117 tgt_grid_cell->edge_type = edge_type_buffer;
118 tgt_grid_cell->array_size = max_num_vertices_per_cell;
119 for (size_t i = 0; i < max_num_src_per_tgt; ++i) {
120 (*src_grid_cells)[i].coordinates_xyz =
121 coordinates_xyz_buffer + (i + 1) * max_num_vertices_per_cell;
122 (*src_grid_cells)[i].edge_type =
123 edge_type_buffer + (i + 1) * max_num_vertices_per_cell;
124 (*src_grid_cells)[i].array_size = max_num_vertices_per_cell;
125 }
126 }
127}
128
130 struct yac_interp_grid * interp_grid,
131 struct yac_grid_cell * tgt_grid_cell, struct yac_grid_cell * src_grid_cell) {
132
133 struct yac_const_basic_grid_data * src_basic_grid_data =
135 struct yac_const_basic_grid_data * tgt_basic_grid_data =
137
138 int max_num_vertices_per_cell =
139 MAX(get_max_num_vertices_per_cell(src_basic_grid_data),
140 get_max_num_vertices_per_cell(tgt_basic_grid_data));
141
142 enum yac_edge_type * edge_type_buffer =
143 xmalloc(2 * (size_t)max_num_vertices_per_cell *
144 sizeof(*edge_type_buffer));
145 yac_coordinate_pointer coordinates_xyz_buffer =
146 xmalloc(2 * (size_t)max_num_vertices_per_cell *
147 sizeof(*coordinates_xyz_buffer));
148
149 tgt_grid_cell->coordinates_xyz = coordinates_xyz_buffer;
150 tgt_grid_cell->edge_type = edge_type_buffer;
151 tgt_grid_cell->array_size = max_num_vertices_per_cell;
152
153 src_grid_cell->coordinates_xyz =
154 coordinates_xyz_buffer + max_num_vertices_per_cell;
155 src_grid_cell->edge_type =
156 edge_type_buffer + max_num_vertices_per_cell;
157 src_grid_cell->array_size = max_num_vertices_per_cell;
158}
159
161 struct yac_const_basic_grid_data * tgt_basic_grid_data, size_t tgt_cell,
162 struct yac_const_basic_grid_data * src_basic_grid_data, size_t src_count,
163 size_t * src_cells, struct yac_grid_cell tgt_grid_cell_buffer,
164 struct yac_grid_cell * src_grid_cell_buffer,
165 double * weights, size_t * num_weights, int partial_coverage,
167 int enforced_conserv) {
168
170 tgt_basic_grid_data, tgt_cell, &tgt_grid_cell_buffer);
171 for (size_t i = 0; i < src_count; ++i)
173 src_basic_grid_data, src_cells[i], src_grid_cell_buffer + i);
174
175 double * area = weights;
177 src_count, src_grid_cell_buffer, tgt_grid_cell_buffer, area);
178
179 size_t num_valid_weights = 0;
180 for (size_t i = 0; i < src_count; ++i) {
181
182 if (area[i] > 0.0) {
183 if (i != num_valid_weights) {
184 area[num_valid_weights] = area[i];
185 src_cells[num_valid_weights] = src_cells[i];
186 }
187 ++num_valid_weights;
188 }
189 }
190 *num_weights = num_valid_weights;
191 if (num_valid_weights == 0) return 0;
192
193 double tgt_cell_area = yac_huiliers_area(tgt_grid_cell_buffer);
194 double norm_factor;
195
197 (normalisation == YAC_INTERP_CONSERV_DESTAREA) ||
198 (normalisation == YAC_INTERP_CONSERV_FRACAREA),
199 "ERROR(compute_weights_order_first_conserv_no_partial): "
200 "invalid normalisation option in conservative remapping")
201 switch(normalisation) {
203 norm_factor = 1.0 / tgt_cell_area;
204 break;
205 default:
207 double fracarea = 0.0;
208 for (size_t i = 0; i < num_valid_weights; ++i) fracarea += area[i];
209 norm_factor = 1.0 / fracarea;
210 break;
211 }
212 };
213
214 if (partial_coverage) {
215 for (size_t i = 0; i < num_valid_weights; ++i) weights[i] *= norm_factor;
216 return 1;
217 } else {
218 double tgt_cell_area_diff = tgt_cell_area;
219 double area_tol = tgt_cell_area * AREA_TOL_FACTOR;
220 for (size_t i = 0; i < num_valid_weights; ++i) {
221 double curr_area = area[i];
222 tgt_cell_area_diff -= curr_area;
223 weights[i] = curr_area * norm_factor;
224 }
225 int successful = fabs(tgt_cell_area_diff) <= area_tol;
226 if (successful && enforced_conserv)
227 yac_correct_weights(num_valid_weights, weights);
228 return successful;
229 }
230}
231
232static size_t do_search_conserv_1st_order (struct interp_method * method,
233 struct yac_interp_grid * interp_grid,
234 size_t * tgt_points, size_t count,
235 struct yac_interp_weights * weights,
236 int * interpolation_complete) {
237
238 if (*interpolation_complete) return 0;
239
240 struct interp_method_conserv * method_conserv =
241 (struct interp_method_conserv *)method;
242
244 yac_interp_grid_get_num_src_fields(interp_grid) == 1,
245 "ERROR(do_search_conserv): invalid number of source fields")
246
249 "ERROR(do_search_conserv): unsupported source field location type")
250
253 "ERROR(do_search_conserv): unsupported target field location type")
254
255
256 size_t * src_cells = NULL;
257 size_t * num_src_per_tgt = xmalloc(count * sizeof(*num_src_per_tgt));
258
259 // search matching cells
261 interp_grid, tgt_points, count, &src_cells, num_src_per_tgt);
262
263 // we did a search on the interp_grid, therefore we have to re-get the basic
264 // grid data
265 struct yac_const_basic_grid_data * tgt_basic_grid_data =
267 struct yac_const_basic_grid_data * src_basic_grid_data =
269
270 size_t total_num_weights = 0;
271 size_t max_num_src_per_tgt = 0;
272 for (size_t i = 0; i < count; ++i) {
273 size_t curr_num_src_per_tgt = num_src_per_tgt[i];
274 if (curr_num_src_per_tgt > max_num_src_per_tgt)
275 max_num_src_per_tgt = curr_num_src_per_tgt;
276 total_num_weights += num_src_per_tgt[i];
277 }
278
279 // to ensure that the interpolation always procduces the same result, we
280 // sort the source cells for each target point by their global ids
281 {
282 yac_int * temp_src_global_ids =
283 xmalloc(max_num_src_per_tgt * sizeof(*temp_src_global_ids));
284
285 for (size_t i = 0, offset = 0; i < count; ++i) {
286
287 size_t curr_num_src_per_tgt = num_src_per_tgt[i];
288 size_t * curr_src_cells = src_cells + offset;
289 offset += curr_num_src_per_tgt;
290
291 for (size_t j = 0; j < curr_num_src_per_tgt; ++j)
292 temp_src_global_ids[j] =
293 src_basic_grid_data->ids[YAC_LOC_CELL][curr_src_cells[j]];
294
296 temp_src_global_ids, curr_num_src_per_tgt, curr_src_cells);
297 }
298
299 free(temp_src_global_ids);
300 }
301
302 double * w = xmalloc(total_num_weights * sizeof(*w));
303 size_t result_count = 0;
304 size_t * failed_tgt = xmalloc(count * sizeof(*failed_tgt));
305 total_num_weights = 0;
306
307 int partial_coverage = method_conserv->partial_coverage;
308 enum yac_interp_method_conserv_normalisation normalisation =
309 method_conserv->normalisation;
310 int enforced_conserv = method_conserv->enforced_conserv;
311
312 struct yac_grid_cell tgt_grid_cell;
313 struct yac_grid_cell * src_grid_cells;
315 interp_grid, max_num_src_per_tgt, &tgt_grid_cell, &src_grid_cells);
316
317 // compute overlaps
318 for (size_t i = 0, offset = 0, result_offset = 0; i < count; ++i) {
319
320 size_t curr_src_count = num_src_per_tgt[i];
321 size_t curr_tgt_point = tgt_points[i];
322 size_t num_weights;
323
324 // if weight computation was successful
326 tgt_basic_grid_data, curr_tgt_point,
327 src_basic_grid_data, curr_src_count, src_cells + offset,
328 tgt_grid_cell, src_grid_cells, w + result_offset, &num_weights,
329 partial_coverage, normalisation, enforced_conserv)) {
330
331 if (offset != result_offset) {
332
333 memmove(
334 src_cells + result_offset, src_cells + offset,
335 num_weights * sizeof(*src_cells));
336 }
337 tgt_points[result_count] = curr_tgt_point;
338 num_src_per_tgt[result_count] = num_weights;
339 result_count++;
340 result_offset += num_weights;
341 total_num_weights += num_weights;
342 } else {
343 failed_tgt[i - result_count] = curr_tgt_point;
344 }
345
346 offset += curr_src_count;
347 }
348
350 free(tgt_grid_cell.edge_type);
351 free(tgt_grid_cell.coordinates_xyz);
352 free(src_grid_cells);
353
354 if (result_count != count)
355 memcpy(tgt_points + result_count, failed_tgt,
356 (count - result_count) * sizeof(*tgt_points));
357 free(failed_tgt);
358
359 struct remote_points tgts = {
360 .data =
362 interp_grid, tgt_points, result_count),
363 .count = result_count};
364 struct remote_point * srcs =
366 interp_grid, 0, src_cells, total_num_weights);
367
368 // store weights
370 weights, &tgts, num_src_per_tgt, srcs, w);
371
372 free(tgts.data);
373 free(srcs);
374 free(src_cells);
375 free(num_src_per_tgt);
376 free(w);
377
378 return result_count;
379}
380
381static int
382compare_supermesh_cell_src_local_ids(const void * a, const void * b) {
383
384 struct supermesh_cell * a_ = (struct supermesh_cell *)a;
385 struct supermesh_cell * b_ = (struct supermesh_cell *)b;
386
387 int ret = (a_->src.local_id > b_->src.local_id) -
388 (a_->src.local_id < b_->src.local_id);
389 if (ret) return ret;
390 return (a_->tgt.global_id > b_->tgt.global_id) -
391 (a_->tgt.global_id < b_->tgt.global_id);
392}
393
394static int
395compare_supermesh_cell_tgt_local_ids(const void * a, const void * b) {
396
397 struct supermesh_cell * a_ = (struct supermesh_cell *)a;
398 struct supermesh_cell * b_ = (struct supermesh_cell *)b;
399
400 int ret = (a_->tgt.local_id > b_->tgt.local_id) -
401 (a_->tgt.local_id < b_->tgt.local_id);
402 if (ret) return ret;
403 return (a_->src.global_id > b_->src.global_id) -
404 (a_->src.global_id < b_->src.global_id);
405}
406
408 double * src_cell_centroid, struct weight_vector_3d * G_i,
409 struct weight_vector_data_3d * buffer) {
410
411 // This routine computes: (I_3 - C_i * C_i^-1) * G_i
412 //
413 // O(g_i) = g_i - C_i * (C_i^-1 * g_i)
414 // where: C_i is the centeroid of a source cell
415 // g_i is the gradient of the source field in C_i
416 // O(g_i) is the projection of g_i into the plane perpendicular to C_i
417 // g_i = G_i * f
418 // where: G_i is the weight matrix to compute g_i
419 // f is the source field vector
420 // => O(g_i) = (I_3 - C_i * C_i^-1) * G_i * f
421 // where: I_3 is the identity matrix of size 3 x 3
422 //
423 // M = I_3 - C_i * C_i^-1
424
425 double M[3][3];
426 for (size_t k = 0; k < 3; ++k)
427 for (size_t l = 0; l < 3; ++l)
428 M[k][l] = - src_cell_centroid[k] * src_cell_centroid[l];
429 for (size_t k = 0; k < 3; ++k)
430 M[k][k] += 1.0;
431
432 struct weight_vector_data_3d * G_i_data = G_i->data;
433
434 size_t N = G_i->n;
435 for (size_t i = 0; i < N; ++i) {
436 buffer[i].local_id = G_i_data[i].local_id;
437 buffer[i].global_id = G_i_data[i].global_id;
438 for (size_t j = 0; j < 3; ++j) buffer[i].weight[j] = 0.0;
439 }
440
441 for (size_t n = 0; n < N; ++n)
442 for (size_t i = 0; i < 3; ++i)
443 for (size_t j = 0; j < 3; ++j)
444 buffer[n].weight[i] += G_i_data[n].weight[j] * M[i][j];
445
446 memcpy(G_i->data, buffer, N * sizeof(*buffer));
447}
448
450 void const * a, void const * b) {
451
452 struct weight_vector_data const * weight_a =
453 (struct weight_vector_data const *)a;
454 struct weight_vector_data const * weight_b =
455 (struct weight_vector_data const *)b;
456
457 int ret = weight_a->global_id - weight_b->global_id;
458 if (ret) return ret;
459 double abs_weight_a = fabs(weight_a->weight);
460 double abs_weight_b = fabs(weight_b->weight);
461 ret = (abs_weight_a > abs_weight_b) - (abs_weight_a < abs_weight_b);
462 if (ret) return ret;
463 return (weight_a->weight > weight_b->weight) -
464 (weight_a->weight < weight_b->weight);
465}
466
468 void const * a, void const * b) {
469
470 struct weight_vector_data const * weight_a =
471 (struct weight_vector_data const *)a;
472 struct weight_vector_data const * weight_b =
473 (struct weight_vector_data const *)b;
474
475 return weight_a->global_id - weight_b->global_id;
476}
477
479 struct weight_vector_data * weights, size_t * n) {
480
481 size_t n_ = *n;
482
483 if (n_ <= 1) return;
484
485 // sort weights by global_id then by weight
486 qsort(weights, n_, sizeof(*weights), compare_weight_vector_data_weight);
487
488 size_t new_n = 1;
489 struct weight_vector_data * prev_weight_data = weights;
490 struct weight_vector_data * curr_weight_data = weights + 1;
491 for (size_t i = 1; i < n_; ++i, ++curr_weight_data) {
492
493 // if both weights refer to the same source point (by global_id)
494 if (!compare_weight_vector_data(prev_weight_data, curr_weight_data)) {
495 prev_weight_data->weight += curr_weight_data->weight;
496 } else {
497 ++new_n;
498 ++prev_weight_data;
499 *prev_weight_data = *curr_weight_data;
500 }
501 }
502
503 n_ = new_n;
504 new_n = 0;
505
506 // check for zero-weights
507 for (size_t i = 0; i < n_; ++i) {
508
509 if (weights[i].weight == 0.0) continue;
510 if (i != new_n) weights[new_n] = weights[i];
511 ++new_n;
512 }
513
514 *n = new_n;
515}
516
518 struct supermesh_cell * super_cell, struct weight_vector_data * weights) {
519
520 weights[0].weight = super_cell->norm_area;
521 weights[0].global_id = super_cell->src.global_id;
522 weights[0].local_id = super_cell->src.local_id;
523
524 struct weight_vector_3d * src_cell_gradient = super_cell->src_cell_gradient;
525
526 size_t N = src_cell_gradient->n;
527 // in case we have no gradient for the current supermesh cell,
528 // we assume a constant field across the whole associated source cell
529 if (N > 0) {
530 struct weight_vector_data_3d * gradient_weights = src_cell_gradient->data - 1;
531 double * overlap_barycenter = super_cell->barycenter;
532
533 for (size_t n = 1; n <= N; ++n) {
534 weights[n].weight =
535 (gradient_weights[n].weight[0] * overlap_barycenter[0] +
536 gradient_weights[n].weight[1] * overlap_barycenter[1] +
537 gradient_weights[n].weight[2] * overlap_barycenter[2]) *
538 super_cell->norm_area;
539 weights[n].global_id = gradient_weights[n].global_id;
540 weights[n].local_id = gradient_weights[n].local_id;
541 }
542 }
543
544 return 1 + N;
545}
546
548 struct yac_const_basic_grid_data * grid_data, size_t cell_idx,
549 double barycenter[3]) {
550
551 size_t num_vertices = grid_data->num_vertices_per_cell[cell_idx];
552 size_t const * vertices =
553 grid_data->cell_to_vertex + grid_data->cell_to_vertex_offsets[cell_idx];
554
555 barycenter[0] = 0.0;
556 barycenter[1] = 0.0;
557 barycenter[2] = 0.0;
558
559 for (size_t i = 0; i < num_vertices; ++i) {
560 double const * curr_vertex_coordinate =
561 grid_data->vertex_coordinates[vertices[i]];
562 barycenter[0] += curr_vertex_coordinate[0];
563 barycenter[1] += curr_vertex_coordinate[1];
564 barycenter[2] += curr_vertex_coordinate[2];
565 }
566 normalise_vector(barycenter);
567}
568
570 struct yac_interp_grid * interp_grid, size_t * tgt_points, size_t count,
571 struct supermesh_cell ** super_cells_, size_t * num_super_cells,
572 int * interp_fail_flag, size_t ** src_cells, size_t * num_src_cells,
574 int partial_coverage) {
575
577 (normalisation == YAC_INTERP_CONSERV_DESTAREA) ||
578 (normalisation == YAC_INTERP_CONSERV_FRACAREA),
579 "ERROR(compute_super_cells): "
580 "invalid normalisation option in conservative remapping")
581
582 size_t * num_src_per_tgt = xmalloc(count * sizeof(*num_src_per_tgt));
583
584 // search for all source cell overlapping with the the target cells
586 interp_grid, tgt_points, count, src_cells, num_src_per_tgt);
587
588 // determine the number of unique matching source cells
589 size_t total_num_overlaps = 0;
590 for (size_t i = 0; i < count; ++i) total_num_overlaps += num_src_per_tgt[i];
591 yac_quicksort_index_size_t_int(*src_cells, total_num_overlaps, NULL);
592 *num_src_cells = total_num_overlaps;
593 yac_remove_duplicates_size_t(*src_cells, num_src_cells);
594
595 size_t * num_tgt_per_src =
596 xrealloc(num_src_per_tgt, *num_src_cells * sizeof(*num_tgt_per_src));
597
598 // for some required source cells we may have not all required supermesh cells
599 // in that case we have to find the respective target cells and compute the
600 // missing supermesh cells from them
601 size_t * tgt_cells = NULL;
603 interp_grid, *src_cells, *num_src_cells, &tgt_cells, num_tgt_per_src);
604
605 total_num_overlaps = 0;
606 for (size_t i = 0; i < *num_src_cells; ++i)
607 total_num_overlaps += num_tgt_per_src[i];
608
609 struct supermesh_cell * super_cells =
610 xmalloc(total_num_overlaps * sizeof(*super_cells));
611
612 struct yac_const_basic_grid_data * src_basic_grid_data =
614 struct yac_const_basic_grid_data * tgt_basic_grid_data =
616
617 for (size_t i = 0, j = 0; i < *num_src_cells; ++i) {
618
619 size_t curr_num_overlaps = num_tgt_per_src[i];
620 size_t curr_src_cell = (*src_cells)[i];
621 yac_int curr_src_global_id =
622 src_basic_grid_data->ids[YAC_LOC_CELL][curr_src_cell];
623
624 for (size_t k = 0; k < curr_num_overlaps; ++k, ++j) {
625
626 size_t curr_tgt_cell = tgt_cells[j];
627 struct supermesh_cell * curr_super_cell = super_cells + j;
628 curr_super_cell->src.local_id = curr_src_cell;
629 curr_super_cell->src.global_id = curr_src_global_id;
630 curr_super_cell->tgt.local_id = curr_tgt_cell;
631 curr_super_cell->tgt.global_id =
632 tgt_basic_grid_data->ids[YAC_LOC_CELL][curr_tgt_cell];
633 }
634 }
635 free(tgt_cells);
636 free(num_tgt_per_src);
637
638 // sort supermesh_cell first by local ids of the target cells and
639 // second by global cell id
640 qsort(super_cells, total_num_overlaps, sizeof(*super_cells),
642
643 struct yac_grid_cell tgt_grid_cell;
644 struct yac_grid_cell src_grid_cell;
645 get_cell_buffers_(interp_grid, &tgt_grid_cell, &src_grid_cell);
646
647 src_basic_grid_data = yac_interp_grid_get_basic_grid_data_src(interp_grid);
648 tgt_basic_grid_data = yac_interp_grid_get_basic_grid_data_tgt(interp_grid);
649
650 // For all supermesh cells compute the area and normalised area.
651 // Additionally, remove all empty supermesh cells.
652 size_t new_num_super_cells = 0;
653 size_t tgt_idx = 0;
654 for (size_t i = 0, j = 0; i < total_num_overlaps;) {
655
656 // get information about the current target cell
657 size_t curr_tgt_cell = super_cells[i].tgt.local_id;
659 tgt_basic_grid_data, curr_tgt_cell, &tgt_grid_cell);
660 double curr_tgt_cell_coverage = 0.0;
661
662 // for all supermesh cells overlapping with the current target cell
663 for (;(i < total_num_overlaps) &&
664 (super_cells[i].tgt.local_id == curr_tgt_cell); ++i) {
665
666 // get the current source cell
668 src_basic_grid_data, super_cells[i].src.local_id, &src_grid_cell);
669
670 // compute area of the current supermesh cell
671 double super_cell_area;
672 double barycenter[3];
674 1, &src_grid_cell, tgt_grid_cell, &super_cell_area, &barycenter);
675
676 // if there is an overlap between the current source and target cell
677 if (super_cell_area > 0.0) {
678
679 super_cells[new_num_super_cells].src = super_cells[i].src;
680 super_cells[new_num_super_cells].tgt = super_cells[i].tgt;
681 super_cells[new_num_super_cells].area = super_cell_area;
682 memcpy(super_cells[new_num_super_cells].barycenter, barycenter,
683 3 * sizeof(double));
684 super_cells[new_num_super_cells].src_cell_gradient = NULL;
685 ++new_num_super_cells;
686
687 curr_tgt_cell_coverage += super_cell_area;
688 }
689 }
690
691 double curr_tgt_cell_area = yac_huiliers_area(tgt_grid_cell);
692
693 // if there was an overlap
694 if (new_num_super_cells != j) {
695
696 double norm_factor;
698 (normalisation == YAC_INTERP_CONSERV_DESTAREA) ||
699 (normalisation == YAC_INTERP_CONSERV_FRACAREA),
700 "ERROR(compute_super_cells): invalid normalisation")
701 switch (normalisation) {
702 default:
704 norm_factor = 1.0 / curr_tgt_cell_area;
705 break;
707 norm_factor = 1.0 / curr_tgt_cell_coverage;
708 break;
709 }
710 // compute normalised area
711 for (; j < new_num_super_cells; ++j)
712 super_cells[j].norm_area = super_cells[j].area * norm_factor;
713 }
714
715
716 // for target cell that do not overlap with any source cell
717 while ((tgt_idx < count) && (tgt_points[tgt_idx] < curr_tgt_cell))
718 interp_fail_flag[tgt_idx++] = 1;
719
720 if ((tgt_idx < count) && (tgt_points[tgt_idx] == curr_tgt_cell)) {
721
722 double area_tol = curr_tgt_cell_area * AREA_TOL_FACTOR;
723
724 if (partial_coverage) {
725 interp_fail_flag[tgt_idx] = curr_tgt_cell_coverage < area_tol;
726 } else {
727 interp_fail_flag[tgt_idx] =
728 fabs(curr_tgt_cell_area - curr_tgt_cell_coverage) > area_tol;
729 }
730 ++tgt_idx;
731 }
732 }
733 // for all remaining target cell that do not overlap with any source cell
734 for (; tgt_idx < count; ++tgt_idx) interp_fail_flag[tgt_idx] = 1;
735 *num_super_cells = new_num_super_cells;
736 *super_cells_ =
737 xrealloc(super_cells, new_num_super_cells * sizeof(*super_cells));
739 free(tgt_grid_cell.coordinates_xyz);
740 free(tgt_grid_cell.edge_type);
741}
742
744 struct yac_interp_grid * interp_grid,
745 size_t * src_cells, int * skip_src_cell, size_t num_src_cells,
746 struct supermesh_cell * super_cells, size_t num_super_cells) {
747
748 yac_coordinate_pointer src_cell_centroids =
749 xmalloc(num_src_cells * sizeof(*src_cell_centroids));
750
751 // sort supermesh cells first by source local id and second by
752 // target global id
753 qsort(super_cells, num_super_cells, sizeof(*super_cells),
755
756 struct yac_grid_cell src_grid_cell, dummy;
757 get_cell_buffers_(interp_grid, &src_grid_cell, &dummy);
758
759 struct yac_const_basic_grid_data * src_basic_grid_data =
761
762 // compute centroids of source cells
763 // C_i = N(S_(U_k) (A_k*C_k))
764 // where: N(C) = C*(C*C)^-0.5 // normalisation
765 // U_k all supermesh cells overlaping with the respective source cell
766 // A_k area of supermesh cell
767 // C_k barycenter of supermesh cell (normalisation of the sum of all
768 // vertices of the cell)
769 for (size_t i = 0, offset = 0; i < num_src_cells; ++i) {
770
771 if (skip_src_cell[i]) continue;
772
773 size_t curr_src_cell = src_cells[i];
774
775 struct supermesh_cell * curr_super_cells = super_cells + offset;
776 size_t curr_num_super_cells = offset;
777 while ((offset < num_super_cells) &&
778 (super_cells[offset].src.local_id == curr_src_cell)) ++offset;
779 curr_num_super_cells = offset - curr_num_super_cells;
780
781 double src_cell_centroid[3] = {0.0, 0.0, 0.0};
782
783 if (curr_num_super_cells > 0) {
784 for (size_t j = 0; j < curr_num_super_cells; ++j) {
785
786 double super_cell_area = curr_super_cells[j].area;
787 double * super_cell_barycenter = curr_super_cells[j].barycenter;
788 src_cell_centroid[0] += super_cell_area * super_cell_barycenter[0];
789 src_cell_centroid[1] += super_cell_area * super_cell_barycenter[1];
790 src_cell_centroid[2] += super_cell_area * super_cell_barycenter[2];
791 }
792 } else {
793
794 // In case an unmasked source cell is not covered by any unmasked target
795 // cell (curr_num_super_cells == 0) its centroid is only used to compute
796 // the gradiants of its neighbour cells. In that case a rough estimate
797 // of its centroid (computed here) is sufficient.
799 src_basic_grid_data, curr_src_cell, &src_grid_cell);
800 for (size_t j = 0; j < src_grid_cell.num_corners; ++j) {
801 src_cell_centroid[0] += src_grid_cell.coordinates_xyz[j][0];
802 src_cell_centroid[1] += src_grid_cell.coordinates_xyz[j][1];
803 src_cell_centroid[2] += src_grid_cell.coordinates_xyz[j][2];
804 }
805 }
806
807 normalise_vector(src_cell_centroid);
808 src_cell_centroids[i][0] = src_cell_centroid[0];
809 src_cell_centroids[i][1] = src_cell_centroid[1];
810 src_cell_centroids[i][2] = src_cell_centroid[2];
811
812 }
813 free(src_grid_cell.coordinates_xyz);
814 free(src_grid_cell.edge_type);
815
816 return src_cell_centroids;
817}
818
820 struct yac_interp_grid * interp_grid, size_t * src_cells,
821 yac_coordinate_pointer src_cell_centroids, int * skip_src_cell,
822 size_t num_src_cells, size_t * src_cell_neighbours) {
823
824 struct weight_vector_3d * src_cell_gradients =
825 xmalloc(num_src_cells * sizeof(*src_cell_gradients));
826
827 struct yac_const_basic_grid_data * src_basic_grid_data =
829
830 size_t total_num_gradient_weights = 0;
831 size_t max_num_neigh_per_src = 0;
832 for (size_t i = 0; i < num_src_cells; ++i) {
833 src_cell_gradients[i].data = NULL;
834 src_cell_gradients[i].n = 0;
835 size_t curr_num_neigh =
836 src_basic_grid_data->num_vertices_per_cell[src_cells[i]];
837 total_num_gradient_weights += curr_num_neigh + 1;
838 if (max_num_neigh_per_src < curr_num_neigh)
839 max_num_neigh_per_src = curr_num_neigh;
840 }
841 struct weight_vector_data_3d * weight_vector_data_buffer =
842 (total_num_gradient_weights > 0)?
843 (xmalloc(total_num_gradient_weights *
844 sizeof(*weight_vector_data_buffer))):NULL;
845 for (size_t i = 0; i < total_num_gradient_weights; ++i)
846 for (size_t j = 0; j < 3; ++j)
847 weight_vector_data_buffer[i].weight[j] = 0.0;
848
849 struct weight_vector_data_3d * orth_buffer =
850 xmalloc((max_num_neigh_per_src + 1) * sizeof(*orth_buffer));
851
852 // compute gradient in the centroid for each source cell
853 // g_i = O_i(g'_i)
854 // where: O_i(g) = g - C_i*(C_i*g) // makes g orthogonal to C_i
855 // g'_i = (A_(C_k))^-1 * S_ijk(((f_j + f_k) * 0.5 - f_i) *
856 // (C_j x C_k) * |C_j x C_k|^-1 *
857 // asin(|C_j x C_k|))
858 // where: g'_i is the estimated centroid gradient
859 // A_(C_k) is the area of the cell generated by connecting the
860 // barycenters of all neighbour cells
861 // S_ijk is the sum of all edges of the previously described cell in
862 // counterclockwise order
863 // f_i, f_j, and f_k are the mean values of the field over the area of
864 // the respective source cell area
865 // asin(|C_j x C_k|) / |C_j x C_k| ~ 1.0
866 // => g'_i = S_ijk(((f_j + f_k) * 0.5 - f_i) * (C_j x C_k)) / A_(C_k)
867 //
868 // g_i = G_i * f
869 // G_i = S_ijk(((I_j + I_k) * 0.5 - I_i) * (C_j x C_k)) / A_(C_k)
870 // where: G_i is the gradient weight matrix
871 // I_x is a vector of the same size as f, which is all zero except at
872 // position x, where it is one
873 // f is the source field vector
874 for (size_t i = 0, offset = 0, weight_vector_data_buffer_offset = 0;
875 i < num_src_cells; ++i) {
876
877 size_t curr_num_neigh =
878 src_basic_grid_data->num_vertices_per_cell[src_cells[i]];
879 size_t * curr_neighs = src_cell_neighbours + offset;
880 offset += curr_num_neigh;
881 struct weight_vector_3d * G_i = src_cell_gradients + i;
882 G_i->data = weight_vector_data_buffer + weight_vector_data_buffer_offset;
883
884 if (skip_src_cell[i]) continue;
885
886 weight_vector_data_buffer_offset += curr_num_neigh + 1;
887 G_i->n = curr_num_neigh + 1;
888 G_i->data[0].local_id = src_cells[i];
889 G_i->data[0].global_id =
890 src_basic_grid_data->ids[YAC_LOC_CELL][src_cells[i]];
891 for (size_t j = 0; j < curr_num_neigh; ++j) {
892 size_t curr_neigh = curr_neighs[j];
893 // if the current edge has a neighbour
894 if (curr_neigh != SIZE_MAX) {
895 G_i->data[j+1].local_id = curr_neigh;
896 G_i->data[j+1].global_id =
897 src_basic_grid_data->ids[YAC_LOC_CELL][curr_neigh];
898 } else {
899 // if the current edge has no neighbour, use current cell instead
900 G_i->data[j+1].local_id = G_i->data[0].local_id;
901 G_i->data[j+1].global_id = G_i->data[0].global_id;
902 }
903 }
904
905 // area of the polygon that is formed by connecting the barycenters of
906 // the neighbouring cells
907 double A_C_k = 0.0;
908
909 struct yac_grid_cell centroid_triangle = {
910 .coordinates_xyz = (double[3][3]){{0}},
911 .edge_type =
913 .num_corners = 3, .array_size = 0};
914 centroid_triangle.coordinates_xyz[0][0] = src_cell_centroids[i][0];
915 centroid_triangle.coordinates_xyz[0][1] = src_cell_centroids[i][1];
916 centroid_triangle.coordinates_xyz[0][2] = src_cell_centroids[i][2];
917
918 double edge_direction = 0.0;
919
920 // We split the cell that is comprised of the barycenters of the edge
921 // neigbours into triangles, which has the centroid of the current cell
922 // as one corner. The sum of the areas of these triangles is A_C_K.
923 for (size_t j = 0; j < curr_num_neigh; ++j) {
924
925 size_t neigh_idx[2] = {j + 1, (j+1)%curr_num_neigh+1};
926 size_t neigh_local_ids[2] =
927 {G_i->data[neigh_idx[0]].local_id,
928 G_i->data[neigh_idx[1]].local_id};
929
930 if (neigh_local_ids[0] == neigh_local_ids[1]) continue;
931
932 double neigh_cell_barycenters[2][3];
934 src_basic_grid_data, neigh_local_ids[0], neigh_cell_barycenters[0]);
936 src_basic_grid_data, neigh_local_ids[1], neigh_cell_barycenters[1]);
937
938 centroid_triangle.coordinates_xyz[1][0] = neigh_cell_barycenters[0][0];
939 centroid_triangle.coordinates_xyz[1][1] = neigh_cell_barycenters[0][1];
940 centroid_triangle.coordinates_xyz[1][2] = neigh_cell_barycenters[0][2];
941 centroid_triangle.coordinates_xyz[2][0] = neigh_cell_barycenters[1][0];
942 centroid_triangle.coordinates_xyz[2][1] = neigh_cell_barycenters[1][1];
943 centroid_triangle.coordinates_xyz[2][2] = neigh_cell_barycenters[1][2];
944
945 A_C_k += yac_huiliers_area(centroid_triangle);
946
947 // C_j x C_k
948 double C_j_x_C_k[3];
950 neigh_cell_barycenters[0], neigh_cell_barycenters[1], C_j_x_C_k);
951
952 double curr_edge_direction =
953 C_j_x_C_k[0] * centroid_triangle.coordinates_xyz[0][0] +
954 C_j_x_C_k[1] * centroid_triangle.coordinates_xyz[0][1] +
955 C_j_x_C_k[2] * centroid_triangle.coordinates_xyz[0][2];
956
957 if (fabs(curr_edge_direction) > fabs(edge_direction))
958 edge_direction = curr_edge_direction;
959
960 // -I_i * (C_j x C_k)
961 G_i->data[0].weight[0] -= C_j_x_C_k[0];
962 G_i->data[0].weight[1] -= C_j_x_C_k[1];
963 G_i->data[0].weight[2] -= C_j_x_C_k[2];
964
965 for (size_t l = 0; l < 3; ++l) C_j_x_C_k[l] *= 0.5;
966
967 // 0.5 * I_j * (C_j x C_k)
968 G_i->data[neigh_idx[0]].weight[0] += C_j_x_C_k[0];
969 G_i->data[neigh_idx[0]].weight[1] += C_j_x_C_k[1];
970 G_i->data[neigh_idx[0]].weight[2] += C_j_x_C_k[2];
971
972 // 0.5 * I_k * (C_j x C_k)
973 G_i->data[neigh_idx[1]].weight[0] += C_j_x_C_k[0];
974 G_i->data[neigh_idx[1]].weight[1] += C_j_x_C_k[1];
975 G_i->data[neigh_idx[1]].weight[2] += C_j_x_C_k[2];
976 } // curr_num_neigh
977
978 // if the neighbours were ordered in the wrong direction
979 if (edge_direction > 0.0)
980 for (size_t j = 0; j <= curr_num_neigh; ++j)
981 for (size_t k = 0; k < 3; ++k)
982 G_i->data[j].weight[k] *= -1.0;
983
984 double inv_A_C_K = (A_C_k > YAC_AREA_TOL)?(1.0/A_C_k):0.0;
985 // ((I_j + I_k) * 0.5 - I_i) * (C_j x C_k) / A_(C_k)
986 for (size_t k = 0; k <= curr_num_neigh; ++k)
987 for (size_t l = 0; l < 3; ++l)
988 G_i->data[k].weight[l] *= inv_A_C_K;
989
991 src_cell_centroids[i], G_i, orth_buffer);
992 } // num_src_cells
993 free(orth_buffer);
994
995 return src_cell_gradients;
996}
997
999 size_t * tgt_cells, int * interp_fail_flag, size_t num_tgt_cells,
1000 struct supermesh_cell * super_cells, size_t num_super_cells,
1001 size_t ** src_per_tgt, double ** weights, size_t * num_src_per_tgt) {
1002
1003 size_t num_interpolated_tgt = 0;
1004
1005 // sort supermesh cells first by target local id and second by
1006 // source global id
1007 qsort(super_cells, num_super_cells, sizeof(*super_cells),
1009
1010 size_t max_num_weights_per_tgt = 0;
1011 size_t max_num_total_weights = 0;
1012
1013 // count maximum number of weights
1014 for (size_t i = 0, j = 0; i < num_tgt_cells; ++i) {
1015
1016 if (interp_fail_flag[i]) continue;
1017
1018 size_t curr_tgt_cell = tgt_cells[i];
1019 size_t curr_num_weights = 0;
1020
1021 // skip supermesh cells not overlapping with current target cell
1022 while ((j < num_super_cells) &&
1023 (super_cells[j].tgt.local_id < curr_tgt_cell)) ++j;
1024
1025 // for all supermesh cells overlapping with the current target cell
1026 while ((j < num_super_cells) &&
1027 (super_cells[j].tgt.local_id == curr_tgt_cell))
1028 curr_num_weights += 1 + super_cells[j++].src_cell_gradient->n;
1029
1030 max_num_total_weights += curr_num_weights;
1031 if (max_num_weights_per_tgt < curr_num_weights)
1032 max_num_weights_per_tgt = curr_num_weights;
1033 num_interpolated_tgt++;
1034 }
1035
1036 struct weight_vector_data * weight_buffer =
1037 xmalloc(max_num_weights_per_tgt * sizeof(*weight_buffer));
1038 *weights = xmalloc(max_num_total_weights * sizeof(**weights));
1039 *src_per_tgt = xmalloc(max_num_total_weights * sizeof(**src_per_tgt));
1040
1041 // sort all target points that can be interpolated to the beginning of the
1042 // tgt_cells array
1043 yac_quicksort_index_int_size_t(interp_fail_flag, num_tgt_cells, tgt_cells);
1044 yac_quicksort_index_size_t_int(tgt_cells, num_interpolated_tgt, NULL);
1045
1046 // compute 2nd order weights
1047 // f_j = SUM(f_k') / A_j
1048 // f_k' = A_k*(f_i + g_i * C_k)
1049 //
1050 // f_k' = A_k * (I_i + C_k * G_i) * f
1051 // where: I_i is a vector of the same length as f, that is all 0.0 except at
1052 // position i, where it is 1.0
1053 // f is the source field vector
1054 // => f_k' / A_j = M_k * f
1055 // where: M_k = A_k / A_j * (I_i + C_k * G_i)
1056 // => f_j = SUM(M_k) * f
1057 // f_j = M_j * f
1058 // where: M_j = SUM(M_k)
1059 size_t w_idx = 0;
1060 for (size_t i = 0, j = 0; i < num_interpolated_tgt; ++i) {
1061
1062 size_t curr_tgt_cell = tgt_cells[i];
1063
1064 // skip supermesh cells not overlapping with current target cell
1065 while ((j < num_super_cells) &&
1066 (super_cells[j].tgt.local_id != curr_tgt_cell)) ++j;
1067
1068 size_t weight_buffer_offset = 0;
1069
1070 // for all supermesh cells overlapping with the current target cell
1071 while ((j < num_super_cells) &&
1072 (super_cells[j].tgt.local_id == curr_tgt_cell)) {
1073
1074 size_t num_weights =
1076 super_cells + j, weight_buffer + weight_buffer_offset);
1077 weight_buffer_offset += num_weights;
1078 ++j;
1079 }
1080
1081 // compact weights and sort them by global_id
1082 compact_weight_vector_data(weight_buffer, &weight_buffer_offset);
1083
1084 num_src_per_tgt[i] = weight_buffer_offset;
1085
1086 for (size_t k = 0; k < weight_buffer_offset; ++k, ++w_idx) {
1087 (*weights)[w_idx] = weight_buffer[k].weight;
1088 (*src_per_tgt)[w_idx] = weight_buffer[k].local_id;
1089 }
1090 }
1091 free(weight_buffer);
1092
1093 return num_interpolated_tgt;
1094}
1095
1096static size_t do_search_conserv_2nd_order (struct interp_method * method,
1097 struct yac_interp_grid * interp_grid,
1098 size_t * tgt_points, size_t count,
1099 struct yac_interp_weights * weights,
1100 int * interpolation_complete) {
1101
1102 if (*interpolation_complete) return 0;
1103
1104 struct interp_method_conserv * method_conserv =
1105 (struct interp_method_conserv *)method;
1106
1107 YAC_ASSERT(
1108 yac_interp_grid_get_num_src_fields(interp_grid) == 1,
1109 "ERROR(do_search_conserv): invalid number of source fields")
1110
1111 YAC_ASSERT(
1113 "ERROR(do_search_conserv): unsupported source field location type")
1114
1115 YAC_ASSERT(
1117 "ERROR(do_search_conserv): unsupported target field location type")
1118
1119 // sort target points
1120 yac_quicksort_index_size_t_int(tgt_points, count, NULL);
1121
1122 int * interp_fail_flag = xmalloc(count * sizeof(*interp_fail_flag));
1123 struct supermesh_cell * super_cells = NULL;
1124 size_t num_super_cells = 0;
1125 size_t * src_cells = NULL;
1126 size_t num_src_cells = 0;
1127
1128 // compute the overlaps between the target cells and the source grid
1130 interp_grid, tgt_points, count, &super_cells, &num_super_cells,
1131 interp_fail_flag, &src_cells, &num_src_cells,
1132 method_conserv->normalisation, method_conserv->partial_coverage);
1133
1134 size_t total_num_src_cell_neighbours = 0;
1135 struct yac_const_basic_grid_data * src_basic_grid_data =
1137 for (size_t i = 0; i < num_src_cells; ++i)
1138 total_num_src_cell_neighbours +=
1139 src_basic_grid_data->num_vertices_per_cell[src_cells[i]];
1140 size_t * src_cell_neighbours =
1141 xmalloc(total_num_src_cell_neighbours * sizeof(*src_cell_neighbours));
1142
1143 // get the neighbours for all source cells overlapping with a target cell
1145 interp_grid, src_cells, num_src_cells, src_cell_neighbours);
1146
1147 const_int_pointer src_cell_mask =
1148 yac_interp_grid_get_src_field_mask(interp_grid, 0);
1149 int * skip_src_cell = xmalloc(num_src_cells * sizeof(*skip_src_cell));
1150
1151 // check whether any required source cell or any of its neighbours is masked
1152 // out in the field mask (deactivate respective cells)
1153 if (src_cell_mask != NULL) {
1154 for (size_t i = 0, offset = 0; i < num_src_cells; ++i) {
1155 size_t curr_src_cell = src_cells[i];
1156 if ((skip_src_cell[i] = !src_cell_mask[curr_src_cell])) continue;
1157 size_t * curr_neighbours = src_cell_neighbours + offset;
1158 size_t curr_num_neigh =
1159 src_basic_grid_data->num_vertices_per_cell[curr_src_cell];
1160 offset += curr_num_neigh;
1161 for (size_t j = 0; j < curr_num_neigh; ++j)
1162 if ((curr_neighbours[j] != SIZE_MAX) &&
1163 (!src_cell_mask[curr_neighbours[j]]))
1164 curr_neighbours[j] = SIZE_MAX;
1165 }
1166 } else {
1167 memset(skip_src_cell, 0, num_src_cells * sizeof(*skip_src_cell));
1168 }
1169
1170 // compute the centroids of all required source cells
1171 yac_coordinate_pointer src_cell_centroids =
1172 compute_src_cell_centroids(interp_grid, src_cells, skip_src_cell,
1173 num_src_cells, super_cells, num_super_cells);
1174
1175 // compute the gradients weights for the source cells
1176 struct weight_vector_3d * src_cell_gradients =
1178 interp_grid, src_cells, src_cell_centroids,
1179 skip_src_cell, num_src_cells, src_cell_neighbours);
1180 free(src_cell_neighbours);
1181 free(src_cell_centroids);
1182
1183 // sort supermesh cells by local src id
1184 qsort(super_cells, num_super_cells, sizeof(*super_cells),
1186 for (size_t i = 0, j = 0; i < num_src_cells; ++i) {
1187 size_t curr_src_cell = src_cells[i];
1188 struct weight_vector_3d * curr_src_cell_gradient = src_cell_gradients + i;
1189 // there should not be any supercell whose source cell is not in the list of
1190 // required source cells
1191 YAC_ASSERT(
1192 (j >= num_super_cells) ||
1193 (super_cells[j].src.local_id >= curr_src_cell),
1194 "ERROR(do_search_conserv_2nd_order): internal error");
1195 while ((j < num_super_cells) &&
1196 (super_cells[j].src.local_id == curr_src_cell)) {
1197 super_cells[j++].src_cell_gradient = curr_src_cell_gradient;
1198 }
1199 }
1200 free(skip_src_cell);
1201 free(src_cells);
1202
1203 size_t * src_per_tgt = NULL;
1204 double * w = NULL;
1205 size_t * num_src_per_tgt = xmalloc(count * sizeof(*num_src_per_tgt));
1206
1207 // compute the weights for the target points
1208 size_t num_interpolated_tgt =
1210 tgt_points, interp_fail_flag, count, super_cells, num_super_cells,
1211 &src_per_tgt, &w, num_src_per_tgt);
1212 if (num_src_cells > 0) free(src_cell_gradients->data);
1213 free(src_cell_gradients);
1214 free(super_cells);
1215 free(interp_fail_flag);
1216
1217 size_t total_num_weights = 0;
1218 for (size_t i = 0; i < num_interpolated_tgt; ++i)
1219 total_num_weights += num_src_per_tgt[i];
1220
1221 struct remote_points tgts = {
1222 .data =
1224 interp_grid, tgt_points, num_interpolated_tgt),
1225 .count = num_interpolated_tgt};
1226 struct remote_point * srcs =
1228 interp_grid, 0, src_per_tgt, total_num_weights);
1229
1230 // store weights
1232 weights, &tgts, num_src_per_tgt, srcs, w);
1233
1234 free(tgts.data);
1235 free(srcs);
1236 free(w);
1237 free(num_src_per_tgt);
1238 free(src_per_tgt);
1239
1240 return num_interpolated_tgt;
1241}
1242
1244 int order, int enforced_conserv, int partial_coverage,
1245 enum yac_interp_method_conserv_normalisation normalisation) {
1246
1247 struct interp_method_conserv * method = xmalloc(1 * sizeof(*method));
1248
1249 YAC_ASSERT(
1250 (enforced_conserv != 1) || (order == 1),
1251 "ERROR(yac_interp_method_conserv_new): interp_method_conserv only "
1252 "supports enforced_conserv with first order conservative remapping")
1253 YAC_ASSERT(
1254 (order == 1) || (order == 2),
1255 "ERROR(yac_interp_method_conserv_new): invalid order")
1256
1257 method->vtable =
1258 (order == 1)?
1262 method->normalisation = normalisation;
1264
1265 return (struct interp_method*)method;
1266}
1267
1268static void delete_conserv(struct interp_method * method) {
1269 free(method);
1270}
double yac_huiliers_area(struct yac_grid_cell cell)
Area calculation on a unit sphere taken from ESMF based on L'Huilier's Theorem.
Definition area.c:449
Structs and interfaces for area calculations.
#define YAC_AREA_TOL
Definition area.h:23
static int edge_direction(double *a, double *b)
void yac_correct_weights(size_t nSourceCells, double *weight)
correct interpolation weights
Definition clipping.c:1447
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:276
void yac_compute_overlap_buf_free()
Definition clipping.c:88
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:2440
int const * const_int_pointer
static void crossproduct_kahan(double const a[], double const b[], double cross[])
Definition geometry.h:318
static void normalise_vector(double v[])
Definition geometry.h:671
yac_edge_type
Definition grid_cell.h:12
@ YAC_GREAT_CIRCLE_EDGE
great circle
Definition grid_cell.h:13
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)
enum yac_location yac_interp_grid_get_tgt_field_location(struct yac_interp_grid *interp_grid)
size_t yac_interp_grid_get_num_src_fields(struct yac_interp_grid *interp_grid)
const_int_pointer yac_interp_grid_get_src_field_mask(struct yac_interp_grid *interp_grid, size_t src_field_idx)
void yac_interp_grid_get_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)
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)
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)
static void delete_conserv(struct interp_method *method)
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 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 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
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)
static struct interp_method_vtable interp_method_conserv_1st_order_vtable
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)
yac_interp_method_conserv_normalisation
@ YAC_INTERP_CONSERV_DESTAREA
@ YAC_INTERP_CONSERV_FRACAREA
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
#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::@9 src
struct supermesh_cell::@9 tgt
struct weight_vector_data_3d * data
const yac_const_coordinate_pointer vertex_coordinates
const_size_t_pointer cell_to_vertex_offsets
const_size_t_pointer cell_to_vertex
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
#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:108
void yac_quicksort_index_size_t_int(size_t *a, size_t n, int *idx)
#define YAC_ASSERT(exp, msg)
Definition yac_assert.h:16
Xt_int yac_int
Definition yac_types.h:15
double(* yac_coordinate_pointer)[3]
Definition yac_types.h:19