YAC 3.12.0
Yet Another Coupler
Loading...
Searching...
No Matches
test_area.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#include <stdlib.h>
6#include <stdio.h>
7#include <math.h>
8#include "test_common.h"
9#include "clipping.h"
10#include "area.h"
11#include "tests.h"
12#include "geometry.h"
13
19#define YAC_EARTH_RADIUS (6371.2290)
20
21static int utest_compare_area(double a, double b);
22static void utest_test_area(struct yac_grid_cell cell, double ref_area,
23 double (*area_func)(struct yac_grid_cell));
24
25int main (void) {
26
27 enum yac_edge_type gc_edges[] =
31 enum yac_edge_type lat_edges[4] =
33
34 double area;
35
36 puts ("----- calculating area -----\n");
37
38 {
39 /* set the test data over the Equator
40
41 0.0 (lon)
42 0.5 (lat)
43 / \
44 / \
45 -0.5 / \ 0.5
46 0.0 \ / 0.0
47 \ /
48 \ /
49 0.0
50 -0.5
51 */
52
53 struct yac_grid_cell Quad =
54 generate_cell_deg((double[4]){0.5, 0.0, -0.5, 0.0},
55 (double[4]){0.0, 0.5, 0.0, -0.5}, gc_edges, 4);
56
57 area = yac_pole_area ( Quad );
58 printf ( "pole area of quad over Equator is %f sqr km\n", area * YAC_EARTH_RADIUS * YAC_EARTH_RADIUS );
59
60 area = yac_huiliers_area ( Quad );
61 printf ( "huiliers area of quad over Equator is %f sqr km\n", area * YAC_EARTH_RADIUS * YAC_EARTH_RADIUS );
62 yac_free_grid_cell(&Quad);
63 }
64
65 {
66 /* Triangle, half of the above Quad */
67
68 struct yac_grid_cell Tri =
69 generate_cell_deg((double[3]){0.5, 0.0, -0.5},
70 (double[3]){0.0, 0.5, 0.0}, gc_edges, 3);
71
72 area = yac_triangle_area ( Tri );
73 printf ( "ICON area of triangle over Equator is %f sqr km\n", area * YAC_EARTH_RADIUS * YAC_EARTH_RADIUS );
74
75 area = yac_pole_area ( Tri );
76 printf ( "pole area of triangle over Equator is %f sqr km\n", area * YAC_EARTH_RADIUS * YAC_EARTH_RADIUS );
77
78 area = yac_huiliers_area ( Tri );
79 printf ( "huiliers area of triangle over Equator is %f sqr km\n", area * YAC_EARTH_RADIUS * YAC_EARTH_RADIUS );
81 }
82
83 {
84 /* set the test data over the Equator
85
86 -0.5 0.5 (lon)
87 0.5 ----------- 0.5 (lat)
88 | |
89 | |
90 | |
91 | |
92 | |
93 -0.5 ----------- 0.5
94 -0.5 -0.5
95
96 */
97
98 struct yac_grid_cell Quad =
99 generate_cell_deg((double[4]){-0.5, 0.5, 0.5, -0.5},
100 (double[4]){-0.5, -0.5, 0.5, 0.5}, gc_edges, 4);
101
102 area = yac_pole_area ( Quad );
103 printf ( "pole area of quad over Equator is %f sqr km\n", area * YAC_EARTH_RADIUS * YAC_EARTH_RADIUS );
104
105 area = yac_huiliers_area ( Quad );
106 printf ( "huiliers area of quad over Equator is %f sqr km\n", area * YAC_EARTH_RADIUS * YAC_EARTH_RADIUS );
107
108 double ref_area = yac_pole_area(Quad);
109
110 utest_test_area(Quad, ref_area, yac_pole_area);
111 utest_test_area(Quad, ref_area, yac_huiliers_area);
112
113 yac_free_grid_cell(&Quad);
114 }
115
116 {
117 /* Half of the above Quad */
118
119 struct yac_grid_cell Tri =
120 generate_cell_deg((double[3]){-0.5, 0.5, 0.5},
121 (double[3]){-0.5, -0.5, 0.5}, gc_edges, 3);
122
123 area = yac_triangle_area ( Tri );
124 printf ( "ICON area of triangle over Equator is %f sqr km\n", area * YAC_EARTH_RADIUS * YAC_EARTH_RADIUS );
125
126 area = yac_pole_area ( Tri );
127 printf ( "pole area of triangle over Equator is %f sqr km\n", area * YAC_EARTH_RADIUS * YAC_EARTH_RADIUS );
128
129 area = yac_huiliers_area ( Tri );
130 printf ( "huiliers area of triangle over Equator is %f sqr km\n", area * YAC_EARTH_RADIUS * YAC_EARTH_RADIUS );
131
132 yac_free_grid_cell(&Tri);
133 }
134
135 {
136
137 struct yac_grid_cell Tri =
138 generate_cell_deg((double[3]){150.0, 180.0, 180.0},
139 (double[3]){-60.0, -60.0, -90.0}, gc_edges, 3);
140
141 area = yac_triangle_area ( Tri );
142 printf ( "ICON area of triangle over South Pole is %f sqr km\n", area * YAC_EARTH_RADIUS * YAC_EARTH_RADIUS );
143
144 area = yac_pole_area ( Tri );
145 printf ( "pole area of triangle over South Pole is %f sqr km\n", area * YAC_EARTH_RADIUS * YAC_EARTH_RADIUS );
146
147 area = yac_huiliers_area ( Tri );
148 printf ( "huiliers area of triangle over South Pole is %f sqr km\n", area * YAC_EARTH_RADIUS * YAC_EARTH_RADIUS );
149
150 yac_free_grid_cell(&Tri);
151 }
152
153 {
154 /* set the test data over the North Pole
155
156 90.0 0.0 (lon)
157 89.5 ----------- 89.5 (lat)
158 | |
159 | |
160 | x |
161 | |
162 | |
163 180.0 ----------- 270.0
164 89.5 89.5
165
166 */
167
168 struct yac_grid_cell Quad =
169 generate_cell_deg((double[4]){0.0, 90.0, -180.0, -90.0},
170 (double[4]){89.5, 89.5, 89.5, 89.5}, gc_edges, 4);
171
172 area = yac_pole_area ( Quad );
173 printf ( "pole area of quad over North Pole is %f sqr km\n", area * YAC_EARTH_RADIUS * YAC_EARTH_RADIUS );
174
175 area = yac_huiliers_area ( Quad );
176 printf ( "huiliers area of quad over North Pole is %f sqr km\n", area * YAC_EARTH_RADIUS * YAC_EARTH_RADIUS );
177
178 yac_free_grid_cell(&Quad);
179 }
180
181 {
182 struct yac_grid_cell Quad =
183 generate_cell_deg((double[4]){-180.0, -150.0, -150.0, -180.0},
184 (double[4]){60.0, 60.0, 90.0, 90.0}, gc_edges, 4);
185
186 area = yac_pole_area ( Quad );
187 printf ( "pole area of quad near North Pole is %f sqr km\n", area * YAC_EARTH_RADIUS * YAC_EARTH_RADIUS );
188
189 area = yac_huiliers_area ( Quad );
190 printf ( "huiliers area of quad near North Pole is %f sqr km\n", area * YAC_EARTH_RADIUS * YAC_EARTH_RADIUS );
191
192 yac_free_grid_cell(&Quad);
193 }
194
195 {
196 struct yac_grid_cell Quad =
197 generate_cell_deg((double[4]){-180.0, -150.0, -150.0, -180.0},
198 (double[4]){-90.0, -90.0, -60.0, -60.0}, gc_edges, 4);
199
200 printf ( "ICON area of quad near South Pole is %f sqr km\n", area * YAC_EARTH_RADIUS * YAC_EARTH_RADIUS );
201
202 area = yac_pole_area ( Quad );
203 printf ( "pole area of quad near South Pole is %f sqr Km \n", area * YAC_EARTH_RADIUS * YAC_EARTH_RADIUS );
204
205 area = yac_huiliers_area ( Quad );
206 printf ( "huiliers area of quad near South Pole is %f sqr Km \n", area * YAC_EARTH_RADIUS * YAC_EARTH_RADIUS );
207
208 yac_free_grid_cell(&Quad);
209 }
210
211 {
212 struct yac_grid_cell Quin =
213 generate_cell_deg((double[5]){-180.0, -150.0, 0.0, -150.0, -180.0},
214 (double[5]){60.0, 60.0, 90.0, 90.0, 90.0}, gc_edges, 5);
215
216 area = yac_pole_area ( Quin );
217 printf ( "pole area of quin near North Pole is %f sqr km\n", area * YAC_EARTH_RADIUS * YAC_EARTH_RADIUS );
218
219 area = yac_huiliers_area ( Quin );
220 printf ( "huiliers area of quin near North Pole is %f sqr km\n", area * YAC_EARTH_RADIUS * YAC_EARTH_RADIUS );
221
222 yac_free_grid_cell(&Quin);
223 }
224
225 {
226 /* Triangle that contains an edge of length zero */
227
228 struct yac_grid_cell Tri =
229 generate_cell_deg((double[3]){-0.5, 0.5, -0.5},
230 (double[3]){-0.5, -0.5, -0.5}, gc_edges, 3);
231
232 area = yac_triangle_area ( Tri );
233 printf ( "ICON area of triangle over Equator is %f sqr km\n", area * YAC_EARTH_RADIUS * YAC_EARTH_RADIUS );
234
235 area = yac_pole_area ( Tri );
236 printf ( "pole area of triangle over Equator is %f sqr km\n", area * YAC_EARTH_RADIUS * YAC_EARTH_RADIUS );
237
238 area = yac_huiliers_area ( Tri );
239 printf ( "huiliers area of triangle over Equator is %f sqr km\n", area * YAC_EARTH_RADIUS * YAC_EARTH_RADIUS );
240
241 if ((area < 0.0) || (area > 1e-9))
242 PUT_ERR("ERROR in yac_huiliers_area for zero size triangle");
243
244 yac_free_grid_cell(&Tri);
245 }
246
247 {
248 struct yac_grid_cell Quad =
249 generate_cell_deg((double[4]){0, 1, 1, 0},
250 (double[4]){0, 0, 1, 1}, gc_edges, 4);
251 struct yac_grid_cell Tri =
252 generate_cell_deg((double[3]){1, 1, 1},
253 (double[3]){0, 0, 1}, gc_edges, 3);
254
255 double base_area = yac_huiliers_area(Quad);
256
257 yac_free_grid_cell(&Quad);
258 yac_free_grid_cell(&Tri);
259
260 /* A dx of 1e-8 deg corresponds to a dx of ~1 mm on the Earth surface */
261
262 double dx[] = {1e-8, 1e-7, 1e-6, 1e-5, 1e-4, 1e-3, 1e-2, 1e-1,
263 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9};
264
265 for (size_t i = 0; i < sizeof(dx) / sizeof(dx[0]); ++i) {
266
267
268 struct yac_grid_cell Quad =
269 generate_cell_deg((double[4]){0, 1.0-dx[i], 1, 0},
270 (double[4]){0, 0, 1, 1}, gc_edges, 4);
271 struct yac_grid_cell Tri =
272 generate_cell_deg((double[3]){1.0-dx[i], 1, 1},
273 (double[3]){0, 0, 1}, gc_edges, 3);
274
275 double partial_area = yac_huiliers_area(Quad);
276 partial_area += yac_huiliers_area(Tri);
277
278 yac_free_grid_cell(&Quad);
279 yac_free_grid_cell(&Tri);
280
281 if (utest_compare_area(base_area, partial_area))
282 PUT_ERR("yac_huiliers_area computed wrong area\n");
283
284 printf ("accuracy check for (base_area - partial_area) %8.1e sqr km for dx %.1e\n",
285 base_area - partial_area, dx[i]);
286 }
287 }
288
289 {
290 struct yac_grid_cell Tri =
292 (double[3]){0.09817477/YAC_RAD, 0.09817477/YAC_RAD, 0.098174496/YAC_RAD},
293 (double[3]){0.353325247/YAC_RAD, 0.353335501/YAC_RAD, 0.353335609/YAC_RAD},
294 gc_edges, 3);
295
296 area = yac_pole_area(Tri);
297
298 if (area < 0)
299 PUT_ERR("pole_area computed wrong area\n");
300
301 printf ("pole accuracy check of very small area %.2e sqr km\n", area * YAC_EARTH_RADIUS * YAC_EARTH_RADIUS );
302
303 area = yac_huiliers_area(Tri);
304
305 if (area < 0)
306 PUT_ERR("huiliers_area computed wrong area\n");
307
308 printf ("huiliers accuracy check of very small area %.2e sqr km\n", area * YAC_EARTH_RADIUS * YAC_EARTH_RADIUS );
309
310 yac_free_grid_cell(&Tri);
311 }
312
313 {
314 double edge_length_deg = 1.0e-8; // ~1.11 mm
315
316 printf ("\n accuracy check for a unit square\n");
317 printf (" edge length [m] | plain | simple | pole | huiliers\n");
318 printf (" ----------------+--------------------+--------------------+--------------------+--------------------\n");
319 for ( unsigned i = 1; i < 11; ++i ) {
320
321 double edge_length_m =
322 edge_length_deg * YAC_RAD * YAC_EARTH_RADIUS * 1.0e3;
323
324 struct yac_grid_cell Quad =
325 generate_cell_deg((double[4]){0, edge_length_deg, edge_length_deg, 0},
326 (double[4]){0, 0, edge_length_deg, edge_length_deg},
327 gc_edges, 4);
328
329 double t_area = edge_length_m * edge_length_m;
330 double p_area = yac_planar_3dcell_area(Quad) * YAC_EARTH_RADIUS * YAC_EARTH_RADIUS * 1.0e6;
331 double s_area = yac_pole_area(Quad) * YAC_EARTH_RADIUS * YAC_EARTH_RADIUS * 1.0e6;
332 double h_area = yac_huiliers_area(Quad) * YAC_EARTH_RADIUS * YAC_EARTH_RADIUS * 1.0e6;
333
334 if (0)
335 printf (" %.8e m|%.8e sqr m|%.8e sqr m|%.8e sqr m|%.8e sqr m\n",
336 edge_length_m, p_area, t_area, s_area, h_area);
337
338 edge_length_deg *= 10.0;
339
340 yac_free_grid_cell(&Quad);
341 }
342
343 }
344
345 { // cell with two edges (one great circle and one circle of latitude)
346
347 for (int y = -90; y <= 90; y += 5) {
348
349 struct yac_grid_cell cell =
350 generate_cell_deg((double[2]){0.0, 20.0},
351 (double[2]){(double)y, (double)y},
352 (enum yac_edge_type[]){
354
355 // compute reference area
356 double ref_area;
357
358 {
359 double coordinates_x[3] = {0.0, 20.0, 0.0};
360 double coordinates_y[3] = {(double)y, (double)y, 0};
361
362 if ((y == -90) || (y == 90) || (y == 0)) {
363
364 ref_area = 0.0;
365
366 } else {
367
368 if (y < 0) {
369 ref_area = (coordinates_x[1]*YAC_RAD - coordinates_x[0]*YAC_RAD) *
370 (1 - cos(M_PI_2 + coordinates_y[0]*YAC_RAD));
371 coordinates_y[2] = -90.0;
372 } else {
373 ref_area = (coordinates_x[1]*YAC_RAD - coordinates_x[0]*YAC_RAD) *
374 (1 - cos(M_PI_2 - coordinates_y[0]*YAC_RAD));
375 coordinates_y[2] = 90.0;
376 }
377
378 struct yac_grid_cell tmp_cell =
380 // ref_area *= YAC_EARTH_RADIUS * YAC_EARTH_RADIUS;
381 ref_area -= yac_huiliers_area(tmp_cell);
382
383 yac_free_grid_cell(&tmp_cell);
384 }
385 }
386
387 utest_test_area(cell, ref_area, yac_pole_area);
388 utest_test_area(cell, ref_area, yac_huiliers_area);
389
390 yac_free_grid_cell(&cell);
391 }
392 }
393
394 { // cell with lon lat edges and one edge on the equator
395
396 double ref_area = sin(0.5 * YAC_RAD) * (0.5 * YAC_RAD);
397 // ref_area *= YAC_EARTH_RADIUS * YAC_EARTH_RADIUS;
398
399 double coordinates_x[2][4] = {{-0.5, 0.0, 0.0, -0.5},
400 { 0.0, 0.5, 0.5, 0.0}};
401 double coordinates_y[2][4] = {{-0.5, -0.5, 0.0, 0.0},
402 { 0.0, 0.0, 0.5, 0.5}};
403
404 for (int x = 0; x < 2; ++x) {
405 for (int y = 0; y < 2; ++y) {
406 struct yac_grid_cell cell =
407 generate_cell_deg(coordinates_x[x], coordinates_y[y], lat_edges, 4);
408
409 utest_test_area(cell, ref_area, yac_pole_area);
410 utest_test_area(cell, ref_area, yac_huiliers_area);
411
412 yac_free_grid_cell(&cell);
413 }
414 }
415 }
416
417 { // cell with lon lat edges (both lat edges on the different side of the
418 // equator)
419 double ref_area = (2.0 * sin(0.5 * YAC_RAD)) * (1.0 * YAC_RAD);
420 // ref_area *= YAC_EARTH_RADIUS * YAC_EARTH_RADIUS;
421
422 struct yac_grid_cell cell =
423 generate_cell_deg((double[4]){-0.5, 0.5, 0.5, -0.5},
424 (double[4]){-0.5, -0.5, 0.5, 0.5}, lat_edges, 4);
425
426 utest_test_area(cell, ref_area, yac_pole_area);
427 utest_test_area(cell, ref_area, yac_huiliers_area);
428
429 yac_free_grid_cell(&cell);
430 }
431
432 { // cell with lon lat edges (both lat edges on the same side of the equator)
433 double ref_area = sin(1.0 * YAC_RAD);
434 ref_area -= sin(0.5 * YAC_RAD);
435 ref_area *= 1.0 * YAC_RAD;
436 // ref_area *= YAC_EARTH_RADIUS * YAC_EARTH_RADIUS;
437
438 for (int i = 0; i < 2; ++i) {
439
440 double coordinates_x[4] = {-0.5, 0.5, 0.5, -0.5};
441 double coordinates_y[2][4] = {{ 0.5, 0.5, 1.0, 1.0},
442 {-0.5,-0.5,-1.0, -1.0}};
443 enum yac_edge_type edge_types[4] =
445
446 struct yac_grid_cell cell =
448
449 utest_test_area(cell, ref_area, yac_pole_area);
450 utest_test_area(cell, ref_area, yac_huiliers_area);
451
452 yac_free_grid_cell(&cell);
453 }
454 }
455
456 { // concave cell
457
458 double intersections[2][3];
459
460 if (!intersect(YAC_GREAT_CIRCLE_EDGE, 20.0, 59.0, 0.0, 80.0,
461 YAC_LAT_CIRCLE_EDGE, 0.0, 60.0, 20.0, 60.0,
462 intersections[0]))
463 return EXIT_FAILURE;
464 if (!intersect(YAC_GREAT_CIRCLE_EDGE, 20.0, 59.0, -20.0, 59.0,
465 YAC_LAT_CIRCLE_EDGE, 0.0, 60.0, 20.0, 60.0,
466 intersections[1]))
467 return EXIT_FAILURE;
468
469 double intersections_lon[2], intersections_lat[2];
470 XYZtoLL(intersections[0], &(intersections_lon[0]), &(intersections_lat[0]));
471 XYZtoLL(intersections[1], &(intersections_lon[1]), &(intersections_lat[1]));
472
473 // this cell is convex
474 struct yac_grid_cell partial_ref_cell =
476 (double[]){20.0, intersections_lon[0]/YAC_RAD,
477 intersections_lon[1]/YAC_RAD},
478 (double[]){59.0, 60.0, 60.0},
480
481 double partial_area = yac_pole_area(partial_ref_cell);
482
483 if (utest_compare_area(partial_area,
484 yac_huiliers_area(partial_ref_cell)))
485 PUT_ERR("pole_area != huiliers_area for convex cell");
486
487 double ref_area = 2.0 * partial_area;
488
489 struct yac_grid_cell cells[2] =
491 (double[]){20.0,
492 intersections_lon[0]/YAC_RAD,
493 intersections_lon[1]/YAC_RAD,
494 -intersections_lon[1]/YAC_RAD,
495 -intersections_lon[0]/YAC_RAD, -20.0},
496 (double[]){59.0, 60.0, 60.0, 60.0, 60.0, 59.0},
497 (enum yac_edge_type[]){
501 (double[]){20.0,
502 intersections_lon[0]/YAC_RAD,
503 -intersections_lon[0]/YAC_RAD,
504 -20.0,
505 -intersections_lon[1]/YAC_RAD,
506 intersections_lon[1]/YAC_RAD},
507 (double[]){59.0, 60.0, 60.0, 59.0, 60.0, 60.0},
508 (enum yac_edge_type[]){
511
512 for (int i = 0; i < 2; ++i) {
513 utest_test_area(cells[i], ref_area, yac_pole_area);
514 utest_test_area(cells[i], ref_area, yac_huiliers_area);
515 }
516 yac_free_grid_cell(&(cells[0]));
517 yac_free_grid_cell(&(cells[1]));
518 yac_free_grid_cell(&partial_ref_cell);
519 }
520
521 { // case extracted from ICON example, which requires a high accuracy in the
522 // area computation
523 struct yac_grid_cell cells[] = {
524 generate_cell_deg((double[]){-151.1489316535362661,
525 -151.7087167856307133,
526 -150.6174180645230933},
527 (double[]){ 10.6333746562670566,
528 11.5836995038666437,
529 11.6243355661022782}, gc_edges, 3),
530 generate_cell_deg((double[]){-152.8132296086113513,
531 -153.8786613849353557,
532 -151.6929566531634066},
533 (double[]){ 13.4512385235805798,
534 11.4650630285209161,
535 11.5568484830228009}, gc_edges, 3),
536 generate_cell_deg((double[]){-152.8132296086113513,
537 -151.6929566531634066,
538 -150.6265735326831532},
539 (double[]){ 13.4512385235805798,
540 11.5568484830228009,
541 13.5446528932721275}, gc_edges, 3),
542 generate_cell_deg((double[]){-153.8786613849353557,
543 -151.6929566531634066,
544 -152.7627337461449031},
545 (double[]){ 11.4650630285209161,
546 11.5568484830228009,
547 9.5827293336264265}, gc_edges, 3),
548 generate_cell_deg((double[]){-151.6929566531634066,
549 -152.7627337461449031,
550 -150.5840076321059371},
551 (double[]){ 11.5568484830228009,
552 9.5827293336264265,
553 9.6520960946755832}, gc_edges, 3),
554 generate_cell_deg((double[]){-151.6929566531634066,
555 -150.6265735326831532,
556 -149.5139953075027108},
557 (double[]){ 11.5568484830228009,
558 13.5446528932721275,
559 11.6284420125700851}, gc_edges, 3),
560 generate_cell_deg((double[]){-151.6929566531634066,
561 -149.5139953075027108,
562 -150.5840076321059371},
563 (double[]){ 11.5568484830228009,
564 11.6284420125700851,
565 9.6520960946755832}, gc_edges, 3)};
566 size_t num_cells = sizeof(cells) / sizeof(cells[0]);
567
568 struct yac_grid_cell overlap_cells[sizeof(cells) / sizeof(cells[0]) - 1];
569 for (size_t i = 0; i < num_cells-1; ++i)
570 yac_init_grid_cell(&overlap_cells[i]);
571
572 yac_cell_clipping(num_cells - 1, &cells[1], cells[0], &overlap_cells[0]);
573
574 double tgt_area = yac_huiliers_area(cells[0]);
575 double area_tol = tgt_area * 1e-8;
576 double diff_area = tgt_area;
577
578 for (size_t i = 0; i < num_cells-1; ++i)
579 diff_area -= yac_huiliers_area(overlap_cells[i]);
580
581 if (fabs(diff_area) > area_tol)
582 PUT_ERR("yac_huiliers_area is too inaccurate");
583
584 for (size_t i = 0; i < num_cells; ++i)
585 yac_free_grid_cell(&cells[i]);
586 for (size_t i = 0; i < num_cells-1; ++i)
587 yac_free_grid_cell(&overlap_cells[i]);
588 }
589
590 { // check for a bug found by Uwe Schulzweida
591
592 struct yac_grid_cell Tri =
593 generate_cell_deg((double[3]){0.5, 0.5, -0.5},
594 (double[3]){0.0, 0.0, 0.0}, gc_edges, 3);
595
596 if (yac_triangle_area(Tri) != 0.0)
597 PUT_ERR("ERROR in yac_triangle_area");
598 yac_free_grid_cell(&Tri);
599
600 Tri = generate_cell_deg((double[3]){0.5, -0.5, 0.5},
601 (double[3]){0.0, 0.0, 0.0}, gc_edges, 3);
602
603 if (yac_triangle_area(Tri) != 0.0)
604 PUT_ERR("ERROR in yac_triangle_area");
605 yac_free_grid_cell(&Tri);
606
607 Tri = generate_cell_deg((double[3]){-0.5, 0.5, 0.5},
608 (double[3]){0.0, 0.0, 0.0}, gc_edges, 3);
609
610 if (yac_triangle_area(Tri) != 0.0)
611 PUT_ERR("ERROR in yac_triangle_area");
612 yac_free_grid_cell(&Tri);
613 }
614
615 {
616 double ref_area = 0.0;
617 double ref_barycenter[3] = {0.0, 0.0, 0.0};
618
619 {
620 struct yac_grid_cell ref_cell =
622 (double[]){0.0,1.0,1.0, 0.0},
623 (double[]){0.0,0.0,1.0, 1.0}, gc_edges, 4);
624 ref_area = yac_huiliers_area_info(ref_cell, ref_barycenter, 1.0);
625 yac_free_grid_cell(&ref_cell);
626 normalise_vector(ref_barycenter);
627 }
628
629 enum {NUM_CORNERS = 6};
630 double coordinates_x[NUM_CORNERS] = {0.0, 1.0, 1.0, 0.0, 1.0, 0.0};
631 double coordinates_y[NUM_CORNERS] = {0.0, 0.0, 1.0, 0.0, 1.0, 1.0};
632
633 for (size_t i = 0; i < NUM_CORNERS; ++i) {
634
635 double temp_coordinates_x[NUM_CORNERS];
636 double temp_coordinates_y[NUM_CORNERS];
637
638 for (size_t j = 0; j < NUM_CORNERS; ++j) {
639 temp_coordinates_x[(i+j)%NUM_CORNERS] = coordinates_x[j];
640 temp_coordinates_y[(i+j)%NUM_CORNERS] = coordinates_y[j];
641 }
642 double area = 0.0, barycenter[3] = {0.0, 0.0, 0.0};
643 struct yac_grid_cell cell =
645 temp_coordinates_x, temp_coordinates_y, gc_edges, NUM_CORNERS);
646 area = yac_huiliers_area_info(cell, barycenter, 1.0);
647 yac_free_grid_cell(&cell);
648
649 normalise_vector(barycenter);
650 if (fabs(area - ref_area) > YAC_AREA_TOL)
651 PUT_ERR("ERROR in yac_huiliers_area_info (area)");
652
653 if (get_vector_angle(barycenter, ref_barycenter) > yac_angle_tol)
654 PUT_ERR("ERROR in yac_huiliers_area_info (barycenter)");
655
656 // check for NANs
657 if ((barycenter[0] != barycenter[0]) ||
658 (barycenter[1] != barycenter[1]) ||
659 (barycenter[2] != barycenter[2]))
660 PUT_ERR("ERROR in yac_huiliers_area_info (barycenter NAN)");
661 }
662 }
663
664 { // check influence of lat circle edges on computation of the barycenter
665 // of a cell
666
667 for (int pole = -1; pole <= 1; pole += 2) {
668 for (int cell_order_a = 0; cell_order_a < 2; ++cell_order_a) {
669 for (int cell_order_b = 0; cell_order_b < 2; ++cell_order_b) {
670
671 enum yac_edge_type ll_edges[3] =
673 double lon[2][3] = {{0.0,0.0,20.0}, {20.0, 20.0, 0.0}};
674 struct yac_grid_cell gc_triangle =
676 lon[cell_order_a],
677 (double[]){copysign(88.0,(double)pole),
678 copysign(90.0,(double)pole),
679 copysign(88.0,(double)pole)}, gc_edges, 3);
680 struct yac_grid_cell ll_triangle =
682 lon[cell_order_b],
683 (double[]){copysign(88.0,(double)pole),
684 copysign(90.0,(double)pole),
685 copysign(88.0,(double)pole)}, ll_edges, 3);
686
687 double gc_barycenter[3] = {0.0, 0.0, 0.0};
688 double gc_area =
689 yac_huiliers_area_info(gc_triangle, gc_barycenter, 1.0);
690 double ll_barycenter[3] = {0.0, 0.0, 0.0};
691 double ll_area =
692 yac_huiliers_area_info(ll_triangle, ll_barycenter, 1.0);
693
694 if (gc_area < 0.0) {
695 gc_area = -gc_area;
696 gc_barycenter[0] = -gc_barycenter[0];
697 gc_barycenter[1] = -gc_barycenter[1];
698 gc_barycenter[2] = -gc_barycenter[2];
699 }
700 normalise_vector(gc_barycenter);
701
702 if (ll_area < 0.0) {
703 ll_area = -ll_area;
704 ll_barycenter[0] = -ll_barycenter[0];
705 ll_barycenter[1] = -ll_barycenter[1];
706 ll_barycenter[2] = -ll_barycenter[2];
707 }
708 normalise_vector(ll_barycenter);
709
710 // the triangle with the lat circle edge should be bigger
711 if ((ll_area - gc_area) < YAC_AREA_TOL)
712 PUT_ERR("ERROR in yac_huiliers_area_info (area)");
713
714 // the barycenter of the triangle with the gc edges should be closer
715 // to the pole
716 if (((gc_barycenter[2] - ll_barycenter[2]) * (double)pole) < 1e-9)
717 PUT_ERR("ERROR in yac_huiliers_area_info (barycenter)");
718 }
719 }
720 }
721 }
722
723 return TEST_EXIT_CODE;
724}
725
726static void utest_test_area(struct yac_grid_cell cell, double ref_area,
727 double (*area_func)(struct yac_grid_cell)) {
728
729 double mem_dummy_[128][3];
730 enum yac_edge_type edge_dummy[128];
731 struct yac_grid_cell test_cell = {.coordinates_xyz = mem_dummy_,
732 .edge_type = edge_dummy,
733 .num_corners = cell.num_corners};
734
735 for (int order = -1; order <= 1; order += 2) {
736 for (int start = 0; start < (int)(cell.num_corners); ++start) {
737
738 for (int i = 0; i < (int)(cell.num_corners); ++i) {
739 int j = ((int)(cell.num_corners)+start+i*order)%(int)(cell.num_corners);
740 test_cell.coordinates_xyz[i][0] = cell.coordinates_xyz[j][0];
741 test_cell.coordinates_xyz[i][1] = cell.coordinates_xyz[j][1];
742 test_cell.coordinates_xyz[i][2] = cell.coordinates_xyz[j][2];
743 j = ((int)(cell.num_corners) + j - (order < 0))%(int)(cell.num_corners);
744 test_cell.edge_type[i] = cell.edge_type[j];
745 }
746
747 double area = area_func(test_cell);
748
749 if (utest_compare_area(area, ref_area)) PUT_ERR("ERROR: wrong area\n");
750 }
751 }
752}
753
754static int utest_compare_area(double a, double b) {
755
756 double diff = fabs(a - b);
757 double tol = MAX(MIN(a,b)*1e-6, YAC_AREA_TOL);
758
759 if (diff < tol) return 0;
760 else return (a > b) - (a < b);
761}
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
double yac_pole_area(struct yac_grid_cell cell)
Calculate the area of a cell in a 3d plane on a unit sphere.
Definition area.c:332
double yac_planar_3dcell_area(struct yac_grid_cell cell)
Area calculation on a unit sphere of a planar polygon in 3D.
Definition area.c:417
double yac_huiliers_area_info(struct yac_grid_cell cell, double *barycenter, double sign)
Definition area.c:539
double yac_triangle_area(struct yac_grid_cell cell)
Calculate the area of a triangle on a unit sphere.
Definition area.c:21
Structs and interfaces for area calculations.
#define YAC_AREA_TOL
Definition area.h:18
static double const tol
void yac_cell_clipping(size_t N, struct yac_grid_cell *source_cell, struct yac_grid_cell target_cell, struct yac_grid_cell *overlap_buffer)
cell clipping to get the cells describing the intersections
Definition clipping.c:1088
#define YAC_RAD
#define yac_angle_tol
Definition geometry.h:26
static void normalise_vector(double v[])
Definition geometry.h:635
static double get_vector_angle(double const a[3], double const b[3])
Definition geometry.h:340
void yac_init_grid_cell(struct yac_grid_cell *cell)
Definition grid_cell.c:14
void yac_free_grid_cell(struct yac_grid_cell *cell)
Definition grid_cell.c:44
yac_edge_type
Definition grid_cell.h:12
@ YAC_GREAT_CIRCLE_EDGE
great circle
Definition grid_cell.h:13
@ YAC_LAT_CIRCLE_EDGE
latitude circle
Definition grid_cell.h:14
@ YAC_LON_CIRCLE_EDGE
longitude circle
Definition grid_cell.h:15
static void XYZtoLL(double const p_in[], double *lon, double *lat)
size_t num_corners
Definition grid_cell.h:21
enum yac_edge_type * edge_type
Definition grid_cell.h:20
double(* coordinates_xyz)[3]
Definition grid_cell.h:19
#define YAC_EARTH_RADIUS
Definition test_area.c:19
struct yac_grid_cell generate_cell_deg(double *lon, double *lat, enum yac_edge_type *edge_type, size_t num_corners)
Definition test_common.c:36
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)
Definition test_common.c:64
static enum yac_edge_type gc_edges[]
double coordinates_x[]
size_t num_cells[2]
double coordinates_y[]
#define TEST_EXIT_CODE
Definition tests.h:14
#define PUT_ERR(string)
Definition tests.h:10
#define MIN(a, b)
Definition toy_common.h:29
#define MAX(a, b)