21static void utest_check_partial_areas_deg(
22 double * tgt_lon,
double * tgt_lat,
24 double ** src_lons,
double ** src_lats,
25 enum yac_edge_type ** src_edges,
int * src_counts,
size_t nSourceCells);
26static void utest_check_partial_areas_rad(
27 double * tgt_lon,
double * tgt_lat,
29 double ** src_lons,
double ** src_lats,
30 enum yac_edge_type ** src_edges,
int * src_counts,
size_t nSourceCells);
75 enum {nSourceCells = 4};
76 utest_check_partial_areas_deg(
77 (
double[]){0.5, 0.0, -0.5, 0.0},
78 (
double[]){0.0, 0.7, 0.0, -0.5},
gc_edges, 4,
79 (
double*[nSourceCells]){(
double[]){1.0, 0.0, 0.0, 1.0},
80 (
double[]){0.0, -1.0, -1.0, 0.0},
81 (
double[]){0.0, -1.0, -1.0, 0.0},
82 (
double[]){1.0, 0.0, 0.0, 1.0}},
83 (
double*[nSourceCells]){(
double[]){1.8, 1.8, 0.6, 0.6},
84 (
double[]){1.8, 1.8, 0.6, 0.6},
85 (
double[]){0.6, 0.6, -0.6, -0.6},
86 (
double[]){0.6, 0.6, -0.6, -0.6}},
89 (
int[nSourceCells]){4, 4, 4, 4}, nSourceCells);
116 enum {nSourceCells = 4};
117 utest_check_partial_areas_deg(
118 (
double[]){ 0.0, 90.0, -180.0, -90.0},
119 (
double[]){89.5, 89.5, 89.5, 89.5},
gc_edges, 4,
120 (
double*[nSourceCells]){(
double[]){45.0, 90.0, -180.0, 0.0},
121 (
double[]){90.0, 135.0, -180.0, -180.0},
122 (
double[]){-180.0, -180.0, -135.0, -90.0},
123 (
double[]){ 0.0, -180.0, -90.0, -45.0}},
124 (
double*[nSourceCells]){(
double[]){88.5, 89.0, 90.0, 89.0},
125 (
double[]){89.0, 88.5, 89.0, 90.0},
126 (
double[]){90.0, 89.0, 88.5, 89.0},
127 (
double[]){89.0, 90.0, 89.0, 88.5}},
130 (
int[nSourceCells]){4, 4, 4, 4}, nSourceCells);
135 enum {nSourceCells = 1};
136 utest_check_partial_areas_deg(
137 (
double[]){-180.0, -150.0, -150.0, -180.0},
138 (
double[]){ -90.0, -90.0, -60.0, -60.0},
gc_edges, 4,
139 (
double*[nSourceCells]){(
double[]){-180.0, -150.0, -150.0, -180.0}},
140 (
double*[nSourceCells]){(
double[]){ -90.0, -90.0, -60.0, -60.0}},
142 (
int[nSourceCells]){4}, nSourceCells);
145 enum {nSourceCells = 1};
146 utest_check_partial_areas_deg(
147 (
double[]){-180.0, -150.0, -150.0, -180.0},
148 (
double[]){ 60.0, 60.0, 90.0, 90.0},
gc_edges, 4,
149 (
double*[nSourceCells]){(
double[]){-180.0, -150.0, -150.0, -180.0}},
150 (
double*[nSourceCells]){(
double[]){ 60.0, 60.0, 90.0, 90.0}},
152 (
int[nSourceCells]){4}, nSourceCells);
157 enum {nSourceCells = 3};
158 utest_check_partial_areas_deg(
159 (
double[]){25.0, 30.0, 30.0, 25.0},
160 (
double[]){75.0, 75.0, 80.0, 80.0},
gc_edges, 4,
161 (
double*[nSourceCells]){(
double[]){30.0, 35.0, 35.0, 30.0},
162 (
double[]){25.0, 30.0, 30.0, 25.0},
163 (
double[]){20.0, 25.0, 25.0, 20.0}},
164 (
double*[nSourceCells]){(
double[]){75.0, 75.0, 80.0, 80.0},
165 (
double[]){75.0, 75.0, 80.0, 80.0},
166 (
double[]){75.0, 75.0, 80.0, 80.0}},
169 (
int[nSourceCells]){4, 4, 4}, nSourceCells);
176 0.117826295355522680,
177 0.098174496441371703},
178 (
double[]){0.333033372840672190,
179 0.345484775276814930,
180 0.353335609258583650},
gc_edges, 3);
183 0.098174770424681035,
184 0.098174770424681035,
185 0.073631077818510776},
186 (
double[]){0.343611696486383620,
187 0.343611696486383620,
188 0.368155389092553910,
189 0.368155389092553910},
gc_edges, 4);
193 1, &SourceCell, TargetCell, &overlap_area);
195 if (fabs(overlap_area) > 1e-9)
196 PUT_ERR(
"ERROR in yac_compute_overlap_areas");
204 enum {nSourceCells = 4};
205 utest_check_partial_areas_deg(
206 (
double[]){-0.5, 0.5, 0.5, -0.5},
208 (
double*[nSourceCells]){(
double[]){-1, 0, 0, -1},
209 (
double[]){ 0, 1, 1, 0},
210 (
double[]){-1, 0, 0, -1},
211 (
double[]){0, 1, 1, 0}},
212 (
double*[nSourceCells]){(
double[]){-1, -1, 0, 0},
213 (
double[]){-1, -1, 0, 0},
214 (
double[]){ 0, 0, 1, 1},
215 (
double[]){ 0, 0, 1, 1}},
218 (
int[nSourceCells]){4, 4, 4, 4}, nSourceCells);
223 enum {nSourceCells = 1};
224 utest_check_partial_areas_deg(
225 (
double[]){-0.5, 0.5, 0.5, -0.5},
227 (
double*[nSourceCells]){(
double[]){-1, 1, 1, -1}},
228 (
double*[nSourceCells]){(
double[]){-1, -1, 1, 1}},
231 (
int[nSourceCells]){4}, nSourceCells);
236 enum {nSourceCells = 1};
237 utest_check_partial_areas_deg(
238 (
double[]){-0.5, 0.5, 0.0},
239 (
double[]){-0.5, -0.5, 0.5},
gc_edges, 3,
240 (
double*[nSourceCells]){(
double[]){-1, 1, 1, -1}},
241 (
double*[nSourceCells]){(
double[]){-1, -1, 1, 1}},
244 (
int[nSourceCells]){4}, nSourceCells);
249 enum {nSourceCells = 4};
250 utest_check_partial_areas_rad(
251 (
double[]){2.5034566458293663,
255 (
double[]){0.5890486225480862,
259 (
double*[nSourceCells]){(
double[]){2.5132750564642796,
262 (
double[]){2.5530451220055963,
265 (
double[]){2.4735050741253155,
268 (
double[]){2.4750971948235070,
270 2.4735050741253155}},
271 (
double*[nSourceCells]){(
double[]){0.6227096831849960,
274 (
double[]){0.6044728875052012,
277 (
double[]){0.6044725603601205,
280 (
double[]){0.5706923461529829,
282 0.6044725603601205}},
285 (
int[nSourceCells]){3, 3, 3, 3}, nSourceCells);
290 enum {nSourceCells = 3};
291 utest_check_partial_areas_rad(
292 (
double[]){0.6626797003665970,
296 (
double[]){1.2271846303085130,
300 (
double*[nSourceCells]){(
double[]){0.6910166804158336,
303 (
double[]){0.5657152198049494,
306 (
double[]){0.6283674880262698,
308 0.6910166804158336}},
309 (
double*[nSourceCells]){(
double[]){1.2515918327919406,
312 (
double[]){1.2515932566235379,
315 (
double[]){1.2831450892755811,
317 1.2515918327919406}},
320 (
int[nSourceCells]){3, 3, 3}, nSourceCells);
325 enum {nSourceCells = 7};
326 utest_check_partial_areas_rad(
327 (
double[]){-2.1798479726998332,
329 -2.2190472361409284},
330 (
double[]){-0.0311624518327736,
333 (
double*[nSourceCells]){(
double[]){ 4.0987966652304335,
337 (
double[]){ 4.0742529726242633,
341 (
double[]){ 4.0742529726242633,
345 (
double[]){ 4.0987966652304335,
349 (
double[]){ 4.0742529726242633,
353 (
double[]){ 4.0497092800180932,
357 (
double[]){ 4.0497092800180932,
360 4.0497092800180932}},
361 (
double*[nSourceCells]){(
double[]){-0.0490873852123405,
364 -0.0245436926061703},
365 (
double[]){-0.0490873852123405,
368 -0.0245436926061703},
369 (
double[]){ 0.0000000000000000,
373 (
double[]){-0.0245436926061703,
377 (
double[]){-0.0245436926061703,
381 (
double[]){-0.0245436926061703,
385 (
double[]){-0.0490873852123405,
388 -0.0245436926061703}},
392 (
int[nSourceCells]){4, 4, 4, 4, 4, 4, 4}, nSourceCells);
397 enum {nSourceCells = 4};
398 utest_check_partial_areas_rad(
399 (
double[]){ 3.4361169648638361,
403 (
double[]){-0.0245436926061703,
407 (
double*[nSourceCells]){(
double[]){-2.8075010104343816,
409 -2.8467002736213392},
410 (
double[]){-2.8081665040027728,
412 -2.7882305020025413},
413 (
double[]){-2.7882305020025413,
415 -2.8075010104343816},
416 (
double[]){-2.8467002736213392,
418 -2.8666362753717674}},
419 (
double*[nSourceCells]){(
double[]){-0.0338654341705874,
421 -0.0311624540855508},
422 (
double[]){ 0.0311624566805337,
424 -0.0026744729717723},
425 (
double[]){-0.0026744729717723,
427 -0.0338654341705874},
428 (
double[]){-0.0311624540855508,
430 0.0026744751289656}},
433 (
int[nSourceCells]){3, 3, 3, 3}, nSourceCells);
440 enum {nSourceCells = 3};
441 utest_check_partial_areas_rad(
442 (
double[]){ 3.1170489609836229,
446 (
double[]){-1.0062913968529805,
450 (
double*[nSourceCells]){(
double[]){ 3.1415926521557882,
452 -3.0774466652769172},
453 (
double[]){ 3.0774466624490269,
456 (
double[]){ 3.0808931330453300,
458 3.1415926521557882}},
459 (
double*[nSourceCells]){(
double[]){-0.9805860393425995,
461 -0.9979427097227050},
462 (
double[]){-0.9979427096430752,
464 -0.9805860393425995},
465 (
double[]){-0.9613498550843829,
467 -0.9805860393425995}},
470 (
int[nSourceCells]){3, 3, 3}, nSourceCells);
475 enum {nSourceCells = 198};
476 double ** src_lons =
xmalloc(2 * nSourceCells *
sizeof(*src_lons));
477 double ** src_lats = src_lons + nSourceCells;
479 xmalloc(nSourceCells *
sizeof(*src_edges));
480 int * src_counts =
xmalloc(nSourceCells *
sizeof(*src_counts));
482 src_lons[0] =
xmalloc(2 * 4 * nSourceCells *
sizeof(**src_lons));
483 double dx = ((49.2 - 22.8) /((
double)nSourceCells));
484 for (
size_t i = 0;
i < nSourceCells; ++
i) {
485 src_lons[
i] = src_lons[0] +
i * 4;
486 src_lats[
i] = src_lons[0] +
i * 4 + 4 * nSourceCells;
487 src_lons[
i][0] = 22.8000 + dx*((double)(i+0));
488 src_lons[
i][1] = 22.8000 + dx*((double)(i+1));
489 src_lons[
i][2] = 22.8000 + dx*((double)(i+1));
490 src_lons[
i][3] = 22.8000 + dx*((double)(i+0));
491 src_lats[
i][0] = 89.7333;
492 src_lats[
i][1] = 89.7333;
493 src_lats[
i][2] = 89.8667;
494 src_lats[
i][3] = 89.8667;
499 utest_check_partial_areas_deg(
500 (
double[]){22.8313, 49.1687, 36.0000},
501 (
double[]){89.7418, 89.7418, 89.8335},
gc_edges, 3,
502 src_lons, src_lats, src_edges, src_counts, nSourceCells);
512 enum {nSourceCells = 4};
513 utest_check_partial_areas_rad(
514 (
double[]){ 5.0069132916587327,
518 (
double[]){-1.2946797849754812,
522 (
double*[nSourceCells]){(
double[]){ 4.9999997254688875,
526 (
double[]){ 5.0078539201557488,
530 (
double[]){ 5.0078539201557488,
534 (
double[]){ 4.9999997254688875,
537 5.0078539201557488}},
538 (
double*[nSourceCells]){(
double[]){-1.2878426515089207,
541 -1.2878469125666649},
542 (
double[]){-1.2946797849754812,
545 -1.2946840460332254},
546 (
double[]){-1.2878469125666649,
549 -1.2878513067824635},
550 (
double[]){-1.2946756570757916,
553 -1.2946797849754812}},
556 (
int[nSourceCells]){4, 4, 4, 4}, nSourceCells);
561 enum {nSourceCells = 2};
562 utest_check_partial_areas_rad(
563 (
double[]){-2.8460897445189417,
565 -2.8853055611946927},
566 (
double[]){-0.0961602003314924,
569 (
double*[nSourceCells]){(
double[]){-2.8655528147976832,
571 -2.8254194450162888},
572 (
double[]){-2.9440830021466091,
574 -2.8655528147976832}},
575 (
double*[nSourceCells]){(
double[]){-0.0615856127966505,
577 -0.1292806814915037},
578 (
double[]){-0.0558979744839555,
580 -0.0615856127966505}},
582 (
int[nSourceCells]){3, 3}, nSourceCells);
587 enum {nSourceCells = 6};
588 utest_check_partial_areas_rad(
589 (
double[]){3.0127596408133406,
592 (
double[]){0.5498596133493898,
595 (
double*[nSourceCells]){(
double[]){2.9198084624304621,
598 (
double[]){2.8889398582596519,
601 (
double[]){3.0187962726049782,
604 (
double[]){2.9378118571213374,
607 (
double[]){3.0565195473916882,
610 (
double[]){3.0078074923914948,
612 3.0565195473916882}},
613 (
double*[nSourceCells]){(
double[]){0.6123031304013200,
616 (
double[]){0.5392518296263771,
619 (
double[]){0.4805223860987507,
622 (
double[]){0.4745836829538209,
625 (
double[]){0.5519553785110132,
628 (
double[]){0.6192726969308253,
630 0.5519553785110132}},
633 (
int[nSourceCells]){3, 3, 3, 3, 3, 3}, nSourceCells);
640 (
double[]){-0.5, -0.5, 0.0 , 0.5, 0.5, 0.0},
644 (
double[]){0.3, 0.3, -0.3},
gc_edges, 3),
646 (
double[]){-0.4, -0.4, 0.4, 0.4},
gc_edges, 4),
648 (
double[]){-0.6, -0.6, 0.0, 0.6, 0.6, 0.0},
650 enum {nSourceCells =
sizeof(SourceCells)/
sizeof(SourceCells[0])};
652 double ref_area[nSourceCells];
653 double ref_barycenter[nSourceCells][3];
654 for (
int i = 0;
i < nSourceCells; ++
i)
655 for (
int j = 0; j < 3; ++j)
656 ref_barycenter[i][j] = 0.0;
662 LLtoXYZ(0, 0, ref_barycenter[1]);
663 LLtoXYZ(0, 0, ref_barycenter[2]);
666 double overlap_areas[nSourceCells];
667 double overlap_barycenters[nSourceCells][3];
669 nSourceCells, SourceCells, TargetCell,
670 overlap_areas, &overlap_barycenters[0]);
672 for (
int i = 0;
i < nSourceCells; ++
i) {
674 if (fabs(ref_area[i] - overlap_areas[i]) > area_tolerance)
675 PUT_ERR(
"ERROR in yac_compute_overlap_info (area)");
676 if (overlap_areas[i] > area_tolerance) {
680 ref_barycenter[i], overlap_barycenters[i]) > 1e-9)
681 PUT_ERR(
"ERROR in yac_compute_overlap_info (barycenter)");
685 for (
size_t i = 0;
i < nSourceCells; ++
i)
696 (
double[]){-0.5, 0.5, 0.5},
gc_edges, 3),
699 (
double[]){-0.5, 0.5, 0.5, 0.5},
gc_edges, 4)};
700 enum {nTargetCells =
sizeof(TargetCells)/
sizeof(TargetCells[0])};
704 (
double[]){-0.7, 0.6, 0.6},
gc_edges, 3),
706 (
double[]){-0.3, 0.4, 0.4},
gc_edges, 3),
708 (
double[]){-0.5, 0.5, 0.5},
gc_edges, 3),
715 enum {nSourceCells =
sizeof(SourceCells)/
sizeof(SourceCells[0])};
717 double ref_area[nSourceCells];
718 double ref_barycenter[nSourceCells][3];
719 for (
int i = 0;
i < nSourceCells; ++
i)
720 for (
int j = 0; j < 3; ++j)
721 ref_barycenter[i][j] = 0.0;
727 double intersection[3], intersection_lon, intersection_lat;
731 XYZtoLL(intersection, &intersection_lon, &intersection_lat);
736 (
double[]){0.0, 0.5, intersection_lat},
743 (
double[]){ 0.5, -0.5, 0.0, intersection_lat},
750 ref_barycenter[5][0] = 0.0;
751 ref_barycenter[5][1] = 0.0;
752 ref_barycenter[5][2] = 0.0;
755 for (
int i = 0;
i < nTargetCells; ++
i) {
757 double overlap_areas[nSourceCells];
758 double overlap_barycenters[nSourceCells][3];
760 nSourceCells, SourceCells, TargetCells[i],
761 overlap_areas, &overlap_barycenters[0]);
763 for (
int i = 0;
i < nSourceCells; ++
i) {
765 if (fabs(ref_area[i] - overlap_areas[i]) > area_tolerance)
766 PUT_ERR(
"ERROR in yac_compute_overlap_info (area)");
767 if (overlap_areas[i] > area_tolerance) {
771 ref_barycenter[i], overlap_barycenters[i]) > 1e-9)
772 PUT_ERR(
"ERROR in yac_compute_overlap_info (barycenter)");
776 for (
int i = 0;
i < nSourceCells; ++
i)
778 for (
int i = 0;
i < nTargetCells; ++
i)
788static void utest_check_partial_areas(
789 double * tgt_lon,
double * tgt_lat,
791 double ** src_lons,
double ** src_lats,
792 enum yac_edge_type ** src_edges,
int * src_counts,
size_t nSourceCells,
802 double const epsilon = 1.0e-10;
808 xmalloc(nSourceCells *
sizeof(*SourceCells));
809 for (
size_t i = 0;
i < nSourceCells; ++
i)
812 src_lons[i], src_lats[i], src_edges[i], src_counts[i]);
815 double area_tolerance =
MAX(tgt_area * 1e-6, 1e-10);
817 double partial_areas[nSourceCells];
819 nSourceCells, SourceCells, TargetCell, partial_areas);
821 double partial_areas_sum = 0.0;
823 for (
size_t i = 0;
i < nSourceCells; ++
i) {
824 partial_areas_sum += partial_areas[
i];
825 weights[
i] = partial_areas[
i] / tgt_area;
829 if (fabs(partial_areas_sum - tgt_area) > area_tolerance)
830 PUT_ERR(
"ERROR in sum of partial areas\n");
834 double weights_sum = 0.0;
835 for (
size_t i = 0;
i < nSourceCells; ++
i) weights_sum += weights[i];
836 if ( fabs(weights_sum-1.0) > epsilon )
837 PUT_ERR(
"ERROR in sum of corrected weights\n");
839 for (
size_t i = 0;
i < nSourceCells; ++
i)
845static void utest_check_partial_areas_deg(
846 double * tgt_lon,
double * tgt_lat,
848 double ** src_lons,
double ** src_lats,
849 enum yac_edge_type ** src_edges,
int * src_counts,
size_t nSourceCells) {
851 utest_check_partial_areas(
852 tgt_lon, tgt_lat, tgt_edges, tgt_count,
853 src_lons, src_lats, src_edges, src_counts, nSourceCells,
857static void utest_check_partial_areas_rad(
858 double * tgt_lon,
double * tgt_lat,
860 double ** src_lons,
double ** src_lats,
861 enum yac_edge_type ** src_edges,
int * src_counts,
size_t nSourceCells) {
863 utest_check_partial_areas(
864 tgt_lon, tgt_lat, tgt_edges, tgt_count,
865 src_lons, src_lats, src_edges, src_counts, nSourceCells,
double yac_huiliers_area(struct yac_grid_cell cell)
Area calculation on a unit sphere taken from ESMF based on L'Huilier's Theorem.
double yac_huiliers_area_info(struct yac_grid_cell cell, double *barycenter, double sign)
Structs and interfaces for area calculations.
void yac_correct_weights(size_t nSourceCells, double *weight)
correct interpolation weights
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,...
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,...
static void generate_cell(struct point_list *list, struct yac_grid_cell *cell)
void yac_compute_overlap_buf_free()
static void normalise_vector(double v[])
static double get_vector_angle(double const a[3], double const b[3])
void yac_free_grid_cell(struct yac_grid_cell *cell)
@ YAC_GREAT_CIRCLE_EDGE
great circle
@ YAC_LAT_CIRCLE_EDGE
latitude circle
@ YAC_LON_CIRCLE_EDGE
longitude circle
static void XYZtoLL(double const p_in[], double *lon, double *lat)
struct yac_grid_cell generate_cell_rad(double *lon, double *lat, enum yac_edge_type *edge_type, size_t num_corners)
struct yac_grid_cell generate_cell_deg(double *lon, double *lat, enum yac_edge_type *edge_type, size_t num_corners)
int intersect(enum yac_edge_type edge_type_a, double lon_a, double lat_a, double lon_b, double lat_b, enum yac_edge_type edge_type_b, double lon_c, double lat_c, double lon_d, double lat_d, double *intersection)
static enum yac_edge_type gc_edges[]
static enum yac_edge_type latlon_edges[4]
static void LLtoXYZ(double lon, double lat, double p_out[])