@@ -470,6 +470,238 @@ def test_get_zonal_faces_weight_at_constLat_equator():
470470
471471
472472
473+ # A error will be raise if we don't set is_latlonface=True since the face_2 will be concave if
474+ # It's edges are all GCA
475+ with pytest .raises (ValueError ):
476+ _get_zonal_faces_weight_at_constLat (np .array ([
477+ face_0_edge_nodes , face_1_edge_nodes , face_2_edge_nodes
478+ ]), np .deg2rad (20 ), latlon_bounds )
479+
480+
481+ def test_get_zonal_faces_weight_at_constLat_regular ():
482+ face_0 = [[1.7 * np .pi , 0.25 * np .pi ], [1.7 * np .pi , 0.0 ],
483+ [0.3 * np .pi , 0.0 ], [0.3 * np .pi , 0.25 * np .pi ]]
484+ face_1 = [[0.4 * np .pi , 0.3 * np .pi ], [0.4 * np .pi , 0.0 ],
485+ [0.5 * np .pi , 0.0 ], [0.5 * np .pi , 0.3 * np .pi ]]
486+ face_2 = [[0.5 * np .pi , 0.25 * np .pi ], [0.5 * np .pi , 0.0 ], [np .pi , 0.0 ],
487+ [np .pi , 0.25 * np .pi ]]
488+ face_3 = [[1.2 * np .pi , 0.25 * np .pi ], [1.2 * np .pi , 0.0 ],
489+ [1.6 * np .pi , - 0.01 * np .pi ], [1.6 * np .pi , 0.25 * np .pi ]]
490+
491+ # Convert the face vertices to xyz coordinates
492+ face_0 = [_lonlat_rad_to_xyz (* v ) for v in face_0 ]
493+ face_1 = [_lonlat_rad_to_xyz (* v ) for v in face_1 ]
494+ face_2 = [_lonlat_rad_to_xyz (* v ) for v in face_2 ]
495+ face_3 = [_lonlat_rad_to_xyz (* v ) for v in face_3 ]
496+
497+ face_0_edge_nodes = np .array ([[face_0 [0 ], face_0 [1 ]],
498+ [face_0 [1 ], face_0 [2 ]],
499+ [face_0 [2 ], face_0 [3 ]],
500+ [face_0 [3 ], face_0 [0 ]]])
501+ face_1_edge_nodes = np .array ([[face_1 [0 ], face_1 [1 ]],
502+ [face_1 [1 ], face_1 [2 ]],
503+ [face_1 [2 ], face_1 [3 ]],
504+ [face_1 [3 ], face_1 [0 ]]])
505+ face_2_edge_nodes = np .array ([[face_2 [0 ], face_2 [1 ]],
506+ [face_2 [1 ], face_2 [2 ]],
507+ [face_2 [2 ], face_2 [3 ]],
508+ [face_2 [3 ], face_2 [0 ]]])
509+ face_3_edge_nodes = np .array ([[face_3 [0 ], face_3 [1 ]],
510+ [face_3 [1 ], face_3 [2 ]],
511+ [face_3 [2 ], face_3 [3 ]],
512+ [face_3 [3 ], face_3 [0 ]]])
513+
514+ face_0_latlon_bound = np .array ([[0.0 , 0.25 * np .pi ],
515+ [1.7 * np .pi , 0.3 * np .pi ]])
516+ face_1_latlon_bound = np .array ([[0 , 0.3 * np .pi ],
517+ [0.4 * np .pi , 0.5 * np .pi ]])
518+ face_2_latlon_bound = np .array ([[0.0 , 0.25 * np .pi ],
519+ [0.5 * np .pi , np .pi ]])
520+ face_3_latlon_bound = np .array ([[- 0.01 * np .pi , 0.25 * np .pi ],
521+ [1.2 * np .pi , 1.6 * np .pi ]])
522+
523+ latlon_bounds = np .array ([
524+ face_0_latlon_bound , face_1_latlon_bound , face_2_latlon_bound ,
525+ face_3_latlon_bound
526+ ])
527+
528+ expected_weight_df = pd .DataFrame ({
529+ 'face_index' : [0 , 1 , 2 , 3 ],
530+ 'weight' : [0.375 , 0.0625 , 0.3125 , 0.25 ]
531+ })
532+
533+ # Assert the results is the same to the 3 decimal places
534+ weight_df = _get_zonal_faces_weight_at_constLat (np .array ([
535+ face_0_edge_nodes , face_1_edge_nodes , face_2_edge_nodes ,
536+ face_3_edge_nodes
537+ ]), np .sin (0.1 * np .pi ), latlon_bounds )
538+
539+ nt .assert_array_almost_equal (weight_df , expected_weight_df , decimal = 3 )
540+
541+ def test_get_zonal_faces_weight_at_constLat_on_pole_one_face ():
542+ #The face is touching the pole, so the weight should be 1.0 since there's only 1 face
543+ face_edges_cart = np .array ([[
544+ [[- 5.22644277e-02 , - 5.22644277e-02 , - 9.97264689e-01 ],
545+ [- 5.23359562e-02 , - 6.40930613e-18 , - 9.98629535e-01 ]],
546+
547+ [[- 5.23359562e-02 , - 6.40930613e-18 , - 9.98629535e-01 ],
548+ [6.12323400e-17 , 0.00000000e+00 , - 1.00000000e+00 ]],
549+
550+ [[6.12323400e-17 , 0.00000000e+00 , - 1.00000000e+00 ],
551+ [3.20465306e-18 , - 5.23359562e-02 , - 9.98629535e-01 ]],
552+
553+ [[3.20465306e-18 , - 5.23359562e-02 , - 9.98629535e-01 ],
554+ [- 5.22644277e-02 , - 5.22644277e-02 , - 9.97264689e-01 ]]
555+ ]])
556+
557+ # Corrected face_bounds
558+ face_bounds = np .array ([
559+ [- 1.57079633 , - 1.4968158 ],
560+ [3.14159265 , 0. ]
561+ ])
562+ constLat_cart = - 1
563+
564+ weight_df = _get_zonal_faces_weight_at_constLat (face_edges_cart , constLat_cart , face_bounds )
565+ # Define the expected DataFrame
566+ expected_weight_df = pd .DataFrame ({"face_index" : [0 ], "weight" : [1.0 ]})
567+
568+ # Assert that the resulting should have weight is 1.0
569+ pd .testing .assert_frame_equal (weight_df , expected_weight_df )
570+
571+
572+ def test_get_zonal_faces_weight_at_constLat_on_pole_faces ():
573+ #there will be 4 faces touching the pole, so the weight should be 0.25 for each face
574+ face_edges_cart = np .array ([
575+ [
576+ [[5.22644277e-02 , - 5.22644277e-02 , 9.97264689e-01 ], [5.23359562e-02 , 0.00000000e+00 , 9.98629535e-01 ]],
577+ [[5.23359562e-02 , 0.00000000e+00 , 9.98629535e-01 ], [6.12323400e-17 , 0.00000000e+00 , 1.00000000e+00 ]],
578+ [[6.12323400e-17 , 0.00000000e+00 , 1.00000000e+00 ], [3.20465306e-18 , - 5.23359562e-02 , 9.98629535e-01 ]],
579+ [[3.20465306e-18 , - 5.23359562e-02 , 9.98629535e-01 ], [5.22644277e-02 , - 5.22644277e-02 , 9.97264689e-01 ]]
580+ ],
581+ [
582+ [[5.23359562e-02 , 0.00000000e+00 , 9.98629535e-01 ], [5.22644277e-02 , 5.22644277e-02 , 9.97264689e-01 ]],
583+ [[5.22644277e-02 , 5.22644277e-02 , 9.97264689e-01 ], [3.20465306e-18 , 5.23359562e-02 , 9.98629535e-01 ]],
584+ [[3.20465306e-18 , 5.23359562e-02 , 9.98629535e-01 ], [6.12323400e-17 , 0.00000000e+00 , 1.00000000e+00 ]],
585+ [[6.12323400e-17 , 0.00000000e+00 , 1.00000000e+00 ], [5.23359562e-02 , 0.00000000e+00 , 9.98629535e-01 ]]
586+ ],
587+ [
588+ [[3.20465306e-18 , - 5.23359562e-02 , 9.98629535e-01 ], [6.12323400e-17 , 0.00000000e+00 , 1.00000000e+00 ]],
589+ [[6.12323400e-17 , 0.00000000e+00 , 1.00000000e+00 ], [- 5.23359562e-02 , - 6.40930613e-18 , 9.98629535e-01 ]],
590+ [[- 5.23359562e-02 , - 6.40930613e-18 , 9.98629535e-01 ],
591+ [- 5.22644277e-02 , - 5.22644277e-02 , 9.97264689e-01 ]],
592+ [[- 5.22644277e-02 , - 5.22644277e-02 , 9.97264689e-01 ], [3.20465306e-18 , - 5.23359562e-02 , 9.98629535e-01 ]]
593+ ],
594+ [
595+ [[6.12323400e-17 , 0.00000000e+00 , 1.00000000e+00 ], [3.20465306e-18 , 5.23359562e-02 , 9.98629535e-01 ]],
596+ [[3.20465306e-18 , 5.23359562e-02 , 9.98629535e-01 ], [- 5.22644277e-02 , 5.22644277e-02 , 9.97264689e-01 ]],
597+ [[- 5.22644277e-02 , 5.22644277e-02 , 9.97264689e-01 ], [- 5.23359562e-02 , - 6.40930613e-18 , 9.98629535e-01 ]],
598+ [[- 5.23359562e-02 , - 6.40930613e-18 , 9.98629535e-01 ], [6.12323400e-17 , 0.00000000e+00 , 1.00000000e+00 ]]
599+ ]
600+ ])
601+
602+ face_bounds = np .array ([
603+ [[1.4968158 , 1.57079633 ], [4.71238898 , 0.0 ]],
604+ [[1.4968158 , 1.57079633 ], [0.0 , 1.57079633 ]],
605+ [[1.4968158 , 1.57079633 ], [3.14159265 , 0.0 ]],
606+ [[1.4968158 , 1.57079633 ], [0.0 , 3.14159265 ]]
607+ ])
608+
609+ constLat_cart = 1.0
610+
611+ weight_df = _get_zonal_faces_weight_at_constLat (face_edges_cart , constLat_cart , face_bounds )
612+ # Define the expected DataFrame
613+ expected_weight_df = pd .DataFrame ({
614+ 'face_index' : [0 , 1 , 2 , 3 ],
615+ 'weight' : [0.25 , 0.25 , 0.25 , 0.25 ]
616+ })
617+
618+ # Assert that the DataFrame matches the expected DataFrame
619+ pd .testing .assert_frame_equal (weight_df , expected_weight_df )
620+
621+
622+ def test_get_zonal_face_interval_pole ():
623+ #The face is touching the pole
624+ face_edges_cart = np .array ([
625+ [[- 5.22644277e-02 , - 5.22644277e-02 , - 9.97264689e-01 ],
626+ [- 5.23359562e-02 , - 6.40930613e-18 , - 9.98629535e-01 ]],
627+
628+ [[- 5.23359562e-02 , - 6.40930613e-18 , - 9.98629535e-01 ],
629+ [6.12323400e-17 , 0.00000000e+00 , - 1.00000000e+00 ]],
630+
631+ [[6.12323400e-17 , 0.00000000e+00 , - 1.00000000e+00 ],
632+ [3.20465306e-18 , - 5.23359562e-02 , - 9.98629535e-01 ]],
633+
634+ [[3.20465306e-18 , - 5.23359562e-02 , - 9.98629535e-01 ],
635+ [- 5.22644277e-02 , - 5.22644277e-02 , - 9.97264689e-01 ]]
636+ ])
637+
638+ # Corrected face_bounds
639+ face_bounds = np .array ([
640+ [- 1.57079633 , - 1.4968158 ],
641+ [3.14159265 , 0. ]
642+ ])
643+ constLat_cart = - 0.9986295347545738
644+
645+ weight_df = _get_zonal_face_interval (face_edges_cart , constLat_cart , face_bounds )
646+ # No Nan values should be present in the weight_df
647+ assert (not weight_df .isnull ().values .any ())
648+
649+
650+ def test_get_zonal_faces_weight_at_constLat_latlonface ():
651+ face_0 = [[np .deg2rad (350 ), np .deg2rad (40 )], [np .deg2rad (350 ), np .deg2rad (20 )],
652+ [np .deg2rad (10 ), np .deg2rad (20 )], [np .deg2rad (10 ), np .deg2rad (40 )]]
653+ face_1 = [[np .deg2rad (5 ), np .deg2rad (20 )], [np .deg2rad (5 ), np .deg2rad (10 )],
654+ [np .deg2rad (25 ), np .deg2rad (10 )], [np .deg2rad (25 ), np .deg2rad (20 )]]
655+ face_2 = [[np .deg2rad (30 ), np .deg2rad (40 )], [np .deg2rad (30 ), np .deg2rad (20 )],
656+ [np .deg2rad (40 ), np .deg2rad (20 )], [np .deg2rad (40 ), np .deg2rad (40 )]]
657+
658+ # Convert the face vertices to xyz coordinates
659+ face_0 = [_lonlat_rad_to_xyz (* v ) for v in face_0 ]
660+ face_1 = [_lonlat_rad_to_xyz (* v ) for v in face_1 ]
661+ face_2 = [_lonlat_rad_to_xyz (* v ) for v in face_2 ]
662+
663+
664+ face_0_edge_nodes = np .array ([[face_0 [0 ], face_0 [1 ]],
665+ [face_0 [1 ], face_0 [2 ]],
666+ [face_0 [2 ], face_0 [3 ]],
667+ [face_0 [3 ], face_0 [0 ]]])
668+ face_1_edge_nodes = np .array ([[face_1 [0 ], face_1 [1 ]],
669+ [face_1 [1 ], face_1 [2 ]],
670+ [face_1 [2 ], face_1 [3 ]],
671+ [face_1 [3 ], face_1 [0 ]]])
672+ face_2_edge_nodes = np .array ([[face_2 [0 ], face_2 [1 ]],
673+ [face_2 [1 ], face_2 [2 ]],
674+ [face_2 [2 ], face_2 [3 ]],
675+ [face_2 [3 ], face_2 [0 ]]])
676+
677+ face_0_latlon_bound = np .array ([[np .deg2rad (20 ), np .deg2rad (40 )],
678+ [np .deg2rad (350 ), np .deg2rad (10 )]])
679+ face_1_latlon_bound = np .array ([[np .deg2rad (10 ), np .deg2rad (20 )],
680+ [np .deg2rad (5 ), np .deg2rad (25 )]])
681+ face_2_latlon_bound = np .array ([[np .deg2rad (20 ), np .deg2rad (40 )],
682+ [np .deg2rad (30 ), np .deg2rad (40 )]])
683+
684+
685+ latlon_bounds = np .array ([
686+ face_0_latlon_bound , face_1_latlon_bound , face_2_latlon_bound
687+ ])
688+
689+ sum = 17.5 + 17.5 + 10
690+ expected_weight_df = pd .DataFrame ({
691+ 'face_index' : [0 , 1 , 2 ],
692+ 'weight' : [17.5 / sum , 17.5 / sum , 10 / sum ]
693+ })
694+
695+ # Assert the results is the same to the 3 decimal places
696+ weight_df = _get_zonal_faces_weight_at_constLat (np .array ([
697+ face_0_edge_nodes , face_1_edge_nodes , face_2_edge_nodes
698+ ]), np .sin (np .deg2rad (20 )), latlon_bounds , is_latlonface = True )
699+
700+
701+ nt .assert_array_almost_equal (weight_df , expected_weight_df , decimal = 3 )
702+
703+
704+
473705 # A error will be raise if we don't set is_latlonface=True since the face_2 will be concave if
474706 # It's edges are all GCA
475707 with pytest .raises (ValueError ):
0 commit comments