cloudnetpy 1.49.9__py3-none-any.whl → 1.87.3__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (116) hide show
  1. cloudnetpy/categorize/__init__.py +1 -2
  2. cloudnetpy/categorize/atmos_utils.py +297 -67
  3. cloudnetpy/categorize/attenuation.py +31 -0
  4. cloudnetpy/categorize/attenuations/__init__.py +37 -0
  5. cloudnetpy/categorize/attenuations/gas_attenuation.py +30 -0
  6. cloudnetpy/categorize/attenuations/liquid_attenuation.py +84 -0
  7. cloudnetpy/categorize/attenuations/melting_attenuation.py +78 -0
  8. cloudnetpy/categorize/attenuations/rain_attenuation.py +84 -0
  9. cloudnetpy/categorize/categorize.py +332 -156
  10. cloudnetpy/categorize/classify.py +127 -125
  11. cloudnetpy/categorize/containers.py +107 -76
  12. cloudnetpy/categorize/disdrometer.py +40 -0
  13. cloudnetpy/categorize/droplet.py +23 -21
  14. cloudnetpy/categorize/falling.py +53 -24
  15. cloudnetpy/categorize/freezing.py +25 -12
  16. cloudnetpy/categorize/insects.py +35 -23
  17. cloudnetpy/categorize/itu.py +243 -0
  18. cloudnetpy/categorize/lidar.py +36 -41
  19. cloudnetpy/categorize/melting.py +34 -26
  20. cloudnetpy/categorize/model.py +84 -37
  21. cloudnetpy/categorize/mwr.py +18 -14
  22. cloudnetpy/categorize/radar.py +215 -102
  23. cloudnetpy/cli.py +578 -0
  24. cloudnetpy/cloudnetarray.py +43 -89
  25. cloudnetpy/concat_lib.py +218 -78
  26. cloudnetpy/constants.py +28 -10
  27. cloudnetpy/datasource.py +61 -86
  28. cloudnetpy/exceptions.py +49 -20
  29. cloudnetpy/instruments/__init__.py +5 -0
  30. cloudnetpy/instruments/basta.py +29 -12
  31. cloudnetpy/instruments/bowtie.py +135 -0
  32. cloudnetpy/instruments/ceilo.py +138 -115
  33. cloudnetpy/instruments/ceilometer.py +164 -80
  34. cloudnetpy/instruments/cl61d.py +21 -5
  35. cloudnetpy/instruments/cloudnet_instrument.py +74 -36
  36. cloudnetpy/instruments/copernicus.py +108 -30
  37. cloudnetpy/instruments/da10.py +54 -0
  38. cloudnetpy/instruments/disdrometer/common.py +126 -223
  39. cloudnetpy/instruments/disdrometer/parsivel.py +453 -94
  40. cloudnetpy/instruments/disdrometer/thies.py +254 -87
  41. cloudnetpy/instruments/fd12p.py +201 -0
  42. cloudnetpy/instruments/galileo.py +65 -23
  43. cloudnetpy/instruments/hatpro.py +123 -49
  44. cloudnetpy/instruments/instruments.py +113 -1
  45. cloudnetpy/instruments/lufft.py +39 -17
  46. cloudnetpy/instruments/mira.py +268 -61
  47. cloudnetpy/instruments/mrr.py +187 -0
  48. cloudnetpy/instruments/nc_lidar.py +19 -8
  49. cloudnetpy/instruments/nc_radar.py +109 -55
  50. cloudnetpy/instruments/pollyxt.py +135 -51
  51. cloudnetpy/instruments/radiometrics.py +313 -59
  52. cloudnetpy/instruments/rain_e_h3.py +171 -0
  53. cloudnetpy/instruments/rpg.py +321 -189
  54. cloudnetpy/instruments/rpg_reader.py +74 -40
  55. cloudnetpy/instruments/toa5.py +49 -0
  56. cloudnetpy/instruments/vaisala.py +95 -343
  57. cloudnetpy/instruments/weather_station.py +774 -105
  58. cloudnetpy/metadata.py +90 -19
  59. cloudnetpy/model_evaluation/file_handler.py +55 -52
  60. cloudnetpy/model_evaluation/metadata.py +46 -20
  61. cloudnetpy/model_evaluation/model_metadata.py +1 -1
  62. cloudnetpy/model_evaluation/plotting/plot_tools.py +32 -37
  63. cloudnetpy/model_evaluation/plotting/plotting.py +327 -117
  64. cloudnetpy/model_evaluation/products/advance_methods.py +92 -83
  65. cloudnetpy/model_evaluation/products/grid_methods.py +88 -63
  66. cloudnetpy/model_evaluation/products/model_products.py +43 -35
  67. cloudnetpy/model_evaluation/products/observation_products.py +41 -35
  68. cloudnetpy/model_evaluation/products/product_resampling.py +17 -7
  69. cloudnetpy/model_evaluation/products/tools.py +29 -20
  70. cloudnetpy/model_evaluation/statistics/statistical_methods.py +30 -20
  71. cloudnetpy/model_evaluation/tests/e2e/conftest.py +3 -3
  72. cloudnetpy/model_evaluation/tests/e2e/process_cf/main.py +9 -5
  73. cloudnetpy/model_evaluation/tests/e2e/process_cf/tests.py +15 -14
  74. cloudnetpy/model_evaluation/tests/e2e/process_iwc/main.py +9 -5
  75. cloudnetpy/model_evaluation/tests/e2e/process_iwc/tests.py +15 -14
  76. cloudnetpy/model_evaluation/tests/e2e/process_lwc/main.py +9 -5
  77. cloudnetpy/model_evaluation/tests/e2e/process_lwc/tests.py +15 -14
  78. cloudnetpy/model_evaluation/tests/unit/conftest.py +42 -41
  79. cloudnetpy/model_evaluation/tests/unit/test_advance_methods.py +41 -48
  80. cloudnetpy/model_evaluation/tests/unit/test_grid_methods.py +216 -194
  81. cloudnetpy/model_evaluation/tests/unit/test_model_products.py +23 -21
  82. cloudnetpy/model_evaluation/tests/unit/test_observation_products.py +37 -38
  83. cloudnetpy/model_evaluation/tests/unit/test_plot_tools.py +43 -40
  84. cloudnetpy/model_evaluation/tests/unit/test_plotting.py +30 -36
  85. cloudnetpy/model_evaluation/tests/unit/test_statistical_methods.py +68 -31
  86. cloudnetpy/model_evaluation/tests/unit/test_tools.py +33 -26
  87. cloudnetpy/model_evaluation/utils.py +2 -1
  88. cloudnetpy/output.py +170 -111
  89. cloudnetpy/plotting/__init__.py +2 -1
  90. cloudnetpy/plotting/plot_meta.py +562 -822
  91. cloudnetpy/plotting/plotting.py +1142 -704
  92. cloudnetpy/products/__init__.py +1 -0
  93. cloudnetpy/products/classification.py +370 -88
  94. cloudnetpy/products/der.py +85 -55
  95. cloudnetpy/products/drizzle.py +77 -34
  96. cloudnetpy/products/drizzle_error.py +15 -11
  97. cloudnetpy/products/drizzle_tools.py +79 -59
  98. cloudnetpy/products/epsilon.py +211 -0
  99. cloudnetpy/products/ier.py +27 -50
  100. cloudnetpy/products/iwc.py +55 -48
  101. cloudnetpy/products/lwc.py +96 -70
  102. cloudnetpy/products/mwr_tools.py +186 -0
  103. cloudnetpy/products/product_tools.py +170 -128
  104. cloudnetpy/utils.py +455 -240
  105. cloudnetpy/version.py +2 -2
  106. {cloudnetpy-1.49.9.dist-info → cloudnetpy-1.87.3.dist-info}/METADATA +44 -40
  107. cloudnetpy-1.87.3.dist-info/RECORD +127 -0
  108. {cloudnetpy-1.49.9.dist-info → cloudnetpy-1.87.3.dist-info}/WHEEL +1 -1
  109. cloudnetpy-1.87.3.dist-info/entry_points.txt +2 -0
  110. docs/source/conf.py +2 -2
  111. cloudnetpy/categorize/atmos.py +0 -361
  112. cloudnetpy/products/mwr_multi.py +0 -68
  113. cloudnetpy/products/mwr_single.py +0 -75
  114. cloudnetpy-1.49.9.dist-info/RECORD +0 -112
  115. {cloudnetpy-1.49.9.dist-info → cloudnetpy-1.87.3.dist-info/licenses}/LICENSE +0 -0
  116. {cloudnetpy-1.49.9.dist-info → cloudnetpy-1.87.3.dist-info}/top_level.txt +0 -0
