cloudnetpy 1.60.2__py3-none-any.whl → 1.60.4__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.
@@ -28,7 +28,7 @@ MODELS = {
28
28
  level=88,
29
29
  cycle="1-12, 7-18",
30
30
  ),
31
- "harmonie": ModelMetaData(
31
+ "harmonie-fmi-6-11": ModelMetaData(
32
32
  model_name="HARMONIE-AROME",
33
33
  long_name="the HIRLAM–ALADIN Research on Mesoscale Operational NWP in Euromed", # noqa: RUF001
34
34
  level=65,
@@ -17,7 +17,7 @@ import cloudnetpy.model_evaluation.plotting.plot_tools as p_tools
17
17
  from cloudnetpy.model_evaluation.model_metadata import MODELS
18
18
  from cloudnetpy.model_evaluation.plotting.plot_meta import ATTRIBUTES
19
19
  from cloudnetpy.model_evaluation.statistics.statistical_methods import DayStatistics
20
- from cloudnetpy.plotting.plotting import get_log_cbar_tick_labels, lin2log
20
+ from cloudnetpy.plotting.plotting import Dimensions, get_log_cbar_tick_labels, lin2log
21
21
 
22
22
  sys.path.append(os.path.dirname(os.path.abspath(__file__)))
23
23
 
@@ -34,7 +34,7 @@ def generate_L3_day_plots(
34
34
  save_path: str | None = None,
35
35
  image_name: str | None = None,
36
36
  show: bool | None = False,
37
- ) -> None:
37
+ ) -> list[Dimensions]:
38
38
  """Generate visualizations for level 3 dayscale products.
39
39
  With figure type visualizations can be subplot in group, pair, single or
40
40
  statistic of given product. In group fig_type all different methods are plot
@@ -93,7 +93,11 @@ def generate_L3_day_plots(
93
93
  model_info = MODELS[model]
94
94
  model_name = model_info.model_name
95
95
  name_set = p_tools.parse_wanted_names(nc_file, product, model, var_list)
96
- for names in name_set:
96
+ unique_tuples = {tuple(lst) for lst in name_set}
97
+ name_set_unique = tuple(list(tup) for tup in unique_tuples)
98
+
99
+ dimensions = []
100
+ for names in name_set_unique:
97
101
  if len(names) > 0:
98
102
  try:
99
103
  cycle_names, cycles = p_tools.sort_cycles(names, model)
@@ -120,7 +124,11 @@ def generate_L3_day_plots(
120
124
  save_path,
121
125
  image_name,
122
126
  ]
123
- getattr(cls, f"get_{fig_type}_plots")(*params, **kwargs)
127
+ figs, axes = getattr(cls, f"get_{fig_type}_plots")(
128
+ *params, **kwargs
129
+ )
130
+ for fig, ax in zip(figs, axes, strict=False):
131
+ dimensions.append(Dimensions(fig, ax))
124
132
  except AttributeError:
125
133
  params = [
126
134
  product,
@@ -143,7 +151,10 @@ def generate_L3_day_plots(
143
151
  save_path,
144
152
  image_name,
145
153
  ]
146
- getattr(cls, f"get_{fig_type}_plots")(*params, **kwargs)
154
+ figs, axes = getattr(cls, f"get_{fig_type}_plots")(*params, **kwargs)
155
+ for fig, ax in zip(figs, axes, strict=False):
156
+ dimensions.append(Dimensions(fig, ax))
157
+ return dimensions
147
158
 
148
159
 
149
160
  def get_group_plots(
@@ -159,7 +170,7 @@ def get_group_plots(
159
170
  cycle: str = "",
160
171
  title: bool = True,
161
172
  include_xlimits: bool = False,
162
- ) -> None:
173
+ ) -> tuple:
163
174
  """Group subplot visualization for both standard and advection downsampling.
164
175
  Generates group subplot figure for product with model and all different
165
176
  downsampling methods. Generates separated figures for standard and advection
@@ -204,6 +215,7 @@ def get_group_plots(
204
215
  [product, model_run, "group"],
205
216
  show=show,
206
217
  )
218
+ return fig, ax
207
219
 
208
220
 
209
221
  def get_pair_plots(
@@ -280,7 +292,7 @@ def get_single_plots(
280
292
  cycle: str = "",
281
293
  title: bool = True,
282
294
  include_xlimits: bool = False,
283
- ) -> None:
295
+ ) -> tuple[list, list]:
284
296
  """Generates figures of each product variable from given file in loop.
285
297
 
286
298
  Args:
@@ -295,9 +307,13 @@ def get_single_plots(
295
307
  cycle (str): Name of cycle if exists
296
308
  title (bool): True or False if wanted to add title to subfig
297
309
  """
310
+ figs = []
311
+ axes = []
298
312
  variable_info = ATTRIBUTES[product]
299
- for _, name in enumerate(names):
313
+ for name in names:
300
314
  fig, ax = initialize_figure(1)
315
+ figs.append(fig)
316
+ axes.append(ax)
301
317
  set_yax(ax[0], 12, ylabel=None)
302
318
  set_xax(ax[0], include_xlimits=include_xlimits)
303
319
 
@@ -318,6 +334,7 @@ def get_single_plots(
318
334
  [name, "single"],
319
335
  show=show,
320
336
  )
337
+ return figs, axes
321
338
 
322
339
 
323
340
  def plot_colormesh(ax, data: np.ndarray, axes: tuple, variable_info) -> None:
@@ -349,7 +366,7 @@ def get_statistic_plots(
349
366
  show: bool,
350
367
  cycle: str = "",
351
368
  title: bool = True,
352
- ) -> None:
369
+ ) -> tuple:
353
370
  """Statistical subplots for day scale products.
354
371
  Statistical analysis can be done by day scale with relative error ('error'),
355
372
  total data area analysis ('area'), histogram ('hist') or vertical profiles
@@ -387,12 +404,16 @@ def get_statistic_plots(
387
404
  err_msg = f"No data in {model_name} or observation"
388
405
  raise ValueError(err_msg)
389
406
 
407
+ figs = []
408
+ axes = []
390
409
  for stat in stats:
391
410
  try:
392
411
  obs_missing = False
393
412
  model_missing = False
394
413
  variable_info = ATTRIBUTES[product]
395
414
  fig, ax = initialize_figure(len(names) - 1, stat)
415
+ figs.append(fig)
416
+ axes.append(ax)
396
417
  model_data, _, _ = p_tools.read_data_characters(nc_file, names[0], model)
397
418
  if np.all(model_data.mask is True):
398
419
  model_missing = True
@@ -443,6 +464,7 @@ def get_statistic_plots(
443
464
  [name, stat, model_run],
444
465
  show=show,
445
466
  )
467
+ return figs, axes
446
468
 
447
469
 
448
470
  def initialize_statistic_plots(
@@ -2,8 +2,9 @@ import importlib
2
2
  import logging
3
3
 
4
4
  import numpy as np
5
+ import scipy.special
6
+ import scipy.stats
5
7
  from numpy import ma
6
- from scipy.special import gamma
7
8
 
8
9
  import cloudnetpy.utils as cl_tools
9
10
  from cloudnetpy.datasource import DataSource
@@ -44,7 +45,7 @@ class AdvanceProductMethods(DataSource):
44
45
  name = f"get_advance_{self.product}"
45
46
  getattr(cls, name)(self)
46
47
  except AttributeError as error:
47
- logging.warning("No advance method for %s: %s", self.product, error)
48
+ logging.debug("No advance method for %s: %s", self.product, error)
48
49
 
49
50
  def get_advance_cf(self) -> None:
50
51
  self.cf_cirrus_filter()
@@ -60,24 +61,36 @@ class AdvanceProductMethods(DataSource):
60
61
  cf_filtered = self.filter_high_iwc_low_cf(cf, iwc, lwc)
61
62
  cloud_iwc, ice_ind = self.find_ice_in_clouds(cf_filtered, iwc, lwc)
62
63
  variance_iwc = self.iwc_variance(h, ice_ind)
63
- # Looks suspicious, check me:
64
+
64
65
  for i, ind in enumerate(zip(ice_ind[0], ice_ind[-1], strict=True)):
65
- iwc_dist = self.calculate_iwc_distribution(cloud_iwc[i], variance_iwc[i])
66
+ try:
67
+ iwc_dist = self.calculate_iwc_distribution(
68
+ cloud_iwc[i], variance_iwc[i]
69
+ )
70
+ except ValueError:
71
+ continue
72
+
66
73
  p_iwc = self.gamma_distribution(iwc_dist, variance_iwc[i], cloud_iwc[i])
74
+
75
+ if np.isinf(p_iwc).any():
76
+ cf_filtered[ind] = ma.masked
77
+ continue
78
+
67
79
  if np.sum(p_iwc) == 0 or p_iwc[-1] > 0.01 * np.sum(p_iwc):
68
- cf_filtered[ind] = np.nan
80
+ cf_filtered[ind] = ma.masked
69
81
  continue
70
- obs_index = self.get_observation_index(
71
- iwc_dist,
72
- tZT,
73
- tT,
74
- tZ,
75
- t,
76
- float(t_screened[ind]),
77
- float(z_sen[ind]),
82
+
83
+ min_iwc = 10 ** (
84
+ tZT * z_sen[ind] * t_screened[ind]
85
+ + tT * t_screened[ind]
86
+ + tZ * z_sen[ind]
87
+ + t
78
88
  )
89
+ obs_index = iwc_dist > min_iwc
79
90
  cf_filtered[ind] = self.filter_cirrus(p_iwc, obs_index, cf_filtered[ind])
91
+
80
92
  cf_filtered[cf_filtered < 0.05] = ma.masked
93
+
81
94
  self._model_obj.append_data(
82
95
  cf_filtered,
83
96
  f"{self._model_obj.model}{self._model_obj.cycle}_cf_cirrus",
@@ -132,7 +145,7 @@ class AdvanceProductMethods(DataSource):
132
145
  iwc: np.ndarray,
133
146
  lwc: np.ndarray,
134
147
  ) -> np.ndarray:
135
- cf_filtered = np.copy(cf)
148
+ cf_filtered = ma.copy(cf)
136
149
  weird_ind = (iwc / cf > 0.5e-3) & (cf < 0.001)
137
150
  weird_ind = weird_ind | (iwc == 0) & (lwc == 0) & (cf == 0)
138
151
  cf_filtered[weird_ind] = ma.masked
@@ -199,7 +212,9 @@ class AdvanceProductMethods(DataSource):
199
212
  n_std: int = 5,
200
213
  n_dist: int = 250,
201
214
  ) -> np.ndarray:
202
- finish = cloud_iwc + n_std * (np.sqrt(f_variance_iwc) * cloud_iwc)
215
+ finish = cloud_iwc + n_std * (ma.sqrt(f_variance_iwc) * cloud_iwc)
216
+ if isinstance(finish, ma.MaskedArray) and finish.mask.all():
217
+ raise ValueError
203
218
  iwc_dist = np.arange(0, finish, finish / (n_dist - 1))
204
219
  if cloud_iwc < iwc_dist[2]:
205
220
  finish = cloud_iwc * 10
@@ -208,40 +223,11 @@ class AdvanceProductMethods(DataSource):
208
223
 
209
224
  @staticmethod
210
225
  def gamma_distribution(
211
- iwc_dist: np.ndarray,
212
- f_variance_iwc: float,
213
- cloud_iwc: float,
214
- ) -> np.ndarray:
215
- def calculate_gamma_dist() -> float:
216
- alpha = 1 / f_variance_iwc
217
- return (
218
- 1
219
- / gamma(alpha)
220
- * (alpha / cloud_iwc) ** alpha
221
- * iwc_dist[i] ** (alpha - 1)
222
- * ma.exp(-(alpha * iwc_dist[i] / cloud_iwc))
223
- )
224
-
225
- p_iwc = np.zeros(iwc_dist.shape)
226
- for i in range(len(iwc_dist)):
227
- p_iwc[i] = calculate_gamma_dist()
228
- return p_iwc
229
-
230
- @staticmethod
231
- def get_observation_index(
232
- iwc_dist: np.ndarray,
233
- tZT: float,
234
- tT: float,
235
- tZ: float,
236
- t: np.ndarray,
237
- temperature: float,
238
- z_sen: float,
226
+ iwc_dist: np.ndarray, f_variance_iwc: float, cloud_iwc: float
239
227
  ) -> np.ndarray:
240
- def calculate_min_iwc() -> np.ndarray:
241
- return 10 ** (tZT * z_sen * temperature + tT * temperature + tZ * z_sen + t)
242
-
243
- iwc_min = calculate_min_iwc()
244
- return iwc_dist > iwc_min
228
+ alpha = 1 / f_variance_iwc
229
+ theta = cloud_iwc / alpha
230
+ return scipy.stats.gamma.pdf(iwc_dist, a=alpha, scale=theta)
245
231
 
246
232
  @staticmethod
247
233
  def filter_cirrus(
@@ -249,4 +235,4 @@ class AdvanceProductMethods(DataSource):
249
235
  obs_index: np.ndarray,
250
236
  cf_filtered: np.ndarray,
251
237
  ) -> np.ndarray:
252
- return (np.sum(p_iwc * obs_index) / np.sum(p_iwc)) * cf_filtered
238
+ return (ma.sum(p_iwc * obs_index) / ma.sum(p_iwc)) * cf_filtered
@@ -119,56 +119,35 @@ class ProductGrid:
119
119
 
120
120
  def _cf_method_storage(self) -> tuple[dict, dict]:
121
121
  cf_dict = {
122
- "cf_V": np.zeros(self._model_height.shape),
123
- "cf_A": np.zeros(self._model_height.shape),
122
+ "cf_V": ma.zeros(self._model_height.shape),
123
+ "cf_A": ma.zeros(self._model_height.shape),
124
124
  }
125
125
  cf_adv_dict = {
126
- "cf_V_adv": np.zeros(self._model_height.shape),
127
- "cf_A_adv": np.zeros(self._model_height.shape),
126
+ "cf_V_adv": ma.zeros(self._model_height.shape),
127
+ "cf_A_adv": ma.zeros(self._model_height.shape),
128
128
  }
129
129
  return cf_dict, cf_adv_dict
130
130
 
131
131
  def _iwc_method_storage(self) -> tuple[dict, dict]:
132
132
  iwc_dict = {
133
- "iwc": np.zeros(self._model_height.shape),
134
- "iwc_att": np.zeros(self._model_height.shape),
135
- "iwc_rain": np.zeros(self._model_height.shape),
133
+ "iwc": ma.zeros(self._model_height.shape),
134
+ "iwc_att": ma.zeros(self._model_height.shape),
135
+ "iwc_rain": ma.zeros(self._model_height.shape),
136
136
  }
137
137
  iwc_adv_dict = {
138
- "iwc_adv": np.zeros(self._model_height.shape),
139
- "iwc_att_adv": np.zeros(self._model_height.shape),
140
- "iwc_rain_adv": np.zeros(self._model_height.shape),
138
+ "iwc_adv": ma.zeros(self._model_height.shape),
139
+ "iwc_att_adv": ma.zeros(self._model_height.shape),
140
+ "iwc_rain_adv": ma.zeros(self._model_height.shape),
141
141
  }
142
142
  return iwc_dict, iwc_adv_dict
143
143
 
144
144
  def _product_method_storage(self) -> tuple[dict, dict]:
145
- product_dict = {f"{self._obs_obj.obs}": np.zeros(self._model_height.shape)}
145
+ product_dict = {f"{self._obs_obj.obs}": ma.zeros(self._model_height.shape)}
146
146
  product_adv_dict = {
147
- f"{self._obs_obj.obs}_adv": np.zeros(self._model_height.shape),
147
+ f"{self._obs_obj.obs}_adv": ma.zeros(self._model_height.shape),
148
148
  }
149
149
  return product_dict, product_adv_dict
150
150
 
151
- @staticmethod
152
- def _regrid_cf(storage: dict, i: int, j: int, data: np.ndarray | None) -> dict:
153
- """Calculates average cloud fraction value to grid point"""
154
- for key, downsample in storage.items():
155
- if data is not None:
156
- if isinstance(data, ma.MaskedArray) and data.mask.all():
157
- downsample[i, j] = np.nan
158
- elif not np.isnan(data).all():
159
- downsample[i, j] = np.nanmean(data)
160
- else:
161
- downsample[i, j] = np.nan
162
- if "_A" in key and (
163
- not np.isnan(data).all()
164
- and not (isinstance(data, ma.MaskedArray) and data.mask.all())
165
- ):
166
- downsample[i, j] = tl.average_column_sum(data)
167
- else:
168
- downsample[i, j] = np.nan
169
- storage[key] = downsample
170
- return storage
171
-
172
151
  def _reshape_data_to_window(
173
152
  self,
174
153
  ind: np.ndarray,
@@ -181,6 +160,17 @@ class ProductGrid:
181
160
  return self._obs_data[ind].reshape(window_size)
182
161
  return None
183
162
 
163
+ @staticmethod
164
+ def _regrid_cf(storage: dict, i: int, j: int, data: np.ndarray) -> dict:
165
+ """Calculates average cloud fraction value to grid point."""
166
+ data_ma = ma.array(data) if not isinstance(data, ma.MaskedArray) else data
167
+ for key, downsample in storage.items():
168
+ downsample[i, j] = ma.mean(data_ma)
169
+ if "_A" in key and not data_ma.mask.all():
170
+ downsample[i, j] = tl.average_column_sum(data_ma)
171
+ storage[key] = downsample
172
+ return storage
173
+
184
174
  def _regrid_iwc(
185
175
  self,
186
176
  storage: dict,
@@ -189,40 +179,33 @@ class ProductGrid:
189
179
  ind_rain: np.ndarray,
190
180
  ind_no_rain: np.ndarray,
191
181
  ) -> dict:
192
- """Calculates average iwc value for grid point"""
193
- for key, downsample in storage.items():
194
- if not self._obs_data[ind_no_rain].mask.all():
195
- if np.isnan(self._obs_data[ind_no_rain]).all():
196
- downsample[i, j] = np.nan
197
- else:
198
- no_rain_data = self._obs_data[ind_no_rain]
199
- if no_rain_data.size > 0:
200
- downsample[i, j] = np.nanmean(self._obs_data[ind_no_rain])
201
- else:
202
- downsample[i, j] = np.nan
203
- elif "rain" in key and not self._obs_data[ind_rain].mask.all():
204
- downsample[i, j] = np.nanmean(self._obs_data[ind_rain])
205
- else:
206
- downsample[i, j] = np.nan
182
+ """Calculates average iwc value for each grid point."""
183
+ for key, down_sample in storage.items():
184
+ down_sample[i, j] = ma.masked
185
+ if "rain" not in key:
186
+ no_rain_data = self._obs_data[ind_no_rain]
187
+ if ind_no_rain.any() and not no_rain_data.mask.all():
188
+ down_sample[i, j] = ma.mean(no_rain_data)
189
+ if "rain" in key:
190
+ rain_data = self._obs_data[ind_rain]
191
+ if ind_rain.any() and not rain_data.mask.all():
192
+ down_sample[i, j] = ma.mean(rain_data)
207
193
  if "att" in key:
208
- iwc_att = self._obs_obj.data["iwc_att"][:]
209
- if iwc_att[ind_no_rain].mask.all():
210
- downsample[i, j] = np.nan
211
- else:
212
- downsample[i, j] = np.nanmean(iwc_att[ind_no_rain])
213
- storage[key] = downsample
194
+ no_rain_att_data = self._obs_obj.data["iwc_att"][ind_no_rain]
195
+ if ind_no_rain.any() and not no_rain_att_data.mask.all():
196
+ down_sample[i, j] = ma.mean(no_rain_att_data)
197
+ storage[key] = down_sample
214
198
  return storage
215
199
 
216
200
  def _regrid_product(self, storage: dict, i: int, j: int, ind: np.ndarray) -> dict:
217
- """Calculates average of standard product value to grid point"""
201
+ """Calculates average of standard product value for each grid point."""
218
202
  for key, down_sample in storage.items():
219
- if not self._obs_data[ind].mask.all() and ind.any():
220
- if np.isnan(self._obs_data[ind]).all():
221
- down_sample[i, j] = np.nan
222
- else:
223
- down_sample[i, j] = np.nanmean(self._obs_data[ind])
224
- else:
225
- down_sample[i, j] = np.nan
203
+ obs_data_selected = ma.masked_invalid(self._obs_data[ind])
204
+ down_sample[i, j] = (
205
+ ma.mean(obs_data_selected)
206
+ if not obs_data_selected.mask.all()
207
+ else ma.masked
208
+ )
226
209
  storage[key] = down_sample
227
210
  return storage
228
211
 
@@ -3,6 +3,7 @@ from datetime import date
3
3
  import netCDF4
4
4
  import numpy as np
5
5
  import pytest
6
+ from numpy import ma
6
7
 
7
8
 
8
9
  @pytest.fixture(scope="session")
@@ -28,7 +29,7 @@ def model_file(tmpdir_factory, file_metadata) -> str:
28
29
  root_grp.createDimension("level", level)
29
30
  _create_global_attributes(root_grp, file_metadata)
30
31
  var = root_grp.createVariable("time", "f8", "time")
31
- var[:] = np.array([2, 6, 10])
32
+ var[:] = ma.array([2, 6, 10])
32
33
  var = root_grp.createVariable("level", "f8", "level")
33
34
  var[:] = level
34
35
  var = root_grp.createVariable("latitude", "f8")
@@ -38,24 +39,24 @@ def model_file(tmpdir_factory, file_metadata) -> str:
38
39
  var = root_grp.createVariable("horizontal_resolution", "f8")
39
40
  var[:] = 9
40
41
  var = root_grp.createVariable("height", "f8", ("time", "level"))
41
- var[:] = np.array([[10, 14], [8, 14], [9, 15]])
42
+ var[:] = ma.array([[10, 14], [8, 14], [9, 15]])
42
43
  var.units = "km"
43
44
  var = root_grp.createVariable("forecast_time", "f8", "time")
44
- var[:] = np.array([1, 5, 10])
45
+ var[:] = ma.array([1, 5, 10])
45
46
  var = root_grp.createVariable("cloud_fraction", "f8", ("time", "level"))
46
- var[:] = np.array([[0, 2], [3, 6], [5, 8]])
47
+ var[:] = ma.array([[0, 2], [3, 6], [5, 8]])
47
48
  var = root_grp.createVariable("qi", "f8", ("time", "level"))
48
- var[:] = np.array([[0.01, 0.00], [0.02, 0.03], [0.06, 0.08]])
49
+ var[:] = ma.array([[0.01, 0.00], [0.02, 0.03], [0.06, 0.08]])
49
50
  var = root_grp.createVariable("ql", "f8", ("time", "level"))
50
- var[:] = np.array([[0.008, 0.09], [0.004, 0.007], [0.0001, 0.0002]])
51
+ var[:] = ma.array([[0.008, 0.09], [0.004, 0.007], [0.0001, 0.0002]])
51
52
  var = root_grp.createVariable("temperature", "f8", ("time", "level"))
52
- var[:] = np.array([[300, 301], [302, 299], [305, 298]])
53
+ var[:] = ma.array([[300, 301], [302, 299], [305, 298]])
53
54
  var = root_grp.createVariable("pressure", "f8", ("time", "level"))
54
- var[:] = np.array([[1000, 1001], [1010, 1003], [1020, 1005]])
55
+ var[:] = ma.array([[1000, 1001], [1010, 1003], [1020, 1005]])
55
56
  var = root_grp.createVariable("uwind", "f8", ("time", "level"))
56
- var[:] = np.array([[1, 2], [2, 2], [3, 1]])
57
+ var[:] = ma.array([[1, 2], [2, 2], [3, 1]])
57
58
  var = root_grp.createVariable("vwind", "f8", ("time", "level"))
58
- var[:] = np.array([[3, 1], [2, 1], [5, 2]])
59
+ var[:] = ma.array([[3, 1], [2, 1], [5, 2]])
59
60
  root_grp.close()
60
61
  return file_name
61
62
 
@@ -70,9 +71,9 @@ def obs_file(tmpdir_factory, file_metadata) -> str:
70
71
  root_grp.createDimension("height", height)
71
72
  _create_global_attributes(root_grp, file_metadata)
72
73
  var = root_grp.createVariable("time", "f8", "time")
73
- var[:] = np.array([0, 2, 4, 6, 8, 10])
74
+ var[:] = ma.array([0, 2, 4, 6, 8, 10])
74
75
  var = root_grp.createVariable("height", "f8", "height")
75
- var[:] = np.array([8, 9, 12, 15])
76
+ var[:] = ma.array([8, 9, 12, 15])
76
77
  var.units = "km"
77
78
  var = root_grp.createVariable("latitude", "f8")
78
79
  var[:] = 1
@@ -84,11 +85,11 @@ def obs_file(tmpdir_factory, file_metadata) -> str:
84
85
  var = root_grp.createVariable("radar_frequency", "f8")
85
86
  var[:] = 35.5
86
87
  var = root_grp.createVariable("rainrate", "i4", "time")
87
- var[:] = np.array([1, 2, 0, 10, 5, 13])
88
+ var[:] = ma.array([1, 2, 0, 10, 5, 13])
88
89
  var = root_grp.createVariable("Z_sensitivity", "f8", "height")
89
- var[:] = np.array([0.1, 0.2, 0.0, 1.0])
90
+ var[:] = ma.array([0.1, 0.2, 0.0, 1.0])
90
91
  var = root_grp.createVariable("category_bits", "i4", ("time", "height"))
91
- var[:] = np.array(
92
+ var[:] = ma.array(
92
93
  [
93
94
  [0, 1, 2, 0],
94
95
  [2, 8, 4, 1],
@@ -99,7 +100,7 @@ def obs_file(tmpdir_factory, file_metadata) -> str:
99
100
  ],
100
101
  )
101
102
  var = root_grp.createVariable("quality_bits", "i4", ("time", "height"))
102
- var[:] = np.array(
103
+ var[:] = ma.array(
103
104
  [
104
105
  [0, 1, 2, 4],
105
106
  [8, 16, 32, 16],
@@ -110,7 +111,7 @@ def obs_file(tmpdir_factory, file_metadata) -> str:
110
111
  ],
111
112
  )
112
113
  var = root_grp.createVariable("iwc", "f8", ("time", "height"))
113
- var[:] = np.array(
114
+ var[:] = ma.array(
114
115
  [
115
116
  [0.01, 0.02, 0.06, 0.01],
116
117
  [0.02, 0.06, 0.00, 0.03],
@@ -121,7 +122,7 @@ def obs_file(tmpdir_factory, file_metadata) -> str:
121
122
  ],
122
123
  )
123
124
  var = root_grp.createVariable("iwc_retrieval_status", "f8", ("time", "height"))
124
- var[:] = np.array(
125
+ var[:] = ma.array(
125
126
  [
126
127
  [1, 2, 6, 1],
127
128
  [2, 6, 5, 3],
@@ -132,7 +133,7 @@ def obs_file(tmpdir_factory, file_metadata) -> str:
132
133
  ],
133
134
  )
134
135
  var = root_grp.createVariable("lwc", "f8", ("time", "height"))
135
- var[:] = np.array(
136
+ var[:] = ma.array(
136
137
  [
137
138
  [0.08, 0.04, 0.01, 0.08],
138
139
  [0.04, 0.01, 0.09, 0.07],
@@ -143,7 +144,7 @@ def obs_file(tmpdir_factory, file_metadata) -> str:
143
144
  ],
144
145
  )
145
146
  var = root_grp.createVariable("data", "i4", ("time", "height"))
146
- var[:] = np.array(
147
+ var[:] = ma.array(
147
148
  [
148
149
  [2, 4, 3, 6],
149
150
  [7, 1, 9, 7],
@@ -167,7 +168,7 @@ def regrid_file(tmpdir_factory, file_metadata) -> str:
167
168
  root_grp.createDimension("level", level)
168
169
  _create_global_attributes(root_grp, file_metadata)
169
170
  var = root_grp.createVariable("time", "f8", "time")
170
- var[:] = np.array([2, 6, 10])
171
+ var[:] = ma.array([2, 6, 10])
171
172
  var = root_grp.createVariable("level", "f8", "level")
172
173
  var[:] = level
173
174
  var = root_grp.createVariable("latitude", "f8")
@@ -177,23 +178,23 @@ def regrid_file(tmpdir_factory, file_metadata) -> str:
177
178
  var = root_grp.createVariable("horizontal_resolution", "f8")
178
179
  var[:] = 9
179
180
  var = root_grp.createVariable("ecmwf_height", "f8", ("time", "level"))
180
- var[:] = np.array([[10, 14], [8, 14], [9, 15]])
181
+ var[:] = ma.array([[10, 14], [8, 14], [9, 15]])
181
182
  var = root_grp.createVariable("ecmwf_forecast_time", "f8", "time")
182
- var[:] = np.array([1, 5, 10])
183
+ var[:] = ma.array([1, 5, 10])
183
184
  var = root_grp.createVariable("ecmwf_cf", "f8", ("time", "level"))
184
- var[:] = np.array([[0, 2], [3, 6], [5, 8]])
185
+ var[:] = ma.array([[0, 2], [3, 6], [5, 8]])
185
186
  var = root_grp.createVariable("ecmwf_cf_cirrus", "f8", ("time", "level"))
186
- var[:] = np.array([[0, 2], [3, 6], [5, 7]])
187
+ var[:] = ma.array([[0, 2], [3, 6], [5, 7]])
187
188
  var = root_grp.createVariable("ecmwf_cf_snow", "f8", ("time", "level"))
188
- var[:] = np.array([[0, 2], [4, 6], [5, 8]])
189
+ var[:] = ma.array([[0, 2], [4, 6], [5, 8]])
189
190
  var = root_grp.createVariable("cf_ecmwf", "f8", ("time", "level"))
190
- var[:] = np.array([[0, 2], [3, 6], [5, 8]])
191
+ var[:] = ma.array([[0, 2], [3, 6], [5, 8]])
191
192
  var = root_grp.createVariable("cf_adv_ecmwf", "f8", ("time", "level"))
192
- var[:] = np.array([[0, 2], [3, 6], [5, 8]])
193
+ var[:] = ma.array([[0, 2], [3, 6], [5, 8]])
193
194
  var = root_grp.createVariable("temperature", "f8", ("time", "level"))
194
- var[:] = np.array([[300, 301], [302, 299], [305, 298]])
195
+ var[:] = ma.array([[300, 301], [302, 299], [305, 298]])
195
196
  var = root_grp.createVariable("pressure", "f8", ("time", "level"))
196
- var[:] = np.array([[1000, 1001], [1010, 1003], [1020, 1005]])
197
+ var[:] = ma.array([[1000, 1001], [1010, 1003], [1020, 1005]])
197
198
  root_grp.close()
198
199
  return file_name
199
200
 
@@ -248,31 +248,6 @@ def test_gamma_distribution(obs_file, model_file) -> None:
248
248
  testing.assert_array_almost_equal(x, compare)
249
249
 
250
250
 
251
- def test_get_observation_index(obs_file, model_file) -> None:
252
- obs = ObservationManager(PRODUCT, str(obs_file))
253
- model = ModelManager(str(model_file), MODEL, OUTPUT_FILE, PRODUCT)
254
- adv_pro = AdvanceProductMethods(model, str(model_file), obs)
255
- tZT = 0.01
256
- z_sen = 0.02
257
- temperature = -13
258
- tT = 0.04
259
- tZ = 0.05
260
- t = 0.06
261
- min_iwc = 10 ** (tZT * z_sen * temperature + tT * temperature + tZ * z_sen + t)
262
- iwc_dist = np.array([0.1, 0.2, 0.3, 0.4, 0.5, 0.6])
263
- compare = iwc_dist > min_iwc
264
- x = adv_pro.get_observation_index(
265
- iwc_dist,
266
- tZT,
267
- tT,
268
- tZ,
269
- np.array([t]),
270
- temperature,
271
- z_sen,
272
- )
273
- testing.assert_array_almost_equal(x, compare)
274
-
275
-
276
251
  def test_filter_cirrus(obs_file, model_file) -> None:
277
252
  obs = ObservationManager(PRODUCT, str(obs_file))
278
253
  model = ModelManager(str(model_file), MODEL, OUTPUT_FILE, PRODUCT)
@@ -122,7 +122,7 @@ def test_regrid_cf_area(model_file, obs_file) -> None:
122
122
  model = ModelManager(str(model_file), MODEL, OUTPUT_FILE, PRODUCT)
123
123
  obj = ProductGrid(model, obs)
124
124
  data = ma.array([[1, 1, 1], [0, 1, 1], [0, 0, 1], [0, 0, 0]])
125
- d = {"cf_A": np.zeros((1, 1))}
125
+ d = {"cf_A": ma.zeros((1, 1))}
126
126
  d = obj._regrid_cf(d, 0, 0, data)
127
127
  x = d["cf_A"]
128
128
  assert x[0, 0] == 0.75
@@ -134,7 +134,7 @@ def test_regrid_cf_area_masked(model_file, obs_file) -> None:
134
134
  obj = ProductGrid(model, obs)
135
135
  data = ma.array([[1, 1, 1], [0, 1, 1], [0, 0, 1], [0, 0, 0]])
136
136
  data[1, :] = ma.masked
137
- d = {"cf_A": np.zeros((1, 1))}
137
+ d = {"cf_A": ma.zeros((1, 1))}
138
138
  d = obj._regrid_cf(d, 0, 0, data)
139
139
  x = d["cf_A"]
140
140
  assert round(x[0, 0], 3) == 0.667
@@ -146,18 +146,19 @@ def test_regrid_cf_area_all_masked(model_file, obs_file) -> None:
146
146
  obj = ProductGrid(model, obs)
147
147
  data = ma.array([[1, 1, 1], [0, 1, 1], [0, 0, 1], [0, 0, 0]])
148
148
  data[:, :] = ma.masked
149
- d = {"cf_A": np.zeros((1, 1))}
149
+ d = {"cf_A": ma.zeros((1, 1))}
150
150
  d = obj._regrid_cf(d, 0, 0, data)
151
151
  x = d["cf_A"]
152
- testing.assert_equal(x, np.nan)
152
+ testing.assert_equal(x, ma.masked)
153
153
 
154
154
 
155
155
  def test_regrid_cf_area_nan(model_file, obs_file) -> None:
156
156
  obs = ObservationManager(PRODUCT, str(obs_file))
157
157
  model = ModelManager(str(model_file), MODEL, OUTPUT_FILE, PRODUCT)
158
158
  obj = ProductGrid(model, obs)
159
- data = ma.array([[1, np.nan, 1], [0, 1, 1], [np.nan, 0, 1], [0, 0, 0]])
160
- d = {"cf_A": np.zeros((1, 1))}
159
+ data = ma.array([[1, 99, 1], [0, 1, 1], [99, 0, 1], [0, 0, 0]])
160
+ data = ma.masked_where(data == 99, data)
161
+ d = {"cf_A": ma.zeros((1, 1))}
161
162
  d = obj._regrid_cf(d, 0, 0, data)
162
163
  x = d["cf_A"]
163
164
  assert x[0, 0] == 0.75
@@ -169,18 +170,16 @@ def test_regrid_cf_area_all_nan(model_file, obs_file) -> None:
169
170
  obj = ProductGrid(model, obs)
170
171
  data = ma.array(
171
172
  [
172
- [np.nan, np.nan, np.nan],
173
- [np.nan, np.nan, np.nan],
174
- [np.nan, np.nan, np.nan],
175
- [np.nan, np.nan, np.nan],
176
- ],
173
+ [1, 1, 1],
174
+ [1, 1, 1],
175
+ [1, 1, 1],
176
+ [1, 1, 1],
177
+ ], mask=True
177
178
  )
178
- d = {"cf_A": np.zeros((1, 1))}
179
+ d = {"cf_A": ma.zeros((1, 1))}
179
180
  d = obj._regrid_cf(d, 0, 0, data)
180
181
  x = d["cf_A"]
181
- # Not sure if this should be nan or 0 (Simo)
182
- # testing.assert_equal(x, 0.0)
183
- testing.assert_equal(x, np.nan)
182
+ testing.assert_equal(x, ma.masked)
184
183
 
185
184
 
186
185
  def test_regrid_cf_volume(model_file, obs_file) -> None:
@@ -188,7 +187,7 @@ def test_regrid_cf_volume(model_file, obs_file) -> None:
188
187
  model = ModelManager(str(model_file), MODEL, OUTPUT_FILE, PRODUCT)
189
188
  obj = ProductGrid(model, obs)
190
189
  data = ma.array([[1, 1, 1], [0, 1, 1], [0, 0, 1], [0, 0, 0]])
191
- d = {"cf_V": np.zeros((1, 1))}
190
+ d = {"cf_V": ma.zeros((1, 1))}
192
191
  d = obj._regrid_cf(d, 0, 0, data)
193
192
  x = d["cf_V"]
194
193
  assert x[0, 0] == 0.5
@@ -198,8 +197,9 @@ def test_regrid_cf_volume_nan(model_file, obs_file) -> None:
198
197
  obs = ObservationManager(PRODUCT, str(obs_file))
199
198
  model = ModelManager(str(model_file), MODEL, OUTPUT_FILE, PRODUCT)
200
199
  obj = ProductGrid(model, obs)
201
- data = ma.array([[1, np.nan, 1], [0, 1, 1], [np.nan, 0, 1], [0, 0, 0]])
202
- d = {"cf_V": np.zeros((1, 1))}
200
+ data = ma.array([[1, 99, 1], [0, 1, 1], [99, 0, 1], [0, 0, 0]])
201
+ data = ma.masked_where(data == 99, data)
202
+ d = {"cf_V": ma.zeros((1, 1))}
203
203
  d = obj._regrid_cf(d, 0, 0, data)
204
204
  x = d["cf_V"]
205
205
  assert x[0, 0] == 0.5
@@ -211,16 +211,17 @@ def test_regrid_cf_volume_all_nan(model_file, obs_file) -> None:
211
211
  obj = ProductGrid(model, obs)
212
212
  data = ma.array(
213
213
  [
214
- [np.nan, np.nan, np.nan],
215
- [np.nan, np.nan, np.nan],
216
- [np.nan, np.nan, np.nan],
217
- [np.nan, np.nan, np.nan],
214
+ [99, 99, 99],
215
+ [99, 99, 99],
216
+ [99, 99, 99],
217
+ [99, 99, 99],
218
218
  ],
219
219
  )
220
- d = {"cf_V": np.zeros((1, 1))}
220
+ data = ma.masked_where(data == 99, data)
221
+ d = {"cf_V": ma.zeros((1, 1))}
221
222
  d = obj._regrid_cf(d, 0, 0, data)
222
223
  x = d["cf_V"]
223
- testing.assert_equal(x, np.nan)
224
+ testing.assert_equal(x, ma.masked)
224
225
 
225
226
 
226
227
  def test_regrid_cf_volume_masked(model_file, obs_file) -> None:
@@ -229,7 +230,7 @@ def test_regrid_cf_volume_masked(model_file, obs_file) -> None:
229
230
  obj = ProductGrid(model, obs)
230
231
  data = ma.array([[1, 1, 1], [0, 1, 1], [0, 0, 1], [0, 0, 0]])
231
232
  data[1, :] = ma.masked
232
- d = {"cf_V": np.zeros((1, 1))}
233
+ d = {"cf_V": ma.zeros((1, 1))}
233
234
  d = obj._regrid_cf(d, 0, 0, data)
234
235
  x = d["cf_V"]
235
236
  assert round(x[0, 0], 3) == 0.444
@@ -241,10 +242,10 @@ def test_regrid_cf_volume_all_masked(model_file, obs_file) -> None:
241
242
  obj = ProductGrid(model, obs)
242
243
  data = ma.array([[1, 1, 1], [0, 1, 1], [0, 0, 1], [0, 0, 0]])
243
244
  data[:, :] = ma.masked
244
- d = {"cf_V": np.zeros((1, 1))}
245
+ d = {"cf_V": ma.zeros((1, 1))}
245
246
  d = obj._regrid_cf(d, 0, 0, data)
246
247
  x = d["cf_V"]
247
- testing.assert_equal(x, np.nan)
248
+ testing.assert_equal(x, ma.masked)
248
249
 
249
250
 
250
251
  def test_reshape_data_to_window(model_file, obs_file) -> None:
@@ -338,7 +339,7 @@ def test_regrid_iwc(model_file, obs_file) -> None:
338
339
  model = ModelManager(str(model_file), MODEL, OUTPUT_FILE, PRODUCT)
339
340
  obj = ProductGrid(model, obs)
340
341
  obj._obs_data = ma.array([[1, 1, 1, 1], [2, 2, 2, 2], [3, 3, 3, 3], [4, 4, 4, 3]])
341
- d = {"iwc": np.zeros((1, 1))}
342
+ d = {"iwc": ma.zeros((1, 1))}
342
343
  ind = ma.array([[0, 1, 1, 1]], dtype=bool)
343
344
  no_rain = ma.array(
344
345
  [[0, 1, 1, 1], [0, 0, 1, 1], [0, 0, 0, 0], [0, 0, 0, 0]],
@@ -354,9 +355,10 @@ def test_regrid_iwc_nan(model_file, obs_file) -> None:
354
355
  model = ModelManager(str(model_file), MODEL, OUTPUT_FILE, PRODUCT)
355
356
  obj = ProductGrid(model, obs)
356
357
  obj._obs_data = ma.array(
357
- [[1, 1, np.nan, 1], [2, np.nan, 2, 2], [3, 3, 3, 3], [4, 4, 4, np.nan]],
358
+ [[1, 1, 99, 1], [2, 99, 2, 2], [3, 3, 3, 3], [4, 4, 4, 99]],
358
359
  )
359
- d = {"iwc": np.zeros((1, 1))}
360
+ obj._obs_data = ma.masked_where(obj._obs_data == 99, obj._obs_data)
361
+ d = {"iwc": ma.zeros((1, 1))}
360
362
  ind = ma.array([[0, 1, 1, 1]], dtype=bool)
361
363
  no_rain = ma.array(
362
364
  [[0, 1, 1, 1], [0, 0, 1, 1], [0, 0, 0, 0], [0, 0, 0, 0]],
@@ -373,21 +375,21 @@ def test_regrid_iwc_all_nan(model_file, obs_file) -> None:
373
375
  obj = ProductGrid(model, obs)
374
376
  obj._obs_data = ma.array(
375
377
  [
376
- [np.nan, np.nan, np.nan, np.nan],
377
- [np.nan, np.nan, np.nan, np.nan],
378
- [np.nan, np.nan, np.nan, np.nan],
379
- [np.nan, np.nan, np.nan, np.nan],
378
+ [99, 99, 99, 99],
379
+ [99, 99, 99, 99],
380
+ [99, 99, 99, 99],
381
+ [99, 99, 99, 99],
380
382
  ],
381
383
  )
382
- d = {"iwc": np.zeros((1, 1))}
384
+ obj._obs_data = ma.masked_where(obj._obs_data == 99, obj._obs_data)
385
+ d = {"iwc": ma.zeros((1, 1))}
383
386
  ind = ma.array([[0, 1, 1, 1]], dtype=bool)
384
387
  no_rain = ma.array(
385
388
  [[0, 1, 1, 1], [0, 0, 1, 1], [0, 0, 0, 0], [0, 0, 0, 0]],
386
389
  dtype=bool,
387
390
  )
388
391
  d = obj._regrid_iwc(d, 0, 0, ind, no_rain)
389
- x = d["iwc"]
390
- testing.assert_almost_equal(x[0, 0], np.nan)
392
+ assert d["iwc"][0, 0].mask == True
391
393
 
392
394
 
393
395
  def test_regrid_iwc_masked(model_file, obs_file) -> None:
@@ -396,7 +398,7 @@ def test_regrid_iwc_masked(model_file, obs_file) -> None:
396
398
  obj = ProductGrid(model, obs)
397
399
  obj._obs_data = ma.array([[1, 1, 1, 1], [2, 2, 2, 2], [3, 3, 3, 3], [4, 4, 4, 4]])
398
400
  obj._obs_data[1, :] = ma.masked
399
- d = {"iwc": np.zeros((1, 1))}
401
+ d = {"iwc": ma.zeros((1, 1))}
400
402
  ind = ma.array([[0, 1, 1, 1]], dtype=bool)
401
403
  no_rain = ma.array(
402
404
  [[0, 1, 1, 1], [0, 0, 1, 1], [0, 0, 0, 0], [0, 0, 0, 0]],
@@ -411,17 +413,15 @@ def test_regrid_iwc_all_masked(model_file, obs_file) -> None:
411
413
  obs = ObservationManager(PRODUCT, str(obs_file))
412
414
  model = ModelManager(str(model_file), MODEL, OUTPUT_FILE, PRODUCT)
413
415
  obj = ProductGrid(model, obs)
414
- obj._obs_data = ma.array([[1, 1, 1, 1], [2, 2, 2, 2], [3, 3, 3, 3], [4, 4, 4, 4]])
415
- obj._obs_data[:, :] = ma.masked
416
- d = {"iwc": np.zeros((1, 1))}
416
+ obj._obs_data = ma.array([[1, 1, 1, 1], [2, 2, 2, 2], [3, 3, 3, 3], [4, 4, 4, 4]], mask=True)
417
+ d = {"iwc": ma.zeros((1, 1))}
417
418
  ind = ma.array([[0, 1, 1, 1]], dtype=bool)
418
419
  no_rain = ma.array(
419
420
  [[0, 1, 1, 1], [0, 0, 1, 1], [0, 0, 0, 0], [0, 0, 0, 0]],
420
421
  dtype=bool,
421
422
  )
422
423
  d = obj._regrid_iwc(d, 0, 0, ind, no_rain)
423
- x = d["iwc"]
424
- testing.assert_almost_equal(x[0, 0], np.nan)
424
+ assert d["iwc"][0, 0].mask == True
425
425
 
426
426
 
427
427
  def test_regrid_iwc_none(model_file, obs_file) -> None:
@@ -429,22 +429,21 @@ def test_regrid_iwc_none(model_file, obs_file) -> None:
429
429
  model = ModelManager(str(model_file), MODEL, OUTPUT_FILE, PRODUCT)
430
430
  obj = ProductGrid(model, obs)
431
431
  obj._obs_data = ma.array([[1, 1, 1, 1], [2, 2, 2, 2], [3, 3, 3, 3], [4, 4, 4, 4]])
432
- d = {"iwc": np.zeros((1, 1))}
432
+ d = {"iwc": ma.zeros((1, 1))}
433
433
  ind = ma.array([[0, 1, 1, 1]], dtype=bool)
434
434
  no_rain = ma.array(
435
435
  [[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]],
436
436
  dtype=bool,
437
437
  )
438
438
  d = obj._regrid_iwc(d, 0, 0, ind, no_rain)
439
- x = d["iwc"]
440
- testing.assert_equal(x[0, 0], np.nan)
439
+ assert d["iwc"][0, 0].mask == True
441
440
 
442
441
 
443
442
  def test_regrid_iwc_att(model_file, obs_file) -> None:
444
443
  obs = ObservationManager(PRODUCT, str(obs_file))
445
444
  model = ModelManager(str(model_file), MODEL, OUTPUT_FILE, PRODUCT)
446
445
  obj = ProductGrid(model, obs)
447
- d = {"iwc_att": np.zeros((1, 1))}
446
+ d = {"iwc_att": ma.zeros((1, 1))}
448
447
  ind = ma.array([[0, 1, 1, 1]], dtype=bool)
449
448
  no_rain = ma.array(
450
449
  [
@@ -477,7 +476,7 @@ def test_regrid_iwc_att_masked(model_file, obs_file) -> None:
477
476
  ],
478
477
  dtype=bool,
479
478
  )
480
- d = {"iwc_att": np.zeros((1, 1))}
479
+ d = {"iwc_att": ma.zeros((1, 1))}
481
480
  ind = ma.array([[0, 1, 1, 1]], dtype=bool)
482
481
  no_rain = ma.array(
483
482
  [
@@ -510,7 +509,7 @@ def test_regrid_iwc_att_all_masked(model_file, obs_file) -> None:
510
509
  ],
511
510
  dtype=bool,
512
511
  )
513
- d = {"iwc_att": np.zeros((1, 1))}
512
+ d = {"iwc_att": ma.zeros((1, 1))}
514
513
  ind = ma.array([[0, 1, 1, 1]], dtype=bool)
515
514
  no_rain = ma.array(
516
515
  [
@@ -525,14 +524,15 @@ def test_regrid_iwc_att_all_masked(model_file, obs_file) -> None:
525
524
  )
526
525
  d = obj._regrid_iwc(d, 0, 0, ind, no_rain)
527
526
  x = d["iwc_att"]
528
- testing.assert_almost_equal(x[0, 0], np.nan)
527
+ # Simo: not sure if this should be masked or not
528
+ assert x[0, 0] == 0.01
529
529
 
530
530
 
531
531
  def test_regrid_iwc_att_none(model_file, obs_file) -> None:
532
532
  obs = ObservationManager(PRODUCT, str(obs_file))
533
533
  model = ModelManager(str(model_file), MODEL, OUTPUT_FILE, PRODUCT)
534
534
  obj = ProductGrid(model, obs)
535
- d = {"iwc_att": np.zeros((1, 1))}
535
+ d = {"iwc_att": ma.zeros((1, 1))}
536
536
  ind = ma.array([[0, 1, 1, 1]], dtype=bool)
537
537
  no_rain = ma.array(
538
538
  [
@@ -547,7 +547,7 @@ def test_regrid_iwc_att_none(model_file, obs_file) -> None:
547
547
  )
548
548
  d = obj._regrid_iwc(d, 0, 0, ind, no_rain)
549
549
  x = d["iwc_att"]
550
- assert np.isnan(x[0, 0])
550
+ assert x[0, 0].mask == True
551
551
 
552
552
 
553
553
  def test_regrid_iwc_rain(model_file, obs_file) -> None:
@@ -555,7 +555,7 @@ def test_regrid_iwc_rain(model_file, obs_file) -> None:
555
555
  model = ModelManager(str(model_file), MODEL, OUTPUT_FILE, PRODUCT)
556
556
  obj = ProductGrid(model, obs)
557
557
  obj._obs_data = ma.array([[1, 1, 1, 1], [2, 2, 2, 2], [3, 3, 3, 3], [4, 4, 4, 3]])
558
- d = {"iwc_rain": np.zeros((1, 1))}
558
+ d = {"iwc_rain": ma.zeros((1, 1))}
559
559
  ind = ma.array([[0, 1, 1, 1], [0, 0, 1, 1], [0, 1, 1, 1], [0, 0, 1, 1]], dtype=bool)
560
560
  no_rain = ma.array(
561
561
  [[0, 1, 1, 1], [0, 0, 1, 1], [0, 1, 1, 1], [0, 0, 1, 1]],
@@ -572,13 +572,14 @@ def test_regrid_iwc_rain_nan(model_file, obs_file) -> None:
572
572
  obj = ProductGrid(model, obs)
573
573
  obj._obs_data = ma.array(
574
574
  [
575
- [1, np.nan, 1, 1],
576
- [2, 2, 2, np.nan],
575
+ [1, 99, 1, 1],
576
+ [2, 2, 2, 99],
577
577
  [3, 3, 3, 3],
578
- [np.nan, 4, 4, np.nan],
578
+ [99, 4, 4, 99],
579
579
  ],
580
580
  )
581
- d = {"iwc_rain": np.zeros((1, 1))}
581
+ obj._obs_data = ma.masked_where(obj._obs_data == 99, obj._obs_data)
582
+ d = {"iwc_rain": ma.zeros((1, 1))}
582
583
  ind = ma.array([[0, 1, 1, 1], [0, 0, 1, 1], [0, 1, 1, 1], [0, 0, 1, 1]], dtype=bool)
583
584
  no_rain = ma.array(
584
585
  [[0, 1, 1, 1], [0, 0, 1, 1], [0, 1, 1, 1], [0, 0, 1, 1]],
@@ -595,13 +596,14 @@ def test_regrid_iwc_rain_all_nan(model_file, obs_file) -> None:
595
596
  obj = ProductGrid(model, obs)
596
597
  obj._obs_data = ma.array(
597
598
  [
598
- [np.nan, np.nan, np.nan, np.nan],
599
- [np.nan, np.nan, np.nan, np.nan],
600
- [np.nan, np.nan, np.nan, np.nan],
601
- [np.nan, np.nan, np.nan, np.nan],
599
+ [99, 99, 99, 99],
600
+ [99, 99, 99, 99],
601
+ [99, 99, 99, 99],
602
+ [99, 99, 99, 99],
602
603
  ],
603
604
  )
604
- d = {"iwc_rain": np.zeros((1, 1))}
605
+ obj._obs_data = ma.masked_where(obj._obs_data == 99, obj._obs_data)
606
+ d = {"iwc_rain": ma.zeros((1, 1))}
605
607
  ind = ma.array([[0, 1, 1, 1], [0, 0, 1, 1], [0, 1, 1, 1], [0, 0, 1, 1]], dtype=bool)
606
608
  no_rain = ma.array(
607
609
  [[0, 1, 1, 1], [0, 0, 1, 1], [0, 1, 1, 1], [0, 0, 1, 1]],
@@ -609,7 +611,7 @@ def test_regrid_iwc_rain_all_nan(model_file, obs_file) -> None:
609
611
  )
610
612
  d = obj._regrid_iwc(d, 0, 0, ind, no_rain)
611
613
  x = d["iwc_rain"]
612
- testing.assert_almost_equal(x[0, 0], np.nan)
614
+ assert x[0, 0].mask == True
613
615
 
614
616
 
615
617
  def test_regrid_iwc_rain_masked(model_file, obs_file) -> None:
@@ -618,7 +620,7 @@ def test_regrid_iwc_rain_masked(model_file, obs_file) -> None:
618
620
  obj = ProductGrid(model, obs)
619
621
  obj._obs_data = ma.array([[1, 1, 1, 1], [2, 2, 2, 2], [3, 3, 3, 3], [4, 4, 4, 4]])
620
622
  obj._obs_data[2, :] = ma.masked
621
- d = {"iwc_rain": np.zeros((1, 1))}
623
+ d = {"iwc_rain": ma.zeros((1, 1))}
622
624
  ind = ma.array([[0, 1, 1, 1], [0, 0, 1, 1], [0, 1, 1, 1], [0, 0, 1, 1]], dtype=bool)
623
625
  no_rain = ma.array(
624
626
  [[0, 1, 1, 1], [0, 0, 1, 1], [0, 1, 1, 1], [0, 0, 1, 1]],
@@ -635,7 +637,7 @@ def test_regrid_iwc_rain_all_masked(model_file, obs_file) -> None:
635
637
  obj = ProductGrid(model, obs)
636
638
  obj._obs_data = ma.array([[1, 3, 1, 1], [2, 2, 2, 2], [3, 3, 3, 3], [4, 4, 4, 4]])
637
639
  obj._obs_data[:, :] = ma.masked
638
- d = {"iwc_rain": np.zeros((1, 1))}
640
+ d = {"iwc_rain": ma.zeros((1, 1))}
639
641
  ind = ma.array([[0, 1, 1, 1], [0, 0, 1, 1], [0, 1, 1, 1], [0, 0, 1, 1]], dtype=bool)
640
642
  no_rain = ma.array(
641
643
  [[0, 1, 1, 1], [0, 0, 1, 1], [0, 1, 1, 1], [0, 0, 1, 1]],
@@ -643,7 +645,7 @@ def test_regrid_iwc_rain_all_masked(model_file, obs_file) -> None:
643
645
  )
644
646
  d = obj._regrid_iwc(d, 0, 0, ind, no_rain)
645
647
  x = d["iwc_rain"]
646
- testing.assert_equal(x[0, 0], np.nan)
648
+ assert x[0, 0].mask == True
647
649
 
648
650
 
649
651
  def test_regrid_product(model_file, obs_file) -> None:
@@ -651,7 +653,7 @@ def test_regrid_product(model_file, obs_file) -> None:
651
653
  model = ModelManager(str(model_file), MODEL, OUTPUT_FILE, "lwc")
652
654
  obj = ProductGrid(model, obs)
653
655
  obj._obs_data = ma.array([[1, 1, 1, 1], [2, 1, 2, 2], [3, 3, 3, 3], [4, 4, 4, 4]])
654
- d = {"lwc": np.zeros((1, 1))}
656
+ d = {"lwc": ma.zeros((1, 1))}
655
657
  ind = ma.array([[0, 1, 1, 1], [0, 0, 1, 1], [0, 0, 0, 0], [0, 0, 0, 0]], dtype=bool)
656
658
  d = obj._regrid_product(d, 0, 0, ind)
657
659
  x = d["lwc"]
@@ -664,13 +666,14 @@ def test_regrid_product_nan(model_file, obs_file) -> None:
664
666
  obj = ProductGrid(model, obs)
665
667
  obj._obs_data = ma.array(
666
668
  [
667
- [1, np.nan, 1, 1],
668
- [np.nan, 1, 2, 2],
669
- [3, 3, np.nan, 3],
670
- [4, np.nan, 4, 4],
669
+ [1, 99, 1, 1],
670
+ [99, 1, 2, 2],
671
+ [3, 3, 99, 3],
672
+ [4, 99, 4, 4],
671
673
  ],
672
674
  )
673
- d = {"lwc": np.zeros((1, 1))}
675
+ obj._obs_data = ma.masked_where(obj._obs_data == 99, obj._obs_data)
676
+ d = {"lwc": ma.zeros((1, 1))}
674
677
  ind = ma.array([[0, 1, 1, 1], [0, 0, 1, 1], [0, 0, 0, 0], [0, 0, 0, 0]], dtype=bool)
675
678
  d = obj._regrid_product(d, 0, 0, ind)
676
679
  x = d["lwc"]
@@ -681,19 +684,19 @@ def test_regrid_product_all_nan(model_file, obs_file) -> None:
681
684
  obs = ObservationManager("lwc", str(obs_file))
682
685
  model = ModelManager(str(model_file), MODEL, OUTPUT_FILE, "lwc")
683
686
  obj = ProductGrid(model, obs)
684
- obj._obs_data = ma.array(
687
+ data = ma.array(
685
688
  [
686
- [np.nan, np.nan, np.nan, np.nan],
687
- [np.nan, np.nan, np.nan, np.nan],
688
- [np.nan, np.nan, np.nan, np.nan],
689
- [np.nan, np.nan, np.nan, np.nan],
689
+ [99, 99, 99, 99],
690
+ [99, 99, 99, 99],
691
+ [99, 99, 99, 99],
692
+ [99, 99, 99, 99],
690
693
  ],
691
694
  )
692
- d = {"lwc": np.zeros((1, 1))}
695
+ obj._obs_data = ma.masked_where(data == 99, data)
696
+ d = {"lwc": ma.zeros((1, 1))}
693
697
  ind = np.array([[0, 1, 1, 1], [0, 0, 1, 1], [0, 0, 0, 0], [0, 0, 0, 0]], dtype=bool)
694
698
  d = obj._regrid_product(d, 0, 0, ind)
695
- x = d["lwc"]
696
- testing.assert_almost_equal(x[0, 0], np.nan)
699
+ assert d["lwc"][0, 0].mask == True
697
700
 
698
701
 
699
702
  def test_regrid_product_masked(model_file, obs_file) -> None:
@@ -702,7 +705,7 @@ def test_regrid_product_masked(model_file, obs_file) -> None:
702
705
  obj = ProductGrid(model, obs)
703
706
  obj._obs_data = ma.array([[1, 1, 1, 1], [2, 1, 2, 2], [3, 3, 3, 3], [4, 4, 4, 4]])
704
707
  obj._obs_data[2, :] = ma.masked
705
- d = {"lwc": np.zeros((1, 1))}
708
+ d = {"lwc": ma.zeros((1, 1))}
706
709
  ind = np.array([[0, 1, 1, 1], [0, 0, 1, 1], [0, 0, 0, 0], [0, 0, 0, 0]], dtype=bool)
707
710
  d = obj._regrid_product(d, 0, 0, ind)
708
711
  x = d["lwc"]
@@ -715,11 +718,11 @@ def test_regrid_product_all_masked(model_file, obs_file) -> None:
715
718
  obj = ProductGrid(model, obs)
716
719
  obj._obs_data = ma.array([[1, 1, 1, 1], [2, 1, 2, 2], [3, 3, 3, 3], [4, 4, 4, 4]])
717
720
  obj._obs_data[:, :] = ma.masked
718
- d = {"lwc": np.zeros((1, 1))}
721
+ d = {"lwc": ma.zeros((1, 1))}
719
722
  ind = np.array([[0, 1, 1, 1], [0, 0, 1, 1], [0, 0, 0, 0], [0, 0, 0, 0]], dtype=bool)
720
723
  d = obj._regrid_product(d, 0, 0, ind)
721
724
  x = d["lwc"]
722
- testing.assert_almost_equal(x, np.nan)
725
+ testing.assert_almost_equal(x, ma.masked)
723
726
 
724
727
 
725
728
  def test_regrid_product_none(model_file, obs_file) -> None:
@@ -727,11 +730,11 @@ def test_regrid_product_none(model_file, obs_file) -> None:
727
730
  model = ModelManager(str(model_file), MODEL, OUTPUT_FILE, "lwc")
728
731
  obj = ProductGrid(model, obs)
729
732
  obj._obs_data = ma.array([[1, 1, 1, 1], [2, 1, 2, 2], [3, 3, 3, 3], [4, 4, 4, 4]])
730
- d = {"lwc": np.zeros((1, 1))}
733
+ d = {"lwc": ma.zeros((1, 1))}
731
734
  ind = np.array([[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]], dtype=bool)
732
735
  d = obj._regrid_product(d, 0, 0, ind)
733
736
  x = d["lwc"]
734
- testing.assert_almost_equal(x[0, 0], np.nan)
737
+ assert x[0, 0].mask == True
735
738
 
736
739
 
737
740
  @pytest.mark.parametrize("product", ["cf_A", "cf_V", "cf_A_adv", "cf_V_adv"])
@@ -281,10 +281,11 @@ class SubPlot:
281
281
 
282
282
  def _read_plot_meta(self, file_type: str | None) -> PlotMeta:
283
283
  if self.options.plot_meta is not None:
284
- return self.options.plot_meta
285
- fallback = ATTRIBUTES["fallback"].get(self.variable.name, PlotMeta())
286
- file_attributes = ATTRIBUTES.get(file_type or "", {})
287
- plot_meta = file_attributes.get(self.variable.name, fallback)
284
+ plot_meta = self.options.plot_meta
285
+ else:
286
+ fallback = ATTRIBUTES["fallback"].get(self.variable.name, PlotMeta())
287
+ file_attributes = ATTRIBUTES.get(file_type or "", {})
288
+ plot_meta = file_attributes.get(self.variable.name, fallback)
288
289
  if plot_meta.clabel is None:
289
290
  plot_meta = plot_meta._replace(clabel=_reformat_units(self.variable.units))
290
291
  return plot_meta
cloudnetpy/version.py CHANGED
@@ -1,4 +1,4 @@
1
1
  MAJOR = 1
2
2
  MINOR = 60
3
- PATCH = 2
3
+ PATCH = 4
4
4
  __version__ = f"{MAJOR}.{MINOR}.{PATCH}"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: cloudnetpy
3
- Version: 1.60.2
3
+ Version: 1.60.4
4
4
  Summary: Python package for Cloudnet processing
5
5
  Author: Simo Tukiainen
6
6
  License: MIT License
@@ -8,7 +8,7 @@ cloudnetpy/metadata.py,sha256=v_VDo2vbdTxB0zIsfP69IcrwSKiRlLpsGdq6JPI4CoA,5306
8
8
  cloudnetpy/output.py,sha256=WoVTNuxni0DUr163vZ-_mDr1brXhY15XSlGMrq9Aoqw,14700
9
9
  cloudnetpy/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
10
10
  cloudnetpy/utils.py,sha256=0TlHm71YtSrKXBsRKctitnhQrvZPE-ulEVeAQW-oK58,27398
11
- cloudnetpy/version.py,sha256=1gcGyZ8fdho4zB9yztNBgWbkx81LMd52wmB8PPeX75Y,72
11
+ cloudnetpy/version.py,sha256=06fW2hQK7Jbkp2HWa_QZu8yzkaZk1XNjYTDo93YsO94,72
12
12
  cloudnetpy/categorize/__init__.py,sha256=gP5q3Vis1y9u9OWgA_idlbjfWXYN_S0IBSWdwBhL_uU,69
13
13
  cloudnetpy/categorize/atmos.py,sha256=fWW8ye_8HZASRAiYwURFKWzcGOYIA2RKeVxCq0lVOuM,12389
14
14
  cloudnetpy/categorize/atmos_utils.py,sha256=wndpwJxc2-QnNTkV8tc8I11Vs_WkNz9sVMX1fuGgUC4,3777
@@ -54,15 +54,15 @@ cloudnetpy/instruments/disdrometer/thies.py,sha256=h7EwZ9tn47UUMiYqDQ68vkXv4q0rE
54
54
  cloudnetpy/model_evaluation/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
55
55
  cloudnetpy/model_evaluation/file_handler.py,sha256=oUGIblcEWLLv16YKUch-M5KA-dGRAcuHa-9anP3xtX4,6447
56
56
  cloudnetpy/model_evaluation/metadata.py,sha256=7ZL87iDbaQJIMu8wfnMvb01cGVPkl8RtvEm_tt9uIHE,8413
57
- cloudnetpy/model_evaluation/model_metadata.py,sha256=JXbYIxX0wAptoETDqZihsm_Ksk1COa_QCJ9QFwToi6k,1427
57
+ cloudnetpy/model_evaluation/model_metadata.py,sha256=CxpY6RPm7GOTBBmPhcNVVpm9ateUmHSUwGtFXTLq3To,1436
58
58
  cloudnetpy/model_evaluation/utils.py,sha256=Z9VqYVdtY9yTr2JeVfBn4nccIVWCN5Fd-BCyB_qYI-A,154
59
59
  cloudnetpy/model_evaluation/plotting/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
60
60
  cloudnetpy/model_evaluation/plotting/plot_meta.py,sha256=K18Ugohh24uVAIxjZgJsmK80YwsMstm6B7ptVafONAw,3557
61
61
  cloudnetpy/model_evaluation/plotting/plot_tools.py,sha256=0CU9glFeYPCLhrUjvJXPL75DC-aG0dXzmcbfld5TVww,5031
62
- cloudnetpy/model_evaluation/plotting/plotting.py,sha256=gtGEN5ymf3dlmBWVNgiHzvZbxN3n-YOZFTgrKP4Mzdg,30138
62
+ cloudnetpy/model_evaluation/plotting/plotting.py,sha256=h3iouEKrJncPDGOMmD34hLMnrHOIsDHXpkc1yvVD63k,30877
63
63
  cloudnetpy/model_evaluation/products/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
64
- cloudnetpy/model_evaluation/products/advance_methods.py,sha256=QUeGQlu4k0YKLAvzqDxIu6hC84-0u-Lk0ABUGSEPacY,9032
65
- cloudnetpy/model_evaluation/products/grid_methods.py,sha256=cdCBIy0QAwT5UIg-_V6pbbievpt5Ul0lZ-ZHrDEN79k,9744
64
+ cloudnetpy/model_evaluation/products/advance_methods.py,sha256=rng3ZLR1Arv1AGUzq0Ehu-65628PC5LZVKpHSUpCIW8,8526
65
+ cloudnetpy/model_evaluation/products/grid_methods.py,sha256=fRYdPRSewsXlv1frJWOKeCIYWlRAAXRRcKgvmNeBWwY,9066
66
66
  cloudnetpy/model_evaluation/products/model_products.py,sha256=SOd7dZ5lBh0ampovzJ9DryfHOC_tqFa-EN5lAQUHb3Y,6854
67
67
  cloudnetpy/model_evaluation/products/observation_products.py,sha256=ttz-NINIQCSjuyZtRn-vuctHItLT8RLtwwiNXsys-UA,5492
68
68
  cloudnetpy/model_evaluation/products/product_resampling.py,sha256=IuWvtwpya76URh1WmTTgtLxAo4HZxkz6GmftpZkMCGo,3640
@@ -82,9 +82,9 @@ cloudnetpy/model_evaluation/tests/e2e/process_lwc/__init__.py,sha256=47DEQpj8HBS
82
82
  cloudnetpy/model_evaluation/tests/e2e/process_lwc/main.py,sha256=IFcPj-Vce9Yn0CfCy9gASxRf7NzlKFMfsDHzAuapY4I,1306
83
83
  cloudnetpy/model_evaluation/tests/e2e/process_lwc/tests.py,sha256=ANBA0LVao3Xrm-prRnwUmxM6BdQzqM7GZNKB3uz5BXQ,1725
84
84
  cloudnetpy/model_evaluation/tests/unit/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
85
- cloudnetpy/model_evaluation/tests/unit/conftest.py,sha256=ZNBqkt1fvt-5jHzLaT7opM4OxvsXnx89OToWvtiRxkI,7425
86
- cloudnetpy/model_evaluation/tests/unit/test_advance_methods.py,sha256=GCYD-hgKttkdVKU67dsSs0YUuSxmzC1Cscm5_2Yj0KA,10809
87
- cloudnetpy/model_evaluation/tests/unit/test_grid_methods.py,sha256=uQRBf7akxmx3nCGZLf28nPESDEZWao06iUZqIIu1kmE,26269
85
+ cloudnetpy/model_evaluation/tests/unit/conftest.py,sha256=WL_FgrDeoUYGp4PKjb37HLu79D9uu33PGQL40_ctqS0,7446
86
+ cloudnetpy/model_evaluation/tests/unit/test_advance_methods.py,sha256=IkoAVtsWVFrPpFqQOLAPHKb9qgV-KjGGVEtWMudeiSo,10079
87
+ cloudnetpy/model_evaluation/tests/unit/test_grid_methods.py,sha256=qkNPfHI25EE0-BXk73TijpeM7YwswX7e41-764o5lqE,26254
88
88
  cloudnetpy/model_evaluation/tests/unit/test_model_products.py,sha256=FRbYLshSHH2E527uJPwvUIyZKTsPFSZrwDsPsNrFSSU,3475
89
89
  cloudnetpy/model_evaluation/tests/unit/test_observation_products.py,sha256=P-W5QwRHMtem6p5SyyH7p9TvHGro3XW1baQcIwh6nFg,4892
90
90
  cloudnetpy/model_evaluation/tests/unit/test_plot_tools.py,sha256=POdypGWjV2NA4DCU7w8Unk_IdPfOpUb1qBDhfA3x1Bw,9222
@@ -93,7 +93,7 @@ cloudnetpy/model_evaluation/tests/unit/test_statistical_methods.py,sha256=Ra3r4V
93
93
  cloudnetpy/model_evaluation/tests/unit/test_tools.py,sha256=Ia_VrLdV2NstX5gbx_3AZTOAlrgLAy_xFZ8fHYVX0xI,3817
94
94
  cloudnetpy/plotting/__init__.py,sha256=lg9Smn4BI0dVBgnDLC3JVJ4GmwoSnO-qoSd4ApvwV6Y,107
95
95
  cloudnetpy/plotting/plot_meta.py,sha256=cLdCZrhbP-gaobS_zjcf8d2xVALzl7zh2qpttxCHyrg,15983
96
- cloudnetpy/plotting/plotting.py,sha256=Qm1eQK1eTnXtHzmhxerYrKMpZTCxoOvwS8f1IxsZGaM,32428
96
+ cloudnetpy/plotting/plotting.py,sha256=bve91iM9RcWmKaZOFWxVh2y3DPmupI1944MMYDdv17I,32459
97
97
  cloudnetpy/products/__init__.py,sha256=2hRb5HG9hNrxH1if5laJkLeFeaZCd5W1q3hh4ewsX0E,273
98
98
  cloudnetpy/products/classification.py,sha256=0E9OUGR3uLCsS1nORwQu0SqW0_8uX7n6LlRcVhtzKw4,7845
99
99
  cloudnetpy/products/der.py,sha256=mam6jWV7A2h8V5WC3DIeFp6ou7UD1JOw9r7h2B0su-s,12403
@@ -107,8 +107,8 @@ cloudnetpy/products/mie_lu_tables.nc,sha256=It4fYpqJXlqOgL8jeZ-PxGzP08PMrELIDVe5
107
107
  cloudnetpy/products/mwr_tools.py,sha256=PRm5aCULccUehU-Byk55wYhhEHseMjoAjGBu5TSyHao,4621
108
108
  cloudnetpy/products/product_tools.py,sha256=rhx_Ru9FLlQqCNM-awoiHx18-Aq1eBwL9LiUaQoJs6k,10412
109
109
  docs/source/conf.py,sha256=IKiFWw6xhUd8NrCg0q7l596Ck1d61XWeVjIFHVSG9Og,1490
110
- cloudnetpy-1.60.2.dist-info/LICENSE,sha256=wcZF72bdaoG9XugpyE95Juo7lBQOwLuTKBOhhtANZMM,1094
111
- cloudnetpy-1.60.2.dist-info/METADATA,sha256=Em0bHeOPbyNWL1-U7VJOYbembh5hoiXss-QwU23Skw8,5784
112
- cloudnetpy-1.60.2.dist-info/WHEEL,sha256=oiQVh_5PnQM0E3gPdiz09WCNmwiHDMaGer_elqB3coM,92
113
- cloudnetpy-1.60.2.dist-info/top_level.txt,sha256=ibSPWRr6ojS1i11rtBFz2_gkIe68mggj7aeswYfaOo0,16
114
- cloudnetpy-1.60.2.dist-info/RECORD,,
110
+ cloudnetpy-1.60.4.dist-info/LICENSE,sha256=wcZF72bdaoG9XugpyE95Juo7lBQOwLuTKBOhhtANZMM,1094
111
+ cloudnetpy-1.60.4.dist-info/METADATA,sha256=3k80uCASgoavEpHtQM00w8S7ndKtjmqKDP0v0BoeLAw,5784
112
+ cloudnetpy-1.60.4.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
113
+ cloudnetpy-1.60.4.dist-info/top_level.txt,sha256=ibSPWRr6ojS1i11rtBFz2_gkIe68mggj7aeswYfaOo0,16
114
+ cloudnetpy-1.60.4.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: bdist_wheel (0.42.0)
2
+ Generator: bdist_wheel (0.43.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5