YAC 3.21.0
Yet Another Coupler
Loading...
Searching...
No Matches
test_lat_clipping.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
9#include "grids/basic_grid.h"
10#include "clipping.h"
11#include "geometry.h"
12#include "tests.h"
13#include "area.h"
14#include "test_common.h"
15
21static void utest_lat_clipping(struct yac_grid_cell cells,
22 double deg_lat_bounds[2],
23 struct yac_grid_cell * ref_cells,
24 unsigned num_ref_cells);
25
26static int utest_compare_cells(struct yac_grid_cell a, struct yac_grid_cell b);
27
28static void utest_lat_clipping_degenerate_cells(void);
29
30static double utest_get_intersection(
31 enum yac_edge_type edge_type, double points[2][2], double lat) {
32
33 double intersection[3], intersection_lon, intersection_lat;
34
35 if (!utest_intersect(edge_type, points[0][0], points[0][1],
36 points[1][0], points[1][1],
37 YAC_LAT_CIRCLE_EDGE, points[0][0], lat,
38 points[1][0], lat, intersection))
39 exit(EXIT_FAILURE);
40 XYZtoLL(intersection, &intersection_lon, &intersection_lat);
41 return intersection_lon / YAC_RAD;
42}
43
44int main (void) {
45
46 enum yac_edge_type gc_edges[] = {
53 // edges of a lon-lat cell whose lat edge collapsed at a pole
54 // (the pole is the first corner)
55 enum yac_edge_type lonlat_pole_edges[] = {
57 // edges of a cell whose boundary is completely on a circle of latitude
58 enum yac_edge_type lat3_edges[] = {
60
61 double temp_lon[16];
62
63 // a gaussian cell outside the lat bound
64 utest_lat_clipping(
65 utest_generate_cell_deg(
66 (double[4]){-5,5,5,-5},
67 (double[4]){-5,-5,5,5}, latlon_edges, 4),
68 (double[2]){10, 20}, NULL, 0);
69
70 // a gaussian cell outside the lat bound
71 utest_lat_clipping(
72 utest_generate_cell_deg(
73 (double[4]){-5,5,5,-5},
74 (double[4]){-5,-5,10,10}, latlon_edges, 4),
75 (double[2]){10, 20}, NULL, 0);
76
77 // a gaussian cell outside the lat bound
78 utest_lat_clipping(
79 utest_generate_cell_deg(
80 (double[4]){-5,5,5,-5},
81 (double[4]){20,20,30,30}, latlon_edges, 4),
82 (double[2]){10, 20}, NULL, 0);
83
84 // a gaussian cell outside the lat bound
85 utest_lat_clipping(
86 utest_generate_cell_deg(
87 (double[4]){-5,5,5,-5},
88 (double[4]){80,80,90,90}, latlon_edges, 4),
89 (double[2]){10, 20}, NULL, 0);
90
91 // a gaussian cell outside the lat bound
92 utest_lat_clipping(
93 utest_generate_cell_deg(
94 (double[4]){-5,5,5,-5},
95 (double[4]){-80,-80,-90,-90}, latlon_edges, 4),
96 (double[2]){10, 20}, NULL, 0);
97
98 // a gaussian cell outside the lat bound (one bound is at a pole)
99 utest_lat_clipping(
100 utest_generate_cell_deg(
101 (double[4]){-5,5,5,-5},
102 (double[4]){10,10,20,20}, latlon_edges, 4),
103 (double[2]){80, 90}, NULL, 0);
104
105 // a gaussian cell outside the lat bound (both bounds are identical)
106 utest_lat_clipping(
107 utest_generate_cell_deg(
108 (double[4]){-5,5,5,-5},
109 (double[4]){10,10,20,20}, latlon_edges, 4),
110 (double[2]){0, 0}, NULL, 0);
111
112 // a gaussian cell outside the lat bound (both bounds are identical)
113 utest_lat_clipping(
114 utest_generate_cell_deg(
115 (double[4]){-5,5,5,-5},
116 (double[4]){-10,-10,-20,-20}, latlon_edges, 4),
117 (double[2]){0, 0}, NULL, 0);
118
119 // a gaussian cell outside the lat bound (both bounds are identical)
120 utest_lat_clipping(
121 utest_generate_cell_deg(
122 (double[4]){-5,5,5,-5},
123 (double[4]){-5,-5,5,5}, latlon_edges, 4),
124 (double[2]){0, 0}, NULL, 0);
125
126 // a gaussian cell overlapping with the lat bound
127 utest_lat_clipping(
128 utest_generate_cell_deg(
129 (double[4]){-5,5,5,-5},
130 (double[4]){-10,-10,10,10}, latlon_edges, 4),
131 (double[2]){-5, 5},
132 (struct yac_grid_cell[]){
133 utest_generate_cell_deg(
134 (double[4]){-5,5,5,-5},
135 (double[4]){-5,-5,5,5}, latlon_edges, 4)}, 1);
136
137 // a gaussian cell overlapping with the lat bound
138 utest_lat_clipping(
139 utest_generate_cell_deg(
140 (double[4]){40,45,45,40},
141 (double[4]){10,10,20,20}, latlon_edges, 4),
142 (double[2]){12, 15},
143 (struct yac_grid_cell[]){
144 utest_generate_cell_deg(
145 (double[4]){40,45,45,40},
146 (double[4]){12,12,15,15}, latlon_edges, 4)}, 1);
147
148 // a gaussian cell overlapping with the lat bound
149 utest_lat_clipping(
150 utest_generate_cell_deg(
151 (double[4]){40,45,45,40},
152 (double[4]){10,10,20,20}, latlon_edges, 4),
153 (double[2]){15, 25},
154 (struct yac_grid_cell[]){
155 utest_generate_cell_deg(
156 (double[4]){40,45,45,40},
157 (double[4]){15,15,20,20}, latlon_edges, 4)}, 1);
158
159 // a gaussian cell overlapping with the lat bound
160 utest_lat_clipping(
161 utest_generate_cell_deg(
162 (double[4]){40,45,45,40},
163 (double[4]){10,10,20,20}, latlon_edges, 4),
164 (double[2]){15, 5},
165 (struct yac_grid_cell[]){
166 utest_generate_cell_deg(
167 (double[4]){40,45,45,40},
168 (double[4]){15,15,10,10}, latlon_edges, 4)}, 1);
169
170 // a gaussian cell overlapping with the lat bound
171 utest_lat_clipping(
172 utest_generate_cell_deg(
173 (double[4]){40,45,45,40},
174 (double[4]){10,10,20,20}, latlon_edges, 4),
175 (double[2]){5, 25},
176 (struct yac_grid_cell[]){
177 utest_generate_cell_deg(
178 (double[4]){40,45,45,40},
179 (double[4]){10,10,20,20}, latlon_edges, 4)}, 1);
180
181 // a gaussian cell
182 utest_lat_clipping(
183 utest_generate_cell_deg(
184 (double[4]){40,45,45,40},
185 (double[4]){10,10,20,20}, latlon_edges, 4),
186 (double[2]){90, 80}, NULL, 0);
187
188 // a gaussian cell
189 utest_lat_clipping(
190 utest_generate_cell_deg(
191 (double[4]){40,45,45,40},
192 (double[4]){90,90,70,70}, latlon_edges, 4),
193 (double[2]){90, 80},
194 (struct yac_grid_cell[]){
195 utest_generate_cell_deg(
196 (double[4]){40,45,45,40},
197 (double[4]){90,90,80,80}, latlon_edges, 4)}, 1);
198
199 // a gaussian cell
200 utest_lat_clipping(
201 utest_generate_cell_deg(
202 (double[4]){40,45,45,40},
203 (double[4]){90,90,85,85}, latlon_edges, 4),
204 (double[2]){90, 80},
205 (struct yac_grid_cell[]){
206 utest_generate_cell_deg(
207 (double[4]){40,45,45,40},
208 (double[4]){90,90,85,85}, latlon_edges, 4)}, 1);
209
210 // a gaussian cell
211 utest_lat_clipping(
212 utest_generate_cell_deg(
213 (double[4]){40,45,45,40},
214 (double[4]){88,88,83,83}, latlon_edges, 4),
215 (double[2]){90, 80},
216 (struct yac_grid_cell[]){
217 utest_generate_cell_deg(
218 (double[4]){40,45,45,40},
219 (double[4]){88,88,83,83}, latlon_edges, 4)}, 1);
220
221 // a gaussian cell
222 utest_lat_clipping(
223 utest_generate_cell_deg(
224 (double[4]){40,45,45,40},
225 (double[4]){88,88,83,83}, latlon_edges, 4),
226 (double[2]){90, 80},
227 (struct yac_grid_cell[]){
228 utest_generate_cell_deg(
229 (double[4]){40,45,45,40},
230 (double[4]){88,88,83,83}, latlon_edges, 4)}, 1);
231
232 // a gaussian cell
233 utest_lat_clipping(
234 utest_generate_cell_deg(
235 (double[4]){40,45,45,40},
236 (double[4]){88,88,70,70}, latlon_edges, 4),
237 (double[2]){90, 80},
238 (struct yac_grid_cell[]){
239 utest_generate_cell_deg(
240 (double[4]){40,45,45,40},
241 (double[4]){88,88,80,80}, latlon_edges, 4)}, 1);
242
243 // a gaussian cell
244 utest_lat_clipping(
245 utest_generate_cell_deg(
246 (double[4]){40,45,45,40},
247 (double[4]){10,10,20,20}, latlon_edges, 4),
248 (double[2]){-90, -80}, NULL, 0);
249
250 // a gaussian cell
251 utest_lat_clipping(
252 utest_generate_cell_deg(
253 (double[4]){40,45,45,40},
254 (double[4]){-90,-90,-70,-70}, latlon_edges, 4),
255 (double[2]){-90, -80},
256 (struct yac_grid_cell[]){
257 utest_generate_cell_deg(
258 (double[4]){40,45,45,40},
259 (double[4]){-90,-90,-80,-80}, latlon_edges, 4)}, 1);
260
261 // a gaussian cell
262 utest_lat_clipping(
263 utest_generate_cell_deg(
264 (double[4]){40,45,45,40},
265 (double[4]){-90,-90,-85,-85}, latlon_edges, 4),
266 (double[2]){-90, -80},
267 (struct yac_grid_cell[]){
268 utest_generate_cell_deg(
269 (double[4]){40,45,45,40},
270 (double[4]){-90,-90,-85,-85}, latlon_edges, 4)}, 1);
271
272 // a gaussian cell
273 utest_lat_clipping(
274 utest_generate_cell_deg(
275 (double[4]){40,45,45,40},
276 (double[4]){-88,-88,-83,-83}, latlon_edges, 4),
277 (double[2]){-90, -80},
278 (struct yac_grid_cell[]){
279 utest_generate_cell_deg(
280 (double[4]){40,45,45,40},
281 (double[4]){-88,-88,-83,-83}, latlon_edges, 4)}, 1);
282
283 // a gaussian cell
284 utest_lat_clipping(
285 utest_generate_cell_deg(
286 (double[4]){40,45,45,40},
287 (double[4]){-88,-88,-83,-83}, latlon_edges, 4),
288 (double[2]){-90, -80},
289 (struct yac_grid_cell[]){
290 utest_generate_cell_deg(
291 (double[4]){40,45,45,40},
292 (double[4]){-88,-88,-83,-83}, latlon_edges, 4)}, 1);
293
294 // a gaussian cell
295 utest_lat_clipping(
296 utest_generate_cell_deg(
297 (double[4]){40,45,45,40},
298 (double[4]){-88,-88,-70,-70}, latlon_edges, 4),
299 (double[2]){-90, -80},
300 (struct yac_grid_cell[]){
301 utest_generate_cell_deg(
302 (double[4]){40,45,45,40},
303 (double[4]){-88,-88,-80,-80}, latlon_edges, 4)}, 1);
304
305 // a gaussian cell that touches the north pole and partially overlaps
306 // with the bounds
307 utest_lat_clipping(
308 utest_generate_cell_deg(
309 (double[4]){0,5,5,0},
310 (double[4]){90,90,85,85}, latlon_edges, 4),
311 (double[2]){89.9, 80},
312 (struct yac_grid_cell[]){
313 utest_generate_cell_deg(
314 (double[4]){0,5,5,0},
315 (double[4]){89.9,89.9,85,85}, latlon_edges, 4)}, 1);
316
317 // a triangle cell
318 utest_lat_clipping(
319 utest_generate_cell_deg(
320 (double[3]){10,20,15},
321 (double[3]){30,30,40}, gc_edges, 3),
322 (double[2]){35, 50},
323 (struct yac_grid_cell[]){
324 utest_generate_cell_deg(
325 (double[]){15,
326 utest_get_intersection(
328 (double[2][2]){{15, 40}, {10, 30}}, 35),
329 utest_get_intersection(
331 (double[2][2]){{15, 40}, {20, 30}}, 35)},
332 (double[]){40,35,35},
333 (enum yac_edge_type[]){
335
336 // a triangle cell
337 utest_lat_clipping(
338 utest_generate_cell_deg(
339 (double[3]){10,20,15},
340 (double[3]){30,30,40}, gc_edges, 3),
341 (double[2]){35, 25},
342 (struct yac_grid_cell[]){
343 utest_generate_cell_deg(
344 (double[]){20, 10,
345 utest_get_intersection(
347 (double[2][2]){{15, 40}, {10, 30}}, 35),
348 utest_get_intersection(
350 (double[2][2]){{15, 40}, {20, 30}}, 35)},
351 (double[]){30,30,35,35},
354
355 // a triangle cell
356 utest_lat_clipping(
357 utest_generate_cell_deg(
358 (double[]){10,20,15},
359 (double[]){30,30,40}, gc_edges, 3),
360 (double[2]){45, 25},
361 (struct yac_grid_cell[]){
362 utest_generate_cell_deg(
363 (double[]){10,20,15},
364 (double[]){30,30,40}, gc_edges, 3)}, 1);
365
366 // a triangle cell
367 utest_lat_clipping(
368 utest_generate_cell_deg(
369 (double[3]){10,20,15},
370 (double[3]){30,30,40}, gc_edges, 3),
371 (double[2]){32, 38},
372 (struct yac_grid_cell[]){
373 utest_generate_cell_deg(
374 (double[]){utest_get_intersection(
376 (double[2][2]){{15, 40}, {20, 30}}, 32),
377 utest_get_intersection(
379 (double[2][2]){{15, 40}, {20, 30}}, 38),
380 utest_get_intersection(
382 (double[2][2]){{15, 40}, {10, 30}}, 38),
383 utest_get_intersection(
385 (double[2][2]){{15, 40}, {10, 30}}, 32)},
386 (double[]){32,38,38,32},
389
390 // a triangle cell
391 utest_lat_clipping(
392 utest_generate_cell_deg(
393 (double[3]){-20,20,0},
394 (double[3]){80,80,85}, gc_edges, 3),
395 (double[2]){80.001, 89},
396 (struct yac_grid_cell[]){
397 utest_generate_cell_deg(
398 (double[]){0,
399 utest_get_intersection(
401 (double[2][2]){{0, 85}, {-20, 80}}, 80.001),
402 -fabs(utest_get_intersection(
404 (double[2][2]){{-20, 80}, {20, 80}}, 80.001)),
405 fabs(utest_get_intersection(
407 (double[2][2]){{-20, 80}, {20, 80}}, 80.001)),
408 utest_get_intersection(
410 (double[2][2]){{0, 85}, {20, 80}}, 80.001),},
411 (double[]){85,80.001,80.001,80.001,80.001},
414 YAC_GREAT_CIRCLE_EDGE}, 5)}, 1);
415
416 // a triangle cell
417 utest_lat_clipping(
418 utest_generate_cell_deg(
419 (double[]){10,20,15},
420 (double[]){82,82,88}, gc_edges, 3),
421 (double[2]){90, 80},
422 (struct yac_grid_cell[]){
423 utest_generate_cell_deg(
424 (double[]){10,20,15},
425 (double[]){82,82,88}, gc_edges, 3)}, 1);
426
427 // a triangle cell
428 utest_lat_clipping(
429 utest_generate_cell_deg(
430 (double[]){10,20,15},
431 (double[]){-82,-82,-88}, gc_edges, 3),
432 (double[2]){90, 80}, NULL, 0);
433
434 // a triangle cell
435 utest_lat_clipping(
436 utest_generate_cell_deg(
437 (double[]){10,20,15},
438 (double[]){-82,-82,-88}, gc_edges, 3),
439 (double[2]){-90, -80},
440 (struct yac_grid_cell[]){
441 utest_generate_cell_deg(
442 (double[]){10,20,15},
443 (double[]){-82,-82,-88}, gc_edges, 3)}, 1);
444
445 // a triangle cell
446 utest_lat_clipping(
447 utest_generate_cell_deg(
448 (double[]){10,20,15},
449 (double[]){82,82,88}, gc_edges, 3),
450 (double[2]){-90, -80}, NULL, 0);
451
452 // a triangle cell
453 utest_lat_clipping(
454 utest_generate_cell_deg(
455 (double[]){10,20,15},
456 (double[]){82,82,88}, gc_edges, 3),
457 (double[2]){90, 90}, NULL, 0);
458
459 // a triangle cell
460 utest_lat_clipping(
461 utest_generate_cell_deg(
462 (double[]){10,20,15},
463 (double[]){82,82,88}, gc_edges, 3),
464 (double[2]){-90, -90}, NULL, 0);
465
466 // a triangle cell covering the pole
467 utest_lat_clipping(
468 utest_generate_cell_deg(
469 (double[]){0,120,240},
470 (double[]){80,80,80}, gc_edges, 3),
471 (double[2]){90, 70},
472 (struct yac_grid_cell[]){
473 utest_generate_cell_deg(
474 (double[]){0,120,240},
475 (double[]){80,80,80}, gc_edges, 3)}, 1);
476
477 // a triangle cell covering the pole
478 utest_lat_clipping(
479 utest_generate_cell_deg(
480 (double[]){0,120,240},
481 (double[]){80,80,80}, gc_edges, 3),
482 (double[2]){60, 70}, NULL, 0);
483
484 // a triangle cell covering the pole
485 temp_lon[0] =
486 utest_get_intersection(YAC_GREAT_CIRCLE_EDGE, (double[2][2]){{0, 85}, {120, 70}}, 80);
487 temp_lon[1] =
488 utest_get_intersection(YAC_GREAT_CIRCLE_EDGE, (double[2][2]){{0, 85}, {240, 70}}, 80);
489 utest_lat_clipping(
490 utest_generate_cell_deg(
491 (double[]){0,120,240},
492 (double[]){85,70,70}, gc_edges, 3),
493 (double[2]){90, 80},
494 (struct yac_grid_cell[]){
495 utest_generate_cell_deg(
496 (double[]){0,temp_lon[0],temp_lon[1]},
497 (double[]){85,80,80},
498 (enum yac_edge_type[]){
500
501 // a triangle cell covering the pole
502 temp_lon[0] =
503 utest_get_intersection(YAC_GREAT_CIRCLE_EDGE, (double[2][2]){{0, 85}, {120, 70}}, 72);
504 temp_lon[1] =
505 utest_get_intersection(YAC_GREAT_CIRCLE_EDGE, (double[2][2]){{120, 70}, {240, 70}}, 72);
506 temp_lon[1] = (temp_lon[1] < 0)?(temp_lon[1] + 360):(temp_lon[1]);
507 temp_lon[1] = (temp_lon[1] < 180)?(temp_lon[1]):(360 - temp_lon[1]);
508 temp_lon[2] = 360 - temp_lon[1];
509 temp_lon[3] =
510 utest_get_intersection(YAC_GREAT_CIRCLE_EDGE, (double[2][2]){{0, 85}, {240, 70}}, 72);
511 utest_lat_clipping(
512 utest_generate_cell_deg(
513 (double[]){0,120,240},
514 (double[]){85,70,70}, gc_edges, 3),
515 (double[2]){90, 72},
516 (struct yac_grid_cell[]){
517 utest_generate_cell_deg(
518 (double[]){0,temp_lon[0],temp_lon[1],temp_lon[2],temp_lon[3]},
519 (double[]){85,72,72,72,72},
520 (enum yac_edge_type[]){
523
524 // a triangle cell covering the pole
525 temp_lon[0] =
526 utest_get_intersection(YAC_GREAT_CIRCLE_EDGE, (double[2][2]){{0, 85}, {120, 70}}, 80);
527 temp_lon[1] =
528 utest_get_intersection(YAC_GREAT_CIRCLE_EDGE, (double[2][2]){{0, 85}, {240, 70}}, 80);
529 utest_lat_clipping(
530 utest_generate_cell_deg(
531 (double[]){0,120,240},
532 (double[]){85,70,70}, gc_edges, 3),
533 (double[2]){80, 65},
534 (struct yac_grid_cell[]){
535 utest_generate_cell_deg(
536 (double[]){temp_lon[0],120,240,temp_lon[1]},
537 (double[]){80,70,70,80},
538 (enum yac_edge_type[]){
540 YAC_LAT_CIRCLE_EDGE}, 4)}, 1);
541
542 // a triangle cell covering the pole
543 temp_lon[0] =
544 utest_get_intersection(YAC_GREAT_CIRCLE_EDGE, (double[2][2]){{0, 85}, {120, 70}}, 84);
545 temp_lon[1] =
546 utest_get_intersection(YAC_GREAT_CIRCLE_EDGE, (double[2][2]){{0, 85}, {120, 70}}, 80);
547 temp_lon[2] =
548 utest_get_intersection(YAC_GREAT_CIRCLE_EDGE, (double[2][2]){{0, 85}, {240, 70}}, 80);
549 temp_lon[3] =
550 utest_get_intersection(YAC_GREAT_CIRCLE_EDGE, (double[2][2]){{0, 85}, {240, 70}}, 84);
551 utest_lat_clipping(
552 utest_generate_cell_deg(
553 (double[]){0,120,240},
554 (double[]){85,70,70}, gc_edges, 3),
555 (double[2]){80, 84},
556 (struct yac_grid_cell[]){
557 utest_generate_cell_deg(
558 (double[]){temp_lon[0],temp_lon[1],temp_lon[2],temp_lon[3]},
559 (double[]){84,80,80,84},
560 (enum yac_edge_type[]){
562 YAC_LAT_CIRCLE_EDGE}, 4)}, 1);
563
564 // a triangle cell covering the pole
565 temp_lon[0] =
566 utest_get_intersection(YAC_GREAT_CIRCLE_EDGE, (double[2][2]){{0, 85}, {120, 70}}, 80);
567 temp_lon[1] =
568 utest_get_intersection(YAC_GREAT_CIRCLE_EDGE, (double[2][2]){{0, 85}, {120, 70}}, 72);
569 temp_lon[2] =
570 utest_get_intersection(YAC_GREAT_CIRCLE_EDGE, (double[2][2]){{240, 70}, {120, 70}}, 72);
571 temp_lon[2] = (temp_lon[2] < 0)?(temp_lon[2] + 360):(temp_lon[2]);
572 temp_lon[2] = (temp_lon[2] < 180)?(temp_lon[2]):(360 - temp_lon[2]);
573 temp_lon[3] = 360 - temp_lon[2];
574 temp_lon[4] =
575 utest_get_intersection(YAC_GREAT_CIRCLE_EDGE, (double[2][2]){{0, 85}, {240, 70}}, 72);
576 temp_lon[5] =
577 utest_get_intersection(YAC_GREAT_CIRCLE_EDGE, (double[2][2]){{0, 85}, {240, 70}}, 80);
578 utest_lat_clipping(
579 utest_generate_cell_deg(
580 (double[]){0,120,240},
581 (double[]){85,70,70}, gc_edges, 3),
582 (double[2]){80, 72},
583 (struct yac_grid_cell[]){
584 utest_generate_cell_deg(
585 (double[]){temp_lon[0],temp_lon[1],temp_lon[2],
586 temp_lon[3],temp_lon[4],temp_lon[5]},
587 (double[]){80,72,72,72,72,80},
588 (enum yac_edge_type[]){
591
592 // a triangle cell touching the pole
593 temp_lon[0] =
594 utest_get_intersection(YAC_GREAT_CIRCLE_EDGE, (double[2][2]){{0, 90}, {120, 80}}, 85);
595 temp_lon[1] =
596 utest_get_intersection(YAC_GREAT_CIRCLE_EDGE, (double[2][2]){{0, 90}, {240, 80}}, 85);
597 utest_lat_clipping(
598 utest_generate_cell_deg(
599 (double[]){0,120,240},
600 (double[]){90,80,80}, gc_edges, 3),
601 (double[2]){90, 85},
602 (struct yac_grid_cell[]){
603 utest_generate_cell_deg(
604 (double[]){0,temp_lon[0],temp_lon[1]},
605 (double[]){90,85,85},
606 (enum yac_edge_type[]){
608
609 // a triangle cell touching the pole
610 temp_lon[0] =
611 utest_get_intersection(YAC_GREAT_CIRCLE_EDGE, (double[2][2]){{0, 0}, {10, 5}}, 2.5);
612 temp_lon[1] =
613 utest_get_intersection(YAC_GREAT_CIRCLE_EDGE, (double[2][2]){{10, -5}, {10, 5}}, 2.5);
614 temp_lon[2] =
615 utest_get_intersection(YAC_GREAT_CIRCLE_EDGE, (double[2][2]){{10, -5}, {10, 5}}, -2.5);
616 temp_lon[3] =
617 utest_get_intersection(YAC_GREAT_CIRCLE_EDGE, (double[2][2]){{10, -5}, {0, 0}}, -2.5);
618 utest_lat_clipping(
619 utest_generate_cell_deg(
620 (double[]){0,10,10},
621 (double[]){0,5,-5}, gc_edges, 3),
622 (double[2]){2.5, -2.5},
623 (struct yac_grid_cell[]){
624 utest_generate_cell_deg(
625 (double[]){0,temp_lon[0],temp_lon[1],temp_lon[2],temp_lon[3]},
626 (double[]){0,2.5,2.5,-2.5,-2.5},
627 (enum yac_edge_type[]){
630
631 // A lon-lat cell whose upper lat edge collapsed into a single point at the
632 // pole. Such a cell is stored with three corners (the pole being the first
633 // one here), but is still classified as a lon-lat cell.
634
635 // the cell is completely within the lat bound
636 utest_lat_clipping(
637 utest_generate_cell_deg(
638 (double[]){0,0,90},
639 (double[]){90,70,70}, lonlat_pole_edges, 3),
640 (double[2]){60, 90},
641 (struct yac_grid_cell[]){
642 utest_generate_cell_deg(
643 (double[]){0,0,90},
644 (double[]){90,70,70}, lonlat_pole_edges, 3)}, 1);
645
646 // the cell is outside of the lat bound
647 utest_lat_clipping(
648 utest_generate_cell_deg(
649 (double[]){0,0,90},
650 (double[]){90,70,70}, lonlat_pole_edges, 3),
651 (double[2]){30, 60}, NULL, 0);
652
653 // only the lower lat bound overlaps with the cell
654 // (the pole remains part of the overlap)
655 utest_lat_clipping(
656 utest_generate_cell_deg(
657 (double[]){0,0,90},
658 (double[]){90,70,70}, lonlat_pole_edges, 3),
659 (double[2]){75, 90},
660 (struct yac_grid_cell[]){
661 utest_generate_cell_deg(
662 (double[]){0,0,90},
663 (double[]){90,75,75}, lonlat_pole_edges, 3)}, 1);
664
665 // both lat bounds overlap with the cell
666 // (the pole is clipped off, which turns the triangle into a lon-lat cell
667 // with four corners)
668 utest_lat_clipping(
669 utest_generate_cell_deg(
670 (double[]){0,0,90},
671 (double[]){90,70,70}, lonlat_pole_edges, 3),
672 (double[2]){75, 85},
673 (struct yac_grid_cell[]){
674 utest_generate_cell_deg(
675 (double[]){0,90,90,0},
676 (double[]){75,75,85,85}, latlon_edges, 4)}, 1);
677
678 // A cell covering the pole, whose boundary consists of three edges on the
679 // same circle of latitude (covering 170, 170, and 20 degree of longitude).
680 // For two consecutive of these edges the longitude difference between their
681 // first and their last vertex is only 20 degree, even though the two edges
682 // together cover 340 degree.
683 utest_lat_clipping(
684 utest_generate_cell_deg(
685 (double[]){0,170,340},
686 (double[]){45,45,45}, lat3_edges, 3),
687 (double[2]){0, 90},
688 (struct yac_grid_cell[]){
689 utest_generate_cell_deg(
690 (double[]){0,170,340},
691 (double[]){45,45,45}, lat3_edges, 3)}, 1);
692
693 // empty great circle cell
694 utest_lat_clipping(
695 utest_generate_cell_deg(
696 (double[]){0,0,0},
697 (double[]){-5,0,5}, gc_edges, 3),
698 (double[2]){2.5, -2.5}, NULL, 0);
699
700 // cells with too few corners
701 utest_lat_clipping_degenerate_cells();
702
703 return TEST_EXIT_CODE;
704}
705
712static void utest_lat_clipping_degenerate_cells(void) {
713
714 enum yac_edge_type latlon_edges[4] = {
717 double rad_lat_bounds[2] = {-10.0 * YAC_RAD, 10.0 * YAC_RAD};
718
719 struct yac_grid_cell overlap_buffer[2];
720 for (int i = 0; i < 2; ++i) yac_init_grid_cell(overlap_buffer + i);
721
722 // fill the overlap buffer with non-empty overlaps
723 struct yac_grid_cell cells[2] = {
724 utest_generate_cell_deg(
725 (double[4]){-5,5,5,-5}, (double[4]){-5,-5,5,5}, latlon_edges, 4),
726 utest_generate_cell_deg(
727 (double[4]){5,15,15,5}, (double[4]){-5,-5,5,5}, latlon_edges, 4)};
728 yac_cell_lat_clipping(2, cells, rad_lat_bounds, overlap_buffer);
729 for (int i = 0; i < 2; ++i) {
730 if (overlap_buffer[i].num_corners == 0)
731 PUT_ERR("ERROR: test setup failed (expected a non-empty overlap)\n");
732 yac_free_grid_cell(cells + i);
733 }
734
735 // clip degenerate cells using the same (non-empty) overlap buffer
736 double dummy_coordinates_xyz[1][3];
737 LLtoXYZ_deg(0.0, 0.0, dummy_coordinates_xyz[0]);
738 enum yac_edge_type dummy_edge_type[1] = {YAC_GREAT_CIRCLE_EDGE};
739 struct yac_grid_cell degenerate_cells[2];
740 for (int i = 0; i < 2; ++i)
741 degenerate_cells[i] =
742 (struct yac_grid_cell){.coordinates_xyz = dummy_coordinates_xyz,
743 .edge_type = dummy_edge_type,
744 .num_corners = (size_t)i,
745 .array_size = 1};
746 yac_cell_lat_clipping(2, degenerate_cells, rad_lat_bounds, overlap_buffer);
747 for (int i = 0; i < 2; ++i)
748 if (overlap_buffer[i].num_corners != 0)
749 PUT_ERR("ERROR: cell with too few corners does not result in an "
750 "empty overlap\n");
751
752 for (int i = 0; i < 2; ++i) yac_free_grid_cell(overlap_buffer + i);
753}
754
755static int utest_compare_cells(struct yac_grid_cell a, struct yac_grid_cell b) {
756
757 // Trigonometric functions can be very inaccurate depending on the compiler
758 // and the optimsation level. Therefore, we use angle_tol instead of
759 // yac_angle_tol in this routine.
760 double const angle_tol = 1e-6;
761
762 if ((yac_grid_cell_area(a) < angle_tol * angle_tol) &&
763 (yac_grid_cell_area(b) < angle_tol * angle_tol)) return 0;
764
765 if (a.num_corners != b.num_corners) return 1;
766
767 if (a.num_corners == 0) return 0;
768
769 for (int order = -1; order <= 1; order += 2) {
770 for (int start = 0; start < (int)(a.num_corners); ++start) {
771
772 int differences = 0;
773
774 for (int i = 0; i < (int)(a.num_corners); ++i) {
775
776 int j =
777 ((int)(a.num_corners) + start + order * i) % (int)(a.num_corners);
778
780 a.coordinates_xyz[i], b.coordinates_xyz[j]) > angle_tol)
781 ++differences;
782
783 else if ((a.edge_type[i] == YAC_LAT_CIRCLE_EDGE) !=
784 (b.edge_type[
785 (((int)(a.num_corners))+j-(order<0))%
786 ((int)(a.num_corners))] == YAC_LAT_CIRCLE_EDGE))
787 ++differences;
788 }
789
790 if (!differences) return 0;
791 }
792 }
793
794 return 1;
795}
796
797static void utest_lat_clipping(struct yac_grid_cell cell,
798 double deg_lat_bounds[2],
799 struct yac_grid_cell * ref_cells,
800 unsigned num_ref_cells) {
801
802 double const area_tol = 1e-8 * yac_grid_cell_area(cell);
803
804 double rad_lat_bounds[2] =
805 {deg_lat_bounds[0] * YAC_RAD, deg_lat_bounds[1] * YAC_RAD};
806
807 // the arrays are initialised in order to get a reproducible behaviour in
808 // case the clipping accesses more corners than the cell actually has
809 double mem_dummy_[128][3] = {{0.0}};
810 enum yac_edge_type edge_dummy[128] = {YAC_GREAT_CIRCLE_EDGE};
811 struct yac_grid_cell overlap_cell,
812 test_cell =
813 (struct yac_grid_cell){.coordinates_xyz = mem_dummy_,
814 .edge_type = edge_dummy,
815 .num_corners = cell.num_corners};
816
817 yac_init_grid_cell(&overlap_cell);
818
819 for (int pole = 0; pole < 2; ++pole) {
820 for (int order = -1; order <= 1; order += 2) {
821 for (int start = 0; start < (int)(cell.num_corners); ++start) {
822 for (int i = 0; i < ((int)(cell.num_corners)); ++i) {
823 int j = (((int)(cell.num_corners))+start+i*order)%
824 ((int)(cell.num_corners));
825 test_cell.coordinates_xyz[i][0] = cell.coordinates_xyz[j][0];
826 test_cell.coordinates_xyz[i][1] = cell.coordinates_xyz[j][1];
827 test_cell.coordinates_xyz[i][2] = cell.coordinates_xyz[j][2];
828 j = (((int)(cell.num_corners)) + j - (order < 0))%
829 ((int)(cell.num_corners));
830 test_cell.edge_type[i] = cell.edge_type[j];
831 }
832
833 for (int bound_tol_a = -1; bound_tol_a <= 1; ++bound_tol_a) {
834 for (int bound_tol_b = -1; bound_tol_b <= 1; ++bound_tol_b) {
835 for (int bound_order = 0; bound_order <= 1; ++bound_order) {
836 double test_rad_lat_bounds[2] = {
837 MIN(M_PI_2,
838 MAX(-M_PI_2,
839 rad_lat_bounds[bound_order] +
840 (double)bound_tol_a * yac_angle_low_tol)),
841 MIN(M_PI_2,
842 MAX(-M_PI_2,
843 rad_lat_bounds[bound_order^1] +
844 (double)bound_tol_b * yac_angle_low_tol))};
846 1, &test_cell,test_rad_lat_bounds, &overlap_cell);
847 if (num_ref_cells == 0) {
848 if ((overlap_cell.num_corners != 0) &&
849 (yac_grid_cell_area(overlap_cell) > area_tol))
850 PUT_ERR("ERROR: wrong clipping cell\n");
851 } else {
852 int match = 0;
853 for (int i = 0; i < (int)num_ref_cells; ++i)
854 match |= !utest_compare_cells(overlap_cell, ref_cells[i]);
855 if (!match)
856 PUT_ERR("ERROR: wrong clipping cell\n");
857 }
858 }
859 }
860 }
861 }
862 }
863
864 // switch to the other pole
865 for (int i = 0; i < (int)(cell.num_corners); ++i)
866 cell.coordinates_xyz[i][2] *= -1.0;
867 rad_lat_bounds[0] *= -1.0, rad_lat_bounds[1] *= -1.0;
868 for (unsigned i = 0; i < num_ref_cells; ++i)
869 for (int j = 0; j < (int)(ref_cells[i].num_corners); ++j)
870 ref_cells[i].coordinates_xyz[j][2] *= -1.0;
871 }
872
873 yac_free_grid_cell(&cell);
874 for (unsigned i = 0; i < num_ref_cells; ++i)
875 yac_free_grid_cell(&ref_cells[i]);
876 yac_free_grid_cell(&overlap_cell);
877}
double yac_grid_cell_area(struct yac_grid_cell cell)
Area calculation of a spherical cell.
Definition area.c:276
Structs and interfaces for area calculations.
void yac_cell_lat_clipping(size_t N, struct yac_grid_cell *cells, double lat_bounds[2], struct yac_grid_cell *overlap_buffer)
cell clipping to get the cells describing the intersections
Definition clipping.c:1386
#define YAC_RAD
static void LLtoXYZ_deg(double lon, double lat, double p_out[])
Definition geometry.h:278
#define yac_angle_low_tol
Definition geometry.h:29
static double get_vector_angle(double const a[3], double const b[3])
Definition geometry.h:472
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
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
static enum yac_edge_type gc_edges[]
static enum yac_edge_type latlon_edges[4]
#define TEST_EXIT_CODE
Definition tests.h:15
#define PUT_ERR(string)
Definition tests.h:10
#define MIN(a, b)
Definition toy_common.h:29
static void XYZtoLL(double const p_in[], double *lon, double *lat)
Definition toy_common.h:23
#define MAX(a, b)