@@ -1,34 +1,35 @@
1
1
  import pytest
2
2
 
3
3
  from cloudnetpy.model_evaluation.plotting import plotting as pl
4
+ from cloudnetpy.model_evaluation.plotting.plot_meta import PlotMeta
4
5
 
5
6
  MODEL = "ecmwf"
6
-
7
-
8
- class VariableInfo:
9
- def __init__(self):
10
- self.name = "Product"
7
+ VARIABLE_INFO = PlotMeta(
8
+ name="Product",
9
+ cbar="rainbow",
10
+ plot_range=(0, 1),
11
+ plot_scale="linear",
12
+ plot_type="mesh",
13
+ )
11
14
 
12
15
 
13
16
  @pytest.mark.parametrize("key", ["cf_V", "cf_A", "cf_V_adv", "cf_A_adv"])
14
- def test_get_cf_title(key):
15
- var = VariableInfo()
17
+ def test_get_cf_title(key) -> None:
16
18
  field_name = key + "_" + MODEL
17
19
  value = "Product, Volume"
18
20
  if "A" in key:
19
21
  value = "Product, Area"
20
- x = pl._get_cf_title(field_name, var)
22
+ x = pl._get_cf_title(field_name, VARIABLE_INFO)
21
23
  assert x == value
22
24
 
23
25
 
24
26
  @pytest.mark.parametrize("key", ["cf_V", "cf_A", "cf_V_adv", "cf_A_adv"])
25
- def test_get_cf_title_cycle(key):
26
- var = VariableInfo()
27
+ def test_get_cf_title_cycle(key) -> None:
27
28
  field_name = key + "_" + MODEL + "_001"
28
29
  value = "Product, Volume"
29
30
  if "A" in key:
30
31
  value = "Product, Area"
31
- x = pl._get_cf_title(field_name, var)
32
+ x = pl._get_cf_title(field_name, VARIABLE_INFO)
32
33
  assert x == value
33
34
 
34
35
 
@@ -43,10 +44,9 @@ def test_get_cf_title_cycle(key):
43
44
  ("iwc_rain_adv", "Product with rain"),
44
45
  ],
45
46
  )
46
- def test_get_iwc_title(key, value):
47
- var = VariableInfo()
47
+ def test_get_iwc_title(key, value) -> None:
48
48
  field_name = key + "_" + MODEL
49
- x = pl._get_iwc_title(field_name, var)
49
+ x = pl._get_iwc_title(field_name, VARIABLE_INFO)
50
50
  assert x == value
51
51
 
52
52
 
@@ -61,42 +61,38 @@ def test_get_iwc_title(key, value):
61
61
  ("iwc_rain_adv", "Product with rain"),
62
62
  ],
63
63
  )
64
- def test_get_iwc_title_cycle(key, value):
65
- var = VariableInfo()
64
+ def test_get_iwc_title_cycle(key, value) -> None:
66
65
  field_name = key + "_" + MODEL + "_001"
67
- x = pl._get_iwc_title(field_name, var)
66
+ x = pl._get_iwc_title(field_name, VARIABLE_INFO)
68
67
  assert x == value
69
68
 
70
69
 
71
- def test_get_product_title():
72
- var = VariableInfo()
70
+ def test_get_product_title() -> None:
73
71
  value = "Product"
74
- x = pl._get_product_title(var)
72
+ x = pl._get_product_title(VARIABLE_INFO)
75
73
  assert x == value
76
74
 
77
75
 
78
- def test_get_product_title_cycle():
79
- var = VariableInfo()
76
+ def test_get_product_title_cycle() -> None:
80
77
  value = "Product"
81
- x = pl._get_product_title(var)
78
+ x = pl._get_product_title(VARIABLE_INFO)
82
79
  assert x == value
83
80
 
84
81
 
85
82
  @pytest.mark.parametrize(
86
- "key, title", [("lwc", "Product"), ("lwc_adv", "Product (Advection time)")]
83
+ "key, title",
84
+ [("lwc", "Product"), ("lwc_adv", "Product (Advection time)")],
87
85
  )
88
- def test_get_stat_titles(key, title):
86
+ def test_get_stat_titles(key, title) -> None:
89
87
  field_name = key + "_" + MODEL
90
- var = VariableInfo()
91
- x = pl._get_stat_titles(field_name, key, var)
88
+ x = pl._get_stat_titles(field_name, key, VARIABLE_INFO)
92
89
  assert x == title
93
90
 
94
91
 
95
92
  @pytest.mark.parametrize("key", ["cf_V", "cf_A", "cf_V_adv", "cf_A_adv"])
96
- def test_get_cf_title_stat(key):
93
+ def test_get_cf_title_stat(key) -> None:
97
94
  field_name = key + "_" + MODEL
98
- var = VariableInfo()
99
- x = pl._get_cf_title_stat(field_name, var)
95
+ x = pl._get_cf_title_stat(field_name, VARIABLE_INFO)
100
96
  value = "Product volume"
101
97
  if "A" in key:
102
98
  value = "Product area"
@@ -111,15 +107,13 @@ def test_get_cf_title_stat(key):
111
107
  ("iwc_rain", "Product with rain"),
112
108
  ],
113
109
  )
114
- def test_get_iwc_title_stat(key, value):
110
+ def test_get_iwc_title_stat(key, value) -> None:
115
111
  field_name = key + "_" + MODEL
116
- var = VariableInfo()
117
- x = pl._get_iwc_title_stat(field_name, var)
112
+ x = pl._get_iwc_title_stat(field_name, VARIABLE_INFO)
118
113
  assert x == value
119
114
 
120
115
 
121
116
  @pytest.mark.parametrize("key", ["lwc"])
122
- def test_get_product_title_stat(key):
123
- var = VariableInfo()
124
- x = pl._get_product_title_stat(var)
117
+ def test_get_product_title_stat(key) -> None:
118
+ x = pl._get_product_title_stat(VARIABLE_INFO)
125
119
  assert x == "Product"
@@ -8,7 +8,7 @@ PRODUCT_cf = ["cf", "ECMWF", "Cloud fraction"]
8
8
  PRODUCT_iwc = ["iwc", "ECMWF", "Ice water content"]
9
9
 
10
10
 
11
- def test_relative_error():
11
+ def test_relative_error() -> None:
12
12
  model = ma.array([[1, 2, 2, 3], [2, 4, 10, 1]])
13
13
  observation = ma.array([[3, 2, 5, 4], [4, 6, 8, 4]])
14
14
  x, _ = sts.relative_error(model, observation)
@@ -16,29 +16,35 @@ def test_relative_error():
16
16
  testing.assert_array_almost_equal(x, compare)
17
17
 
18
18
 
19
- def test_relative_error_mask():
19
+ def test_relative_error_mask() -> None:
20
20
  model = ma.array([[1, 2, 2, 3], [2, 1, 10, 1]])
21
21
  model.mask = np.array([[0, 0, 0, 1], [0, 1, 0, 1]])
22
22
  observation = ma.array([[1, 2, 5, 4], [4, 6, 8, 1]])
23
23
  observation.mask = np.array([[1, 0, 0, 1], [0, 0, 0, 1]])
24
24
  x, _ = sts.relative_error(model, observation)
25
25
  compare = ma.array(
26
- [[ma.masked, 0.0, -60.0, ma.masked], [-50.0, -83.33, 25.0, ma.masked]]
26
+ [
27
+ ma.array([-99, 0.0, -60.0, -99], mask=[True, False, False, True]),
28
+ ma.array([-50.0, -83.33, 25.0, -99], mask=[False, False, False, True]),
29
+ ],
27
30
  )
28
31
  testing.assert_array_almost_equal(x, compare)
29
32
 
30
33
 
31
- def test_relative_error_nan():
34
+ def test_relative_error_nan() -> None:
32
35
  model = ma.array([[1, 2, 2, 3], [2, 4, 10, 1]])
33
36
  observation = ma.array([[3, 2, 5, np.nan], [4, np.nan, 8, 4]])
34
37
  x, _ = sts.relative_error(model, observation)
35
38
  compare = ma.array(
36
- [[-66.67, 0.0, -60.0, ma.masked], [-50.0, ma.masked, 25.0, -75.0]]
39
+ [
40
+ ma.array([-66.67, 0.0, -60.0, -99], mask=[False, False, False, True]),
41
+ ma.array([-50.0, -99, 25.0, -75.0], mask=[False, True, False, False]),
42
+ ],
37
43
  )
38
44
  testing.assert_array_almost_equal(x, compare)
39
45
 
40
46
 
41
- def test_absolute_error():
47
+ def test_absolute_error() -> None:
42
48
  model = ma.array([[0.1, 0.2, 0.2, 0.3], [0.2, 0.4, 1.0, 0.0]])
43
49
  observation = ma.array([[0.2, 0.2, 0.1, 0.4], [0.4, 0.6, 0.8, 0.2]])
44
50
  x, _ = sts.absolute_error(model, observation)
@@ -46,27 +52,35 @@ def test_absolute_error():
46
52
  testing.assert_array_almost_equal(x, compare)
47
53
 
48
54
 
49
- def test_absolute_error_nan():
55
+ def test_absolute_error_nan() -> None:
50
56
  model = ma.array([[0.1, 0.2, 0.2, 0.3], [0.2, 0.4, 1.0, 0.0]])
51
57
  observation = ma.array([[0.2, np.nan, 0.1, 0.4], [np.nan, 0.6, 0.8, 0.2]])
52
58
  x, _ = sts.absolute_error(model, observation)
53
- compare = ma.array([[10.0, ma.masked, -10.0, 10.0], [ma.masked, 20.0, -20.0, 20.0]])
59
+ compare = ma.array(
60
+ [
61
+ ma.array([10.0, -99, -10.0, 10.0], mask=[False, True, False, False]),
62
+ ma.array([-99, 20.0, -20.0, 20.0], mask=[True, False, False, False]),
63
+ ],
64
+ )
54
65
  testing.assert_array_almost_equal(x, compare)
55
66
 
56
67
 
57
- def test_absolute_error_mask():
68
+ def test_absolute_error_mask() -> None:
58
69
  model = ma.array([[0.1, 0.2, 0.2, 0.3], [0.2, 0.4, 1.0, 0.0]])
59
70
  model.mask = np.array([[0, 0, 0, 1], [0, 1, 0, 1]])
60
71
  observation = ma.array([[0.2, 0.2, 0.1, 0.4], [0.4, 0.6, 0.8, 0.2]])
61
72
  observation.mask = np.array([[0, 0, 0, 0], [0, 1, 0, 0]])
62
73
  x, _ = sts.absolute_error(model, observation)
63
74
  compare = ma.array(
64
- [[10.0, 0.0, -10.0, ma.masked], [20.0, ma.masked, -20.0, ma.masked]]
75
+ [
76
+ ma.array([10.0, 0.0, -10.0, -99], mask=[False, False, False, True]),
77
+ ma.array([20.0, -99, -20.0, -99], mask=[False, True, False, True]),
78
+ ],
65
79
  )
66
80
  testing.assert_array_almost_equal(x, compare)
67
81
 
68
82
 
69
- def test_combine_masked_indices():
83
+ def test_combine_masked_indices() -> None:
70
84
  model = ma.array([[1, 2, 2, 3], [2, 4, 10, 1]])
71
85
  observation = ma.array([[3, 2, 5, 4], [4, 6, 8, 4]])
72
86
  x, y = sts.combine_masked_indices(model, observation)
@@ -76,49 +90,72 @@ def test_combine_masked_indices():
76
90
  testing.assert_array_almost_equal(y, compare_o)
77
91
 
78
92
 
79
- def test_combine_masked_indices_min():
93
+ def test_combine_masked_indices_min() -> None:
80
94
  model = ma.array([[1, 2, 2, 3], [2, 4, 10, 1]])
81
95
  observation = ma.array([[3, 2, 5, 4], [4, 6, 8, 4]])
82
96
  x, y = sts.combine_masked_indices(model, observation)
83
- compare_m = ma.array([[ma.masked, 2, 2, 3], [2, 4, 10, ma.masked]])
84
- compare_o = ma.array([[ma.masked, 2, 5, 4], [4, 6, 8, ma.masked]])
97
+
98
+ compare_m = ma.array(
99
+ [
100
+ ma.array([-99, 2, 2, 3], mask=[True, False, False, False]),
101
+ ma.array([2, 4, 10, -99], mask=[True, False, False, True]),
102
+ ],
103
+ )
104
+ compare_o = ma.array(
105
+ [
106
+ ma.array([-99, 2, 5, 4], mask=[True, False, False, False]),
107
+ ma.array([4, 6, 8, -99], mask=[True, False, False, True]),
108
+ ],
109
+ )
110
+
85
111
  testing.assert_array_almost_equal(x, compare_m)
86
112
  testing.assert_array_almost_equal(y, compare_o)
87
113
 
88
114
 
89
- def test_combine_masked_indices_mask():
115
+ def test_combine_masked_indices_mask() -> None:
90
116
  model = ma.array([[1, 2, 2, 3], [2, 4, 10, 1]])
91
117
  model.mask = ma.array([[1, 0, 0, 0], [0, 0, 0, 1]])
92
118
  observation = ma.array([[3, 2, 1, 4], [4, 6, 8, 4]])
93
119
  observation.mask = ma.array([[0, 1, 1, 0], [1, 0, 0, 0]])
94
120
  x, y = sts.combine_masked_indices(model, observation)
95
121
  model = ma.array(
96
- [[ma.masked, ma.masked, ma.masked, 3], [ma.masked, 4, 10, ma.masked]]
122
+ [
123
+ ma.array([-99, -99, -99, 3], mask=[True, True, True, False]),
124
+ ma.array([-99, 4, 10, -99], mask=[True, False, False, True]),
125
+ ],
97
126
  )
98
127
  observation = ma.array(
99
- [[ma.masked, ma.masked, ma.masked, 4], [ma.masked, 6, 8, ma.masked]]
128
+ [
129
+ ma.array([-99, -99, -99, 4], mask=[True, True, True, False]),
130
+ ma.array([-99, 6, 8, -99], mask=[True, False, False, True]),
131
+ ],
100
132
  )
101
133
  testing.assert_array_almost_equal(x, model)
102
134
  testing.assert_array_almost_equal(y, observation)
103
135
 
104
136
 
105
- def test_combine_masked_indices_nan():
137
+ def test_combine_masked_indices_nan() -> None:
106
138
  model = ma.array([[1, 2, 2, 3], [2, 4, 10, 1]])
107
139
  observation = ma.array([[np.nan, 2, 5, 4], [4, 6, np.nan, 4]])
108
140
  x, y = sts.combine_masked_indices(model, observation)
109
- model = ma.array([[ma.masked, 2, 2, 3], [2, 4, ma.masked, 1]])
141
+ model = ma.array(
142
+ [
143
+ ma.array([-99, 2, 2, 3], mask=[True, False, False, False]),
144
+ ma.array([2, 4, -99, 1], mask=[False, False, True, False]),
145
+ ],
146
+ )
110
147
  testing.assert_array_almost_equal(x, model)
111
148
  testing.assert_array_almost_equal(y, observation)
112
149
 
113
150
 
114
- def test_calc_common_area_sum():
151
+ def test_calc_common_area_sum() -> None:
115
152
  model = ma.array([[1, 2, 2, 3], [2, 4, 10, 1]])
116
153
  observation = ma.array([[3, 2, 1, 4], [4, 6, 8, 4]])
117
154
  x, _ = sts.calc_common_area_sum(model, observation)
118
155
  testing.assert_almost_equal(x, 100)
119
156
 
120
157
 
121
- def test_calc_common_area_sum_min():
158
+ def test_calc_common_area_sum_min() -> None:
122
159
  model = ma.array([[1, 2, 2, 3], [2, 4, 10, 1]])
123
160
  model.mask = ma.array([[1, 0, 0, 0], [0, 0, 0, 1]])
124
161
  observation = ma.array([[3, 2, 1, 4], [4, 6, 8, 4]])
@@ -127,7 +164,7 @@ def test_calc_common_area_sum_min():
127
164
  testing.assert_almost_equal(x, 60.0)
128
165
 
129
166
 
130
- def test_calc_common_area_sum_nan():
167
+ def test_calc_common_area_sum_nan() -> None:
131
168
  model = ma.array([[1, 2, 2, 3], [2, np.nan, 10, 1]])
132
169
  model.mask = ma.array([[1, 0, 0, 0], [0, 0, 0, 1]])
133
170
  observation = ma.array([[3, 2, 1, 4], [4, 6, np.nan, 4]])
@@ -136,7 +173,7 @@ def test_calc_common_area_sum_nan():
136
173
  testing.assert_almost_equal(x, 25.0)
137
174
 
138
175
 
139
- def test_calc_common_area_sum_mask():
176
+ def test_calc_common_area_sum_mask() -> None:
140
177
  model = ma.array([[1, 2, 2, 3], [2, 4, 10, 1]])
141
178
  model.mask = ma.array([[1, 0, 0, 0], [0, 0, 0, 0]])
142
179
  observation = ma.array([[3, 2, 1, 4], [4, 6, 8, 4]])
@@ -145,7 +182,7 @@ def test_calc_common_area_sum_mask():
145
182
  testing.assert_almost_equal(x, 50.0)
146
183
 
147
184
 
148
- def test_histogram():
185
+ def test_histogram() -> None:
149
186
  model = ma.array([[1, 2, 2, 3], [2, 4, 10, 1]])
150
187
  observation = ma.array([[3, 2, 1, 4], [4, 6, 8, 4]])
151
188
  compare_x = np.array([1, 2, 2, 3, 2, 4, 8, 1])
@@ -155,7 +192,7 @@ def test_histogram():
155
192
  testing.assert_array_almost_equal(y, compare_y)
156
193
 
157
194
 
158
- def test_histogram_mask():
195
+ def test_histogram_mask() -> None:
159
196
  model = ma.array([[1, 2, 2, 3], [2, 4, 10, 1]])
160
197
  model.mask = ma.array([[1, 0, 0, 0], [0, 0, 0, 1]])
161
198
  observation = ma.array([[3, 2, 1, 4], [4, 6, 8, 4]])
@@ -167,7 +204,7 @@ def test_histogram_mask():
167
204
  testing.assert_array_almost_equal(y, compare_y)
168
205
 
169
206
 
170
- def test_histogram_nan():
207
+ def test_histogram_nan() -> None:
171
208
  model = ma.array([[1, 2, 2, 3], [2, 4, 10, 1]])
172
209
  observation = ma.array([[3, np.nan, 1, 4], [np.nan, 6, np.nan, 4]])
173
210
  compare_x = np.array([1, 2, 2, 3, 2, 4, 6, 1])
@@ -177,7 +214,7 @@ def test_histogram_nan():
177
214
  testing.assert_array_almost_equal(y, compare_y)
178
215
 
179
216
 
180
- def test_vertical_profile():
217
+ def test_vertical_profile() -> None:
181
218
  model = ma.array([[0, 2, 2, 3], [2, 4, 10, 1], [4, 6, 6, 8]])
182
219
  observation = ma.array([[3, 1, 1, 4], [4, 3, 8, 0], [5, 5, 3, 2]])
183
220
  x, y = sts.vertical_profile(model, observation)
@@ -187,7 +224,7 @@ def test_vertical_profile():
187
224
  testing.assert_array_almost_equal(y, observation)
188
225
 
189
226
 
190
- def test_vertical_profile_nan():
227
+ def test_vertical_profile_nan() -> None:
191
228
  model = ma.array([[0, 2, 2, 3], [2, 4, 10, 1], [4, 6, 6, 8]])
192
229
  observation = ma.array([[3, 1, 1, np.nan], [np.nan, 3, 8, 0], [5, 5, 3, 2]])
193
230
  x, y = sts.vertical_profile(model, observation)
@@ -197,14 +234,14 @@ def test_vertical_profile_nan():
197
234
  testing.assert_array_almost_equal(y, observation)
198
235
 
199
236
 
200
- def test_vertical_profile_mask():
237
+ def test_vertical_profile_mask() -> None:
201
238
  model = ma.array([[0, 2, 2, 3], [2, 4, 10, 1], [4, 6, 6, 8]])
202
239
  model.mask = ma.array([[1, 0, 0, 0], [0, 0, 0, 1], [0, 0, 1, 0]])
203
240
  observation = ma.array([[3, 1, 1, 4], [4, 3, 8, 0], [5, 5, 3, 2]])
204
241
  observation.mask = ma.array([[0, 1, 0, 0], [0, 1, 0, 1], [0, 1, 0, 0]])
205
242
  x, y = sts.vertical_profile(model, observation)
206
243
  model = ma.array([3, 4, 6, 5.5])
207
- observation = ma.array([4, ma.masked, 4, 3])
244
+ observation = ma.array([4, -99, 4, 3], mask=[False, True, False, False])
208
245
  testing.assert_array_almost_equal(x, model)
209
246
  testing.assert_array_almost_equal(y, observation)
210
247
 
@@ -216,6 +253,6 @@ def test_vertical_profile_mask():
216
253
  ("vertical", ("ECMWF", "Cloud fraction")),
217
254
  ],
218
255
  )
219
- def test_day_stat_title(method, title):
256
+ def test_day_stat_title(method, title) -> None:
220
257
  x = sts.day_stat_title(method, PRODUCT_cf)
221
258
  assert x == title
@@ -1,4 +1,4 @@
1
- from datetime import datetime, timedelta
1
+ from datetime import datetime, timedelta, timezone
2
2
 
3
3
  import numpy as np
4
4
  import pytest
@@ -12,61 +12,62 @@ OUTPUT_FILE = "/"
12
12
  PRODUCT = "iwc"
13
13
 
14
14
 
15
- def test_model_file_list():
15
+ def test_model_file_list() -> None:
16
16
  name = "ec"
17
17
  models = ["00_ec_1", "00_ec_2", "00_ec_3"]
18
18
  tools.check_model_file_list(name, models)
19
19
 
20
20
 
21
- @pytest.mark.xfail(raises=AttributeError)
22
- def test_model_file_list_fail():
21
+ def test_model_file_list_fail() -> None:
23
22
  name = "ec"
24
23
  models = ["00_ec_1", "ac_1", "00_ec_2", "00_ec_3"]
25
- tools.check_model_file_list(name, models)
24
+ with pytest.raises(AttributeError):
25
+ tools.check_model_file_list(name, models)
26
26
 
27
27
 
28
- def test_time2datetime():
28
+ def test_time2datetime() -> None:
29
29
  time_list = np.array(range(10))
30
- d = datetime(2020, 4, 7, 0, 0, 0)
30
+ d = datetime(2020, 4, 7, 0, 0, 0, tzinfo=timezone.utc)
31
31
  x = tools.time2datetime(time_list, d)
32
32
  compare = [
33
- datetime(2020, 4, 7, 0, 0, 0) + timedelta(hours=1 * x) for x in range(0, 10)
33
+ datetime(2020, 4, 7, 0, 0, 0, tzinfo=timezone.utc) + timedelta(hours=1 * x)
34
+ for x in range(10)
34
35
  ]
35
36
  assert all(a == b for a, b in zip(x, compare))
36
37
 
37
38
 
38
- def test_rebin_edges():
39
+ def test_rebin_edges() -> None:
39
40
  data = np.array([1, 3, 6, 10, 15, 21, 28])
40
41
  compare = np.array([-1, 2, 4.5, 8, 12.5, 18, 24.5, 35])
41
42
  x = tools.rebin_edges(data)
42
43
  testing.assert_array_almost_equal(x, compare)
43
44
 
44
45
 
45
- def test_calculate_advection_time_hour(model_file):
46
+ def test_calculate_advection_time_hour(model_file) -> None:
46
47
  obj = ModelManager(str(model_file), MODEL, OUTPUT_FILE, PRODUCT)
47
48
  h = obj.resolution_h
48
- v = ma.array([[1, 2, 3], [2, 3, 4], [3, 4, 5]])
49
+ v = np.array([[1, 2, 3], [2, 3, 4], [3, 4, 5]])
49
50
  s = 1
50
51
  compare = h * 1000 / v / 60**2
51
52
  compare[compare > 1 / s] = 1 / s
52
53
  compare = np.asarray([[timedelta(hours=float(t)) for t in tt] for tt in compare])
53
- x = tools.calculate_advection_time(int(h), v, s)
54
+ x = tools.calculate_advection_time(int(h), ma.masked_array(v), s)
54
55
  assert x.all() == compare.all()
55
56
 
56
57
 
57
- def test_calculate_advection_time_10min(model_file):
58
+ def test_calculate_advection_time_10min(model_file) -> None:
58
59
  obj = ModelManager(str(model_file), MODEL, OUTPUT_FILE, PRODUCT)
59
60
  h = obj.resolution_h
60
- v = ma.array([[1, 2, 3], [2, 3, 4], [3, 4, 5]])
61
+ v = np.array([[1, 2, 3], [2, 3, 4], [3, 4, 5]])
61
62
  s = 6
62
63
  compare = h * 1000 / v / 60**2
63
64
  compare[compare > 1 / s] = 1 / s
64
65
  compare = np.asarray([[timedelta(hours=float(t)) for t in tt] for tt in compare])
65
- x = tools.calculate_advection_time(int(h), v, s)
66
+ x = tools.calculate_advection_time(int(h), ma.masked_array(v), s)
66
67
  assert x.all() == compare.all()
67
68
 
68
69
 
69
- def test_get_1d_indices():
70
+ def test_get_1d_indices() -> None:
70
71
  w = (1, 5)
71
72
  d = ma.array([0, 1, 2, 3, 4, 5, 6, 7])
72
73
  compare = ma.array([0, 1, 1, 1, 1, 0, 0, 0])
@@ -74,37 +75,43 @@ def test_get_1d_indices():
74
75
  testing.assert_array_almost_equal(x, compare)
75
76
 
76
77
 
77
- def test_get_1d_indices_mask():
78
+ def test_get_1d_indices_mask() -> None:
78
79
  w = (1, 5)
79
80
  d = ma.array([0, 1, 2, 3, 4, 5, 6, 7])
80
81
  m = np.array([0, 0, 1, 0, 0, 1, 0, 1], dtype=bool)
81
82
  x = tools.get_1d_indices(w, d, m)
82
83
  d[m] = ma.masked
83
- compare = ma.array([0, 1, ma.masked, 1, 1, ma.masked, 0, ma.masked])
84
+ compare = ma.array(
85
+ [0, 1, -99, 1, 1, -99, 0, -99],
86
+ mask=[False, False, True, False, False, True, False, True],
87
+ )
84
88
  testing.assert_array_almost_equal(x, compare)
85
89
 
86
90
 
87
- def test_get_adv_indices():
91
+ def test_get_adv_indices() -> None:
88
92
  mt = 3
89
93
  at = 4
90
94
  d = ma.array([0, 1, 2, 3, 4, 5, 6, 7])
91
- compare = ma.array([0, 1, 1, 1, 1, 0, 0, 0], dtype=bool)
95
+ compare: ma.MaskedArray = ma.array([0, 1, 1, 1, 1, 0, 0, 0], dtype=bool)
92
96
  x = tools.get_adv_indices(mt, at, d)
93
97
  testing.assert_array_almost_equal(x, compare)
94
98
 
95
99
 
96
- def test_get_adv_indices_mask():
100
+ def test_get_adv_indices_mask() -> None:
97
101
  mt = 3
98
102
  at = 4
99
- d = ma.array([0, 1, 2, 3, 4, 5, 6, 7])
100
- m = ma.array([0, 0, 1, 0, 0, 1, 0, 1], dtype=bool)
103
+ d: ma.MaskedArray = ma.array([0, 1, 2, 3, 4, 5, 6, 7])
104
+ m: ma.MaskedArray = ma.array([0, 0, 1, 0, 0, 1, 0, 1], dtype=bool)
101
105
  x = tools.get_adv_indices(mt, at, d, m)
102
106
  d[m] = ma.masked
103
- compare = ma.array([0, 1, ma.masked, 1, 1, ma.masked, 0, 0])
107
+ compare = ma.array(
108
+ [0, 1, -99, 1, 1, -99, 0, 0],
109
+ mask=[False, False, True, False, False, True, False, False],
110
+ )
104
111
  testing.assert_array_almost_equal(x, compare)
105
112
 
106
113
 
107
- def test_obs_windows_size():
114
+ def test_obs_windows_size() -> None:
108
115
  i = np.array([0, 0, 1, 1, 1, 1, 0], dtype=bool)
109
116
  j = np.array([0, 1, 1, 1, 0, 0, 0], dtype=bool)
110
117
  x = tools.get_obs_window_size(i, j)
@@ -112,7 +119,7 @@ def test_obs_windows_size():
112
119
  testing.assert_almost_equal(x, (4, 3))
113
120
 
114
121
 
115
- def test_obs_windows_size_none():
122
+ def test_obs_windows_size_none() -> None:
116
123
  i = np.array([0, 0, 1, 1, 1, 1, 0], dtype=bool)
117
124
  j = np.array([0, 0, 0, 0, 0, 0, 0], dtype=bool)
118
125
  x = tools.get_obs_window_size(i, j)
@@ -1,5 +1,6 @@
1
1
  import os
2
+ from os import PathLike
2
3
 
3
4
 
4
- def file_exists(file_path: str):
5
+ def file_exists(file_path: str | PathLike) -> bool:
5
6
  return os.path.isfile(file_path) and os.path.getsize(file_path) > 0