cloudnetpy 1.80.7__py3-none-any.whl → 1.81.0__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 (83) hide show
  1. cloudnetpy/categorize/__init__.py +1 -1
  2. cloudnetpy/categorize/atmos_utils.py +31 -27
  3. cloudnetpy/categorize/attenuations/__init__.py +4 -4
  4. cloudnetpy/categorize/attenuations/liquid_attenuation.py +7 -5
  5. cloudnetpy/categorize/attenuations/melting_attenuation.py +3 -3
  6. cloudnetpy/categorize/attenuations/rain_attenuation.py +4 -4
  7. cloudnetpy/categorize/categorize.py +25 -11
  8. cloudnetpy/categorize/classify.py +9 -8
  9. cloudnetpy/categorize/containers.py +13 -10
  10. cloudnetpy/categorize/disdrometer.py +5 -3
  11. cloudnetpy/categorize/droplet.py +12 -9
  12. cloudnetpy/categorize/falling.py +9 -8
  13. cloudnetpy/categorize/freezing.py +10 -7
  14. cloudnetpy/categorize/insects.py +18 -17
  15. cloudnetpy/categorize/lidar.py +7 -3
  16. cloudnetpy/categorize/melting.py +16 -15
  17. cloudnetpy/categorize/model.py +17 -10
  18. cloudnetpy/categorize/mwr.py +5 -3
  19. cloudnetpy/categorize/radar.py +15 -13
  20. cloudnetpy/cli.py +10 -8
  21. cloudnetpy/cloudnetarray.py +8 -7
  22. cloudnetpy/concat_lib.py +29 -20
  23. cloudnetpy/datasource.py +26 -21
  24. cloudnetpy/exceptions.py +12 -10
  25. cloudnetpy/instruments/basta.py +19 -9
  26. cloudnetpy/instruments/bowtie.py +18 -11
  27. cloudnetpy/instruments/ceilo.py +22 -10
  28. cloudnetpy/instruments/ceilometer.py +33 -34
  29. cloudnetpy/instruments/cl61d.py +5 -3
  30. cloudnetpy/instruments/cloudnet_instrument.py +7 -7
  31. cloudnetpy/instruments/copernicus.py +16 -7
  32. cloudnetpy/instruments/disdrometer/common.py +5 -4
  33. cloudnetpy/instruments/disdrometer/parsivel.py +14 -9
  34. cloudnetpy/instruments/disdrometer/thies.py +11 -7
  35. cloudnetpy/instruments/fd12p.py +7 -6
  36. cloudnetpy/instruments/galileo.py +16 -7
  37. cloudnetpy/instruments/hatpro.py +33 -24
  38. cloudnetpy/instruments/lufft.py +6 -4
  39. cloudnetpy/instruments/mira.py +33 -19
  40. cloudnetpy/instruments/mrr.py +12 -12
  41. cloudnetpy/instruments/nc_lidar.py +1 -1
  42. cloudnetpy/instruments/nc_radar.py +8 -8
  43. cloudnetpy/instruments/pollyxt.py +19 -12
  44. cloudnetpy/instruments/radiometrics.py +17 -10
  45. cloudnetpy/instruments/rain_e_h3.py +9 -5
  46. cloudnetpy/instruments/rpg.py +32 -21
  47. cloudnetpy/instruments/rpg_reader.py +15 -12
  48. cloudnetpy/instruments/vaisala.py +32 -24
  49. cloudnetpy/instruments/weather_station.py +22 -19
  50. cloudnetpy/model_evaluation/file_handler.py +27 -29
  51. cloudnetpy/model_evaluation/plotting/plot_tools.py +7 -5
  52. cloudnetpy/model_evaluation/plotting/plotting.py +41 -32
  53. cloudnetpy/model_evaluation/products/advance_methods.py +38 -34
  54. cloudnetpy/model_evaluation/products/grid_methods.py +10 -9
  55. cloudnetpy/model_evaluation/products/model_products.py +15 -9
  56. cloudnetpy/model_evaluation/products/observation_products.py +12 -10
  57. cloudnetpy/model_evaluation/products/product_resampling.py +11 -7
  58. cloudnetpy/model_evaluation/products/tools.py +18 -14
  59. cloudnetpy/model_evaluation/statistics/statistical_methods.py +6 -5
  60. cloudnetpy/model_evaluation/tests/unit/test_plotting.py +18 -25
  61. cloudnetpy/model_evaluation/utils.py +3 -3
  62. cloudnetpy/output.py +15 -32
  63. cloudnetpy/plotting/plotting.py +23 -13
  64. cloudnetpy/products/classification.py +15 -9
  65. cloudnetpy/products/der.py +24 -19
  66. cloudnetpy/products/drizzle.py +21 -13
  67. cloudnetpy/products/drizzle_error.py +8 -7
  68. cloudnetpy/products/drizzle_tools.py +27 -23
  69. cloudnetpy/products/epsilon.py +6 -5
  70. cloudnetpy/products/ier.py +11 -5
  71. cloudnetpy/products/iwc.py +18 -9
  72. cloudnetpy/products/lwc.py +41 -31
  73. cloudnetpy/products/mwr_tools.py +30 -19
  74. cloudnetpy/products/product_tools.py +23 -19
  75. cloudnetpy/utils.py +84 -98
  76. cloudnetpy/version.py +2 -2
  77. {cloudnetpy-1.80.7.dist-info → cloudnetpy-1.81.0.dist-info}/METADATA +2 -1
  78. cloudnetpy-1.81.0.dist-info/RECORD +126 -0
  79. cloudnetpy-1.80.7.dist-info/RECORD +0 -126
  80. {cloudnetpy-1.80.7.dist-info → cloudnetpy-1.81.0.dist-info}/WHEEL +0 -0
  81. {cloudnetpy-1.80.7.dist-info → cloudnetpy-1.81.0.dist-info}/entry_points.txt +0 -0
  82. {cloudnetpy-1.80.7.dist-info → cloudnetpy-1.81.0.dist-info}/licenses/LICENSE +0 -0
  83. {cloudnetpy-1.80.7.dist-info → cloudnetpy-1.81.0.dist-info}/top_level.txt +0 -0
cloudnetpy/utils.py CHANGED
@@ -9,7 +9,7 @@ import textwrap
9
9
  import uuid
10
10
  import warnings
11
11
  from collections.abc import Callable, Iterator
12
- from datetime import timezone
12
+ from os import PathLike
13
13
  from typing import Literal, TypeVar
14
14
 
15
15
  import netCDF4
@@ -23,11 +23,8 @@ from cloudnetpy.cloudnetarray import CloudnetArray
23
23
  from cloudnetpy.constants import SEC_IN_DAY, SEC_IN_HOUR, SEC_IN_MINUTE
24
24
  from cloudnetpy.exceptions import ValidTimeStampError
25
25
 
26
- Epoch = tuple[int, int, int]
27
- Date = tuple[str, str, str]
28
26
 
29
-
30
- def seconds2hours(time_in_seconds: np.ndarray) -> np.ndarray:
27
+ def seconds2hours(time_in_seconds: npt.NDArray) -> npt.NDArray:
31
28
  """Converts seconds since some epoch to fraction hour.
32
29
 
33
30
  Args:
@@ -47,25 +44,12 @@ def seconds2hours(time_in_seconds: np.ndarray) -> np.ndarray:
47
44
  return fraction_hour
48
45
 
49
46
 
50
- def seconds2time(time_in_seconds: float) -> list:
51
- """Converts seconds since some epoch to time of day.
52
-
53
- Args:
54
- time_in_seconds: seconds since some epoch.
55
-
56
- Returns:
57
- list: [hours, minutes, seconds] formatted as '05' etc.
58
-
59
- """
60
- seconds_since_midnight = np.mod(time_in_seconds, SEC_IN_DAY)
61
- hours = seconds_since_midnight // SEC_IN_HOUR
62
- minutes = seconds_since_midnight % SEC_IN_HOUR // SEC_IN_MINUTE
63
- seconds = seconds_since_midnight % SEC_IN_MINUTE
64
- time = [hours, minutes, seconds]
65
- return [str(t).zfill(2) for t in time]
66
-
67
-
68
- def seconds2date(time_in_seconds: float, epoch: Epoch = (2001, 1, 1)) -> list:
47
+ def seconds2date(
48
+ time_in_seconds: float,
49
+ epoch: datetime.datetime = datetime.datetime(
50
+ 2001, 1, 1, tzinfo=datetime.timezone.utc
51
+ ),
52
+ ) -> datetime.datetime:
69
53
  """Converts seconds since some epoch to datetime (UTC).
70
54
 
71
55
  Args:
@@ -73,21 +57,13 @@ def seconds2date(time_in_seconds: float, epoch: Epoch = (2001, 1, 1)) -> list:
73
57
  epoch: Epoch, default is (2001, 1, 1) (UTC).
74
58
 
75
59
  Returns:
76
- [year, month, day, hours, minutes, seconds] formatted as '05' etc (UTC).
60
+ Datetime
77
61
 
78
62
  """
79
- epoch_in_seconds = datetime.datetime.timestamp(
80
- datetime.datetime(*epoch, tzinfo=timezone.utc),
81
- )
82
- timestamp = float(time_in_seconds) + epoch_in_seconds
83
- return (
84
- datetime.datetime.fromtimestamp(timestamp, tz=datetime.timezone.utc)
85
- .strftime("%Y %m %d %H %M %S")
86
- .split()
87
- )
63
+ return epoch + datetime.timedelta(seconds=float(time_in_seconds))
88
64
 
89
65
 
90
- def datetime2decimal_hours(data: np.ndarray | list) -> np.ndarray:
66
+ def datetime2decimal_hours(data: npt.NDArray | list) -> npt.NDArray:
91
67
  """Converts array of datetime to decimal_hours."""
92
68
  output = []
93
69
  for timestamp in data:
@@ -97,7 +73,7 @@ def datetime2decimal_hours(data: np.ndarray | list) -> np.ndarray:
97
73
  return np.array(output)
98
74
 
99
75
 
100
- def time_grid(time_step: int = 30) -> np.ndarray:
76
+ def time_grid(time_step: int = 30) -> npt.NDArray:
101
77
  """Returns decimal hour array between 0 and 24.
102
78
 
103
79
  Computes fraction hour time vector 0-24 with user-given
@@ -120,7 +96,7 @@ def time_grid(time_step: int = 30) -> np.ndarray:
120
96
  return np.arange(half_step, 24 + half_step, half_step * 2)
121
97
 
122
98
 
123
- def binvec(x: np.ndarray | list) -> np.ndarray:
99
+ def binvec(x: npt.NDArray | list) -> npt.NDArray:
124
100
  """Converts 1-D center points to bins with even spacing.
125
101
 
126
102
  Args:
@@ -148,15 +124,15 @@ REBIN_STAT_FN: dict[REBIN_STAT, Callable] = {
148
124
 
149
125
 
150
126
  def rebin_2d(
151
- x_in: np.ndarray,
152
- array: np.ndarray,
153
- x_new: np.ndarray,
127
+ x_in: npt.NDArray,
128
+ array: npt.NDArray,
129
+ x_new: npt.NDArray,
154
130
  statistic: REBIN_STAT = "mean",
155
131
  n_min: int = 1,
156
132
  *,
157
133
  keepdim: bool = False,
158
134
  mask_zeros: bool = False,
159
- ) -> tuple[ma.MaskedArray, np.ndarray]:
135
+ ) -> tuple[ma.MaskedArray, npt.NDArray]:
160
136
  edges = binvec(x_new)
161
137
  binn = np.digitize(x_in, edges) - 1
162
138
  n_bins = len(x_new)
@@ -184,9 +160,9 @@ def rebin_2d(
184
160
 
185
161
 
186
162
  def rebin_1d(
187
- x_in: np.ndarray,
188
- array: np.ndarray | ma.MaskedArray,
189
- x_new: np.ndarray,
163
+ x_in: npt.NDArray,
164
+ array: npt.NDArray | ma.MaskedArray,
165
+ x_new: npt.NDArray,
190
166
  statistic: REBIN_STAT = "mean",
191
167
  ) -> ma.MaskedArray:
192
168
  """Rebins 1D array.
@@ -216,7 +192,7 @@ def rebin_1d(
216
192
  return ma.masked_invalid(result, copy=True)
217
193
 
218
194
 
219
- def filter_isolated_pixels(array: np.ndarray) -> np.ndarray:
195
+ def filter_isolated_pixels(array: npt.NDArray) -> npt.NDArray:
220
196
  """From a 2D boolean array, remove completely isolated single cells.
221
197
 
222
198
  Args:
@@ -236,7 +212,7 @@ def filter_isolated_pixels(array: np.ndarray) -> np.ndarray:
236
212
  return _filter(array, structure)
237
213
 
238
214
 
239
- def filter_x_pixels(array: np.ndarray) -> np.ndarray:
215
+ def filter_x_pixels(array: npt.NDArray) -> npt.NDArray:
240
216
  """From a 2D boolean array, remove cells isolated in x-direction.
241
217
 
242
218
  Args:
@@ -259,7 +235,7 @@ def filter_x_pixels(array: np.ndarray) -> np.ndarray:
259
235
  return _filter(array, structure)
260
236
 
261
237
 
262
- def _filter(array: np.ndarray, structure: np.ndarray) -> np.ndarray:
238
+ def _filter(array: npt.NDArray, structure: npt.NDArray) -> npt.NDArray:
263
239
  filtered_array = np.copy(array)
264
240
  id_regions, num_ids = ndimage.label(filtered_array, structure=structure)
265
241
  id_sizes = np.array(ndimage.sum(array, id_regions, range(num_ids + 1))).astype(int)
@@ -268,7 +244,7 @@ def _filter(array: np.ndarray, structure: np.ndarray) -> np.ndarray:
268
244
  return filtered_array
269
245
 
270
246
 
271
- def isbit(array: np.ndarray, nth_bit: int) -> np.ndarray:
247
+ def isbit(array: npt.NDArray, nth_bit: int) -> npt.NDArray:
272
248
  """Tests if nth bit (0,1,2,...) is set.
273
249
 
274
250
  Args:
@@ -298,7 +274,7 @@ def isbit(array: np.ndarray, nth_bit: int) -> np.ndarray:
298
274
  return array & mask > 0
299
275
 
300
276
 
301
- def setbit(array: np.ndarray, nth_bit: int) -> np.ndarray:
277
+ def setbit(array: npt.NDArray, nth_bit: int) -> npt.NDArray:
302
278
  """Sets nth bit (0, 1, 2, ...) on number.
303
279
 
304
280
  Args:
@@ -330,12 +306,12 @@ def setbit(array: np.ndarray, nth_bit: int) -> np.ndarray:
330
306
 
331
307
 
332
308
  def interpolate_2d(
333
- x: np.ndarray,
334
- y: np.ndarray,
335
- z: np.ndarray,
336
- x_new: np.ndarray,
337
- y_new: np.ndarray,
338
- ) -> np.ndarray:
309
+ x: npt.NDArray,
310
+ y: npt.NDArray,
311
+ z: npt.NDArray,
312
+ x_new: npt.NDArray,
313
+ y_new: npt.NDArray,
314
+ ) -> npt.NDArray:
339
315
  """Linear interpolation of gridded 2d data.
340
316
 
341
317
  Args:
@@ -357,11 +333,11 @@ def interpolate_2d(
357
333
 
358
334
 
359
335
  def interpolate_2d_mask(
360
- x: np.ndarray,
361
- y: np.ndarray,
336
+ x: npt.NDArray,
337
+ y: npt.NDArray,
362
338
  z: ma.MaskedArray,
363
- x_new: np.ndarray,
364
- y_new: np.ndarray,
339
+ x_new: npt.NDArray,
340
+ y_new: npt.NDArray,
365
341
  ) -> ma.MaskedArray:
366
342
  """2D linear interpolation preserving the mask.
367
343
 
@@ -403,11 +379,11 @@ def interpolate_2d_mask(
403
379
 
404
380
 
405
381
  def interpolate_2d_nearest(
406
- x: np.ndarray,
407
- y: np.ndarray,
408
- z: np.ndarray,
409
- x_new: np.ndarray,
410
- y_new: np.ndarray,
382
+ x: npt.NDArray,
383
+ y: npt.NDArray,
384
+ z: npt.NDArray,
385
+ x_new: npt.NDArray,
386
+ y_new: npt.NDArray,
411
387
  ) -> ma.MaskedArray:
412
388
  """2D nearest neighbor interpolation preserving mask.
413
389
 
@@ -437,12 +413,12 @@ def interpolate_2d_nearest(
437
413
  return fun((xx, yy)).T
438
414
 
439
415
 
440
- def calc_relative_error(reference: np.ndarray, array: np.ndarray) -> np.ndarray:
416
+ def calc_relative_error(reference: npt.NDArray, array: npt.NDArray) -> npt.NDArray:
441
417
  """Calculates relative error (%)."""
442
418
  return ((array - reference) / reference) * 100
443
419
 
444
420
 
445
- def db2lin(array: float | np.ndarray, scale: int = 10) -> np.ndarray:
421
+ def db2lin(array: float | npt.NDArray, scale: int = 10) -> npt.NDArray:
446
422
  """DB to linear conversion."""
447
423
  data = array / scale
448
424
  with warnings.catch_warnings():
@@ -452,19 +428,19 @@ def db2lin(array: float | np.ndarray, scale: int = 10) -> np.ndarray:
452
428
  return np.power(10, data)
453
429
 
454
430
 
455
- def lin2db(array: np.ndarray, scale: int = 10) -> np.ndarray:
431
+ def lin2db(array: npt.NDArray, scale: int = 10) -> npt.NDArray:
456
432
  """Linear to dB conversion."""
457
433
  if ma.isMaskedArray(array):
458
434
  return scale * ma.log10(array)
459
435
  return scale * np.log10(array)
460
436
 
461
437
 
462
- def mdiff(array: np.ndarray) -> float:
438
+ def mdiff(array: npt.NDArray) -> float:
463
439
  """Returns median difference of 1-D array."""
464
440
  return float(ma.median(ma.diff(array)))
465
441
 
466
442
 
467
- def l2norm(*args) -> ma.MaskedArray:
443
+ def l2norm(*args: npt.NDArray | float) -> ma.MaskedArray:
468
444
  """Returns l2 norm.
469
445
 
470
446
  Args:
@@ -514,7 +490,7 @@ def l2norm_weighted(
514
490
  return overall_scale * l2norm(*weighted_values)
515
491
 
516
492
 
517
- def cumsumr(array: np.ndarray, axis: int = 0) -> np.ndarray:
493
+ def cumsumr(array: npt.NDArray, axis: int = 0) -> npt.NDArray:
518
494
  """Finds cumulative sum that resets on 0.
519
495
 
520
496
  Args:
@@ -534,7 +510,7 @@ def cumsumr(array: np.ndarray, axis: int = 0) -> np.ndarray:
534
510
  return cums - np.maximum.accumulate(cums * (array == 0), axis=axis)
535
511
 
536
512
 
537
- def ffill(array: np.ndarray, value: int = 0) -> np.ndarray:
513
+ def ffill(array: npt.NDArray, value: int = 0) -> npt.NDArray:
538
514
  """Forward fills an array.
539
515
 
540
516
  Args:
@@ -568,7 +544,7 @@ def init(
568
544
  dtype: type = float,
569
545
  *,
570
546
  masked: bool = True,
571
- ) -> Iterator[np.ndarray | ma.MaskedArray]:
547
+ ) -> Iterator[npt.NDArray | ma.MaskedArray]:
572
548
  """Initializes several numpy arrays.
573
549
 
574
550
  Args:
@@ -598,7 +574,7 @@ def init(
598
574
  yield np.zeros(shape, dtype=dtype)
599
575
 
600
576
 
601
- def n_elements(array: np.ndarray, dist: float, var: str | None = None) -> int:
577
+ def n_elements(array: npt.NDArray, dist: float, var: str | None = None) -> int:
602
578
  """Returns the number of elements that cover certain distance.
603
579
 
604
580
  Args:
@@ -637,7 +613,7 @@ def n_elements(array: np.ndarray, dist: float, var: str | None = None) -> int:
637
613
  return int(np.round(n))
638
614
 
639
615
 
640
- def isscalar(array: np.ndarray | float | list | netCDF4.Variable) -> bool:
616
+ def isscalar(array: npt.NDArray | float | list | netCDF4.Variable) -> bool:
641
617
  """Tests if input is scalar.
642
618
 
643
619
  By "scalar" we mean that array has a single value.
@@ -673,9 +649,13 @@ def date_range(
673
649
  yield start_date + datetime.timedelta(n)
674
650
 
675
651
 
676
- def get_uuid() -> str:
677
- """Returns unique identifier."""
678
- return str(uuid.uuid4())
652
+ def get_uuid(input_uuid: str | uuid.UUID | None) -> uuid.UUID:
653
+ """Parse or generate unique identifier."""
654
+ if input_uuid is None:
655
+ return uuid.uuid4()
656
+ if isinstance(input_uuid, str):
657
+ return uuid.UUID(input_uuid)
658
+ return input_uuid
679
659
 
680
660
 
681
661
  def get_wl_band(radar_frequency: float) -> Literal["X", "Ka", "W"]:
@@ -698,7 +678,7 @@ def get_wl_band(radar_frequency: float) -> Literal["X", "Ka", "W"]:
698
678
  raise ValueError(msg)
699
679
 
700
680
 
701
- def transpose(data: np.ndarray) -> np.ndarray:
681
+ def transpose(data: npt.NDArray) -> npt.NDArray:
702
682
  """Transposes numpy array of (n, ) to (n, 1)."""
703
683
  if data.ndim != 1 or len(data) <= 1:
704
684
  msg = "Invalid input array shape"
@@ -725,12 +705,12 @@ def del_dict_keys(data: dict, keys: tuple | list) -> dict:
725
705
 
726
706
 
727
707
  def array_to_probability(
728
- array: np.ndarray,
708
+ array: npt.NDArray,
729
709
  loc: float,
730
710
  scale: float,
731
711
  *,
732
712
  invert: bool = False,
733
- ) -> np.ndarray:
713
+ ) -> npt.NDArray:
734
714
  """Converts continuous variable into 0-1 probability.
735
715
 
736
716
  Args:
@@ -756,7 +736,7 @@ def array_to_probability(
756
736
  return prob
757
737
 
758
738
 
759
- def range_to_height(range_los: np.ndarray, tilt_angle: float) -> np.ndarray:
739
+ def range_to_height(range_los: npt.NDArray, tilt_angle: float) -> npt.NDArray:
760
740
  """Converts distances from a tilted instrument to height above the ground.
761
741
 
762
742
  Args:
@@ -784,7 +764,7 @@ def is_timestamp(timestamp: str) -> bool:
784
764
  return reg_exp.match(timestamp) is not None
785
765
 
786
766
 
787
- def get_sorted_filenames(file_path: str, extension: str) -> list:
767
+ def get_sorted_filenames(file_path: str | PathLike, extension: str) -> list[str]:
788
768
  """Returns full paths of files with some extension, sorted by filename."""
789
769
  extension = extension.lower()
790
770
  all_files = os.listdir(file_path)
@@ -803,9 +783,9 @@ def str_to_numeric(value: str) -> int | float:
803
783
  return float(value)
804
784
 
805
785
 
806
- def get_epoch(units: str) -> Epoch:
786
+ def get_epoch(units: str) -> datetime.datetime:
807
787
  """Finds epoch from units string."""
808
- fallback = (2001, 1, 1)
788
+ fallback = datetime.datetime(2001, 1, 1, tzinfo=datetime.timezone.utc)
809
789
  try:
810
790
  date = units.split()[2]
811
791
  except IndexError:
@@ -823,11 +803,13 @@ def get_epoch(units: str) -> Epoch:
823
803
  year, month, day = date_components
824
804
  current_year = datetime.datetime.now(tz=datetime.timezone.utc).year
825
805
  if (1900 < year <= current_year) and (0 < month < 13) and (0 < day < 32):
826
- return year, month, day
806
+ return datetime.datetime(year, month, day, tzinfo=datetime.timezone.utc)
827
807
  return fallback
828
808
 
829
809
 
830
- def screen_by_time(data_in: dict, epoch: Epoch, expected_date: str) -> dict:
810
+ def screen_by_time(
811
+ data_in: dict, epoch: datetime.datetime, expected_date: datetime.date
812
+ ) -> dict:
831
813
  """Screen data by time.
832
814
 
833
815
  Args:
@@ -864,7 +846,9 @@ def screen_by_time(data_in: dict, epoch: Epoch, expected_date: str) -> dict:
864
846
  return data
865
847
 
866
848
 
867
- def find_valid_time_indices(time: np.ndarray, epoch: Epoch, expected_date: str) -> list:
849
+ def find_valid_time_indices(
850
+ time: npt.NDArray, epoch: datetime.datetime, expected_date: datetime.date
851
+ ) -> list[int]:
868
852
  """Finds valid time array indices for the given date.
869
853
 
870
854
  Args:
@@ -887,15 +871,15 @@ def find_valid_time_indices(time: np.ndarray, epoch: Epoch, expected_date: str)
887
871
  ind_sorted = np.argsort(time)
888
872
  ind_valid: list[int] = []
889
873
  for ind in ind_sorted:
890
- date_str = "-".join(seconds2date(time[ind], epoch=epoch)[:3])
891
- if date_str == expected_date and time[ind] not in time[ind_valid]:
874
+ date = seconds2date(time[ind], epoch=epoch).date()
875
+ if date == expected_date and time[ind] not in time[ind_valid]:
892
876
  ind_valid.append(ind)
893
877
  if not ind_valid:
894
878
  raise ValidTimeStampError
895
879
  return ind_valid
896
880
 
897
881
 
898
- def append_data(data_in: dict, key: str, array: np.ndarray) -> dict:
882
+ def append_data(data_in: dict, key: str, array: npt.NDArray) -> dict:
899
883
  """Appends data to a dictionary field (creates the field if not yet present).
900
884
 
901
885
  Args:
@@ -912,7 +896,7 @@ def append_data(data_in: dict, key: str, array: np.ndarray) -> dict:
912
896
  return data
913
897
 
914
898
 
915
- def edges2mid(data: np.ndarray, reference: Literal["upper", "lower"]) -> np.ndarray:
899
+ def edges2mid(data: npt.NDArray, reference: Literal["upper", "lower"]) -> npt.NDArray:
916
900
  """Shifts values half bin towards up or down.
917
901
 
918
902
  Args:
@@ -958,7 +942,7 @@ def get_files_with_variables(filenames: list, variables: list[str]) -> list:
958
942
  return valid_files
959
943
 
960
944
 
961
- def is_all_masked(array: np.ndarray) -> bool:
945
+ def is_all_masked(array: npt.NDArray) -> bool:
962
946
  """Tests if all values are masked."""
963
947
  return ma.isMaskedArray(array) and hasattr(array, "mask") and array.mask.all()
964
948
 
@@ -992,11 +976,11 @@ def bit_field_definition(definitions: dict[T, str]) -> str:
992
976
  return _format_definition("Bit", definitions)
993
977
 
994
978
 
995
- def path_lengths_from_ground(height: np.ndarray) -> np.ndarray:
979
+ def path_lengths_from_ground(height: npt.NDArray) -> npt.NDArray:
996
980
  return np.diff(height, prepend=0)
997
981
 
998
982
 
999
- def remove_masked_blocks(array: ma.MaskedArray, limit: int = 50) -> np.ndarray:
983
+ def remove_masked_blocks(array: ma.MaskedArray, limit: int = 50) -> npt.NDArray:
1000
984
  """Filters out large blocks of completely masked profiles."""
1001
985
  if array.ndim == 1:
1002
986
  return np.array(not ma.all(array.mask))
@@ -1007,17 +991,19 @@ def remove_masked_blocks(array: ma.MaskedArray, limit: int = 50) -> np.ndarray:
1007
991
  return mask[labeled_array]
1008
992
 
1009
993
 
1010
- def sha256sum(filename: str | os.PathLike) -> str:
994
+ def sha256sum(filename: str | PathLike) -> str:
1011
995
  """Calculates hash of file using sha-256."""
1012
996
  return _calc_hash_sum(filename, "sha256", is_base64=False)
1013
997
 
1014
998
 
1015
- def md5sum(filename: str | os.PathLike, *, is_base64: bool = False) -> str:
999
+ def md5sum(filename: str | PathLike, *, is_base64: bool = False) -> str:
1016
1000
  """Calculates hash of file using md5."""
1017
1001
  return _calc_hash_sum(filename, "md5", is_base64=is_base64)
1018
1002
 
1019
1003
 
1020
- def _calc_hash_sum(filename, method, *, is_base64: bool) -> str:
1004
+ def _calc_hash_sum(
1005
+ filename: str | PathLike, method: Literal["sha256", "md5"], *, is_base64: bool
1006
+ ) -> str:
1021
1007
  hash_sum = getattr(hashlib, method)()
1022
1008
  with open(filename, "rb") as f:
1023
1009
  for byte_block in iter(lambda: f.read(4096), b""):
@@ -1033,7 +1019,7 @@ def add_site_geolocation(
1033
1019
  gps: bool,
1034
1020
  site_meta: dict | None = None,
1035
1021
  dataset: netCDF4.Dataset | None = None,
1036
- ):
1022
+ ) -> None:
1037
1023
  tmp_data = {}
1038
1024
  tmp_source = {}
1039
1025
 
cloudnetpy/version.py CHANGED
@@ -1,4 +1,4 @@
1
1
  MAJOR = 1
2
- MINOR = 80
3
- PATCH = 7
2
+ MINOR = 81
3
+ PATCH = 0
4
4
  __version__ = f"{MAJOR}.{MINOR}.{PATCH}"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cloudnetpy
3
- Version: 1.80.7
3
+ Version: 1.81.0
4
4
  Summary: Python package for Cloudnet processing
5
5
  Author: Simo Tukiainen
6
6
  License: MIT License
@@ -47,6 +47,7 @@ Requires-Dist: requests
47
47
  Requires-Dist: rpgpy>=0.14.5
48
48
  Requires-Dist: scikit-image
49
49
  Requires-Dist: scipy
50
+ Requires-Dist: typing-extensions
50
51
  Provides-Extra: test
51
52
  Requires-Dist: cloudnetpy_qc; extra == "test"
52
53
  Requires-Dist: mypy; extra == "test"
@@ -0,0 +1,126 @@
1
+ cloudnetpy/__init__.py,sha256=X_FqY-4yg5GUj5Edo14SToLEos6JIsC3fN-v1FUgQoA,43
2
+ cloudnetpy/cli.py,sha256=kG48AI5wNK9MfxiUsQPiz56BQLgAZ3AyN0ehUO6MyuI,20892
3
+ cloudnetpy/cloudnetarray.py,sha256=I_U1W2rEXw8lbLwg3XBrr_qHGPqhQG9z_ouvVEg7p24,4908
4
+ cloudnetpy/concat_lib.py,sha256=u4UOjYzLnThaq-89iwA837OcOJpfmj_3RmRwBCFUh74,13218
5
+ cloudnetpy/constants.py,sha256=YnoSzZm35NDooJfhlulSJBc7g0eSchT3yGytRaTaJEI,845
6
+ cloudnetpy/datasource.py,sha256=HzvqTTHLCH9GniUsV_IWwyrvvONnFJh0tmBM61hsqxM,6364
7
+ cloudnetpy/exceptions.py,sha256=ZB3aUwjVRznR0CcZ5sZHrB0yz13URDf52Ksv7G7C7EA,1817
8
+ cloudnetpy/metadata.py,sha256=CFpXmdEkVPzvLPv2xHIR-aMMQ-TR26KfESYw-98j7sk,7213
9
+ cloudnetpy/output.py,sha256=bUp13wv5TVtfZ-wBPU_n2qvWZa-PviozrVUhJnonbYE,14830
10
+ cloudnetpy/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
11
+ cloudnetpy/utils.py,sha256=7PHfJo9iLMdePwEApLfYH4XiVC9DhlFQMdQTxesZylA,31797
12
+ cloudnetpy/version.py,sha256=wY4fvCRQ0ycGB3kwIS4jLTm6yzumJPa_XEba4A9MBDE,72
13
+ cloudnetpy/categorize/__init__.py,sha256=gtvzWr0IDRn2oA6yHBvinEhTGTuub-JkrOv93lBsgrE,61
14
+ cloudnetpy/categorize/atmos_utils.py,sha256=uWc9TABVYPI0sn4H5Az9Jf6NVRaWyEKIi17f0pAJQxE,10679
15
+ cloudnetpy/categorize/attenuation.py,sha256=Y_-fzmQTltWTqIZTulJhovC7a6ifpMcaAazDJcnMIOc,990
16
+ cloudnetpy/categorize/categorize.py,sha256=NtSnLblVBgUobCJkP5SscsQ0UJNoWjJQKuyl2ZyytV0,23221
17
+ cloudnetpy/categorize/classify.py,sha256=skA9K6Bxh9mFZ_fM4d78zt09BPDzfHLttXle6mFCMbw,8553
18
+ cloudnetpy/categorize/containers.py,sha256=PIJwgQos3CxF9BG4hBNLTaZq252FTH0kdgagT31mFmc,5517
19
+ cloudnetpy/categorize/disdrometer.py,sha256=XNL8kDtBAB12UmgRZ4ayxuVs8e3ghyLO0Hy5XpRgfMU,1966
20
+ cloudnetpy/categorize/droplet.py,sha256=wnMN9rHNSMZLXNXuYEd-RAS_8eAIIo2vkE7pp3DSTKs,8725
21
+ cloudnetpy/categorize/falling.py,sha256=Ykbl0dIaXHXgTd9wWUsw958qUxETCW_PfjtZcyWqHFA,4441
22
+ cloudnetpy/categorize/freezing.py,sha256=gigqpb4qfeQSlKXkrPUwCbMnMsxl74thJWSRW2iHJOg,3796
23
+ cloudnetpy/categorize/insects.py,sha256=bAqm4kFRtU16RPttsRLedofPd-yfbALNqz26jKlMNUE,5357
24
+ cloudnetpy/categorize/itu.py,sha256=ffXK27guyRS4d66VWQ2h4UEGjUIhGjPKbFmj7kh698c,10304
25
+ cloudnetpy/categorize/lidar.py,sha256=CQsDEeQYiuQCfCmJQWrqQvCfmciN1NPZ6uRdt89CZLY,2685
26
+ cloudnetpy/categorize/melting.py,sha256=CMBVRv9hJWjaEeHtuYOdCseyKIZeaA19hR0_q6C3cng,6255
27
+ cloudnetpy/categorize/model.py,sha256=DcGLw8iSnYWAerW5X6BXHypN1jcmUD635pEMeQ-Hb84,6800
28
+ cloudnetpy/categorize/mwr.py,sha256=kzSivQuKrsqmFInDLlSM1R2wAG5j-tQebOi_1IwUW_I,1690
29
+ cloudnetpy/categorize/radar.py,sha256=2mTDa9BLxQeaORm-YPQ1lJyjAKew6NYzjtUvjpIvBYU,16044
30
+ cloudnetpy/categorize/attenuations/__init__.py,sha256=kIyQEZ6VVO6jJOAndrt7jNU15pm0Cavh5GnDjFmIG1M,1040
31
+ cloudnetpy/categorize/attenuations/gas_attenuation.py,sha256=emr-RCxQT0i2N8k6eBNhRsmsCBPHJzQsWJfjC4fVSTo,975
32
+ cloudnetpy/categorize/attenuations/liquid_attenuation.py,sha256=bmqmPk_93J4njE16-VQ1bPI7oNSS8m9ACuUH7IErBs8,3069
33
+ cloudnetpy/categorize/attenuations/melting_attenuation.py,sha256=AHmMMK7upxtps5fXF7Ca_ZF8fwpzaTGyGSwXDJq6q1k,2387
34
+ cloudnetpy/categorize/attenuations/rain_attenuation.py,sha256=wJPyCiKWzsQDzMhqbA7mYwj9YRVcJIpXWhBnEYFy3uU,2843
35
+ cloudnetpy/instruments/__init__.py,sha256=PEgrrQNoiOuN_ctYilmt4LV2QCLg1likPjJdWtuGlLs,528
36
+ cloudnetpy/instruments/basta.py,sha256=E_qT5g_lzFVk3v-U0hVwgcNYlc9mhgrAv1NnSg2jwG4,4163
37
+ cloudnetpy/instruments/bowtie.py,sha256=WZYB_o90I5QKOupCRjzZU4Mi54oX_3teyAPBDUogwRI,4301
38
+ cloudnetpy/instruments/ceilo.py,sha256=GJ1ZVX6aEMAZw1cpTXcNy9imfuPAkoqmrLQyUc00UEo,8809
39
+ cloudnetpy/instruments/ceilometer.py,sha256=c37uteeuGnlE-o-Smu49H2qQJw6qZ0tc3Bzhyr1FoSo,13063
40
+ cloudnetpy/instruments/cl61d.py,sha256=3YMisWZ-nTX29I8hFNXrKc73rMPolqAO0lPmqpGamjk,2294
41
+ cloudnetpy/instruments/cloudnet_instrument.py,sha256=B1UkiB0ytnT3MWYalEegql5QIPaMLg5bJy5xI50JEco,4503
42
+ cloudnetpy/instruments/copernicus.py,sha256=ygEViERBSJdMeP9OxfLelZRDEbSRzY8n17ruYie2wm4,6970
43
+ cloudnetpy/instruments/fd12p.py,sha256=5TFyNO26VGpO4ts9UIJiuLo4LUwQPHO6aK2fTnOtaKY,7019
44
+ cloudnetpy/instruments/galileo.py,sha256=f_-GkRxhNaQPbI8HpOwSmoKfGqyjmD16A0ZFgwLOIig,5137
45
+ cloudnetpy/instruments/hatpro.py,sha256=omwZ0M_BqZ7rK1As9DOhTe5X9Bh3coMk2Qjlgr7b8cs,9906
46
+ cloudnetpy/instruments/instruments.py,sha256=z8Osjww3iQRxKvzXdISl-5vV6gShtji8Db5k-ZzDQ-0,4843
47
+ cloudnetpy/instruments/lufft.py,sha256=G6KeJOeltLUlGCHHEk8ns2K7WJ9ImAr25rSB2JltawE,4286
48
+ cloudnetpy/instruments/mira.py,sha256=XqmbytpeCJ2-hNugxdsXSBUDB8SAUc97_6lo5mHFG8E,11840
49
+ cloudnetpy/instruments/mrr.py,sha256=z50VYLOBW2o7enU7FHZYNFQRW2goEQpeGe7-iCBRQtg,6020
50
+ cloudnetpy/instruments/nc_lidar.py,sha256=PtZauDdI3bX3bv4gIVvV6N53e2Co-ehBL_tByHM9hj8,1713
51
+ cloudnetpy/instruments/nc_radar.py,sha256=NKsy0mF2Tdem0lNIYgd3Kbe2dOE-38t4f_rosdhBcy8,7368
52
+ cloudnetpy/instruments/pollyxt.py,sha256=Xo2pYjqGxJbsUgStTnXNir4dIOGztU-G4RH9-NV5Olw,10538
53
+ cloudnetpy/instruments/radiometrics.py,sha256=QKfnrZlQ0sFcFjmv1ShnCMTJQv64w4akjK-JAIY4gCg,16116
54
+ cloudnetpy/instruments/rain_e_h3.py,sha256=fjv3SgeUNx9GisYqLrBnX9AjnO17VtouyoPh12VE9uo,5465
55
+ cloudnetpy/instruments/rpg.py,sha256=R1rUdeSADvB1IMkGOF1S0rUEJDGEI_19SPrmErZpn5M,18825
56
+ cloudnetpy/instruments/rpg_reader.py,sha256=VbF5MN94Bmxo6DTDoUUdRd7s-S1YmvFmum4ztc7KN2g,11539
57
+ cloudnetpy/instruments/toa5.py,sha256=CfmmBMv5iMGaWHIGBK01Rw24cuXC1R1RMNTXkmsm340,1760
58
+ cloudnetpy/instruments/vaisala.py,sha256=tu7aljkMKep0uCWz-Sd-GuBXF_Yy421a4nHy0ffpMoc,4725
59
+ cloudnetpy/instruments/weather_station.py,sha256=v1THiKpCKeRhG10BmZodnw27GV3AiGp7a2dWS_tg5KY,27006
60
+ cloudnetpy/instruments/disdrometer/__init__.py,sha256=lyjwttWvFvuwYxEkusoAvgRcbBmglmOp5HJOpXUqLWo,93
61
+ cloudnetpy/instruments/disdrometer/common.py,sha256=WCPRCfAlElUzZpllOSjjWrLG2jgkiRIy0rWz_omFoJQ,10815
62
+ cloudnetpy/instruments/disdrometer/parsivel.py,sha256=1HIA52f1nGOvSd4SSTr2y3-JT3eKZWwdbMnIMRVvQ_U,25811
63
+ cloudnetpy/instruments/disdrometer/thies.py,sha256=7gPYFzpa58ot6pTblhEnY5eRw5yrue42XwyacHQm14k,11205
64
+ cloudnetpy/model_evaluation/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
65
+ cloudnetpy/model_evaluation/file_handler.py,sha256=yAbJ3yOqufQGV3rahwOm9-k1swEDDq8V8n-zaNVaN54,6473
66
+ cloudnetpy/model_evaluation/metadata.py,sha256=7Gf2w10tu2SYw5sy4-AYVUdVIRW4OgcgTXxjBjUL300,9260
67
+ cloudnetpy/model_evaluation/model_metadata.py,sha256=CxpY6RPm7GOTBBmPhcNVVpm9ateUmHSUwGtFXTLq3To,1436
68
+ cloudnetpy/model_evaluation/utils.py,sha256=u7K5Lpt2kojKpPvD9xlB7K8yFJf_YMbFdnt4h0m-p9w,160
69
+ cloudnetpy/model_evaluation/plotting/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
70
+ cloudnetpy/model_evaluation/plotting/plot_meta.py,sha256=K18Ugohh24uVAIxjZgJsmK80YwsMstm6B7ptVafONAw,3557
71
+ cloudnetpy/model_evaluation/plotting/plot_tools.py,sha256=CHbcwo3jXC45J6EBtEy-CDo7Rt1sOCryl8e98XXJLSQ,5070
72
+ cloudnetpy/model_evaluation/plotting/plotting.py,sha256=ZpfL16dKUYb6VugmvyJPaQ3rAULBsS6FgFzWHLR-Sbk,31736
73
+ cloudnetpy/model_evaluation/products/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
74
+ cloudnetpy/model_evaluation/products/advance_methods.py,sha256=-57z69YL8VVauypa0W1ZAZGHoNybna_CYcxQVORCV9c,8658
75
+ cloudnetpy/model_evaluation/products/grid_methods.py,sha256=gAbRjM8jL0FBmH1t6U9Hvi0-f8GbmmF9Ctrcckluwh8,9110
76
+ cloudnetpy/model_evaluation/products/model_products.py,sha256=vt104hKBM3KoLx-4r8E_LXKRR-FZU0X2gRS2TJ1sVII,7036
77
+ cloudnetpy/model_evaluation/products/observation_products.py,sha256=ifNGmMBTI3G4EvnrXfS7vizbhv_hXlocLWs73BgeUOw,5578
78
+ cloudnetpy/model_evaluation/products/product_resampling.py,sha256=PO9PIJFeh2Nhl1bJ5Vg0_mB2xR5Xvj-qMjfD8n28KvY,3781
79
+ cloudnetpy/model_evaluation/products/tools.py,sha256=pIF3cw3LDhdRfBTuknpzXdr7cxPuD0Reyb_lwLxR-v0,3075
80
+ cloudnetpy/model_evaluation/statistics/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
81
+ cloudnetpy/model_evaluation/statistics/statistical_methods.py,sha256=PNXp9k3Nmz8Yn5zOvMibSc2LH2bmKs1hFWkjS9JLa_8,6023
82
+ cloudnetpy/model_evaluation/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
83
+ cloudnetpy/model_evaluation/tests/e2e/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
84
+ cloudnetpy/model_evaluation/tests/e2e/conftest.py,sha256=TENW6O-OsqNmFEtS0gZLlzVCoF0eXfLBEuFGB5bZ-k8,305
85
+ cloudnetpy/model_evaluation/tests/e2e/process_cf/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
86
+ cloudnetpy/model_evaluation/tests/e2e/process_cf/main.py,sha256=1BhHb6hhJF68pTXhzd_tsUtIRzyt14aZHdw1HAIWNPo,1289
87
+ cloudnetpy/model_evaluation/tests/e2e/process_cf/tests.py,sha256=2PrANQKp7vMlWp1y0XPQnkNpcpYx0kScrCOlRgS48z0,1787
88
+ cloudnetpy/model_evaluation/tests/e2e/process_iwc/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
89
+ cloudnetpy/model_evaluation/tests/e2e/process_iwc/main.py,sha256=9hndE5kVF31PH5zkjBnN9Jko865PMGHawRg13BujD6I,1368
90
+ cloudnetpy/model_evaluation/tests/e2e/process_iwc/tests.py,sha256=0pgqdGmv4T9lbQ4DYXAsAHEf05WgKmO4xUSNIzx3Lf0,1903
91
+ cloudnetpy/model_evaluation/tests/e2e/process_lwc/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
92
+ cloudnetpy/model_evaluation/tests/e2e/process_lwc/main.py,sha256=IFcPj-Vce9Yn0CfCy9gASxRf7NzlKFMfsDHzAuapY4I,1306
93
+ cloudnetpy/model_evaluation/tests/e2e/process_lwc/tests.py,sha256=ANBA0LVao3Xrm-prRnwUmxM6BdQzqM7GZNKB3uz5BXQ,1725
94
+ cloudnetpy/model_evaluation/tests/unit/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
95
+ cloudnetpy/model_evaluation/tests/unit/conftest.py,sha256=WL_FgrDeoUYGp4PKjb37HLu79D9uu33PGQL40_ctqS0,7446
96
+ cloudnetpy/model_evaluation/tests/unit/test_advance_methods.py,sha256=UEF94sBN8pPOyoz5ARag3mc5A8KFjyY_-IJFqdKBGug,10098
97
+ cloudnetpy/model_evaluation/tests/unit/test_grid_methods.py,sha256=AEUXN5HBhKliPsSNGDCUtWOtIx6Y8iqkywb_-RfXYU0,26277
98
+ cloudnetpy/model_evaluation/tests/unit/test_model_products.py,sha256=FRbYLshSHH2E527uJPwvUIyZKTsPFSZrwDsPsNrFSSU,3475
99
+ cloudnetpy/model_evaluation/tests/unit/test_observation_products.py,sha256=DN3yVqq8vFYca_9POjcrJ8XViMrJks_jM-aQznfN8QQ,4936
100
+ cloudnetpy/model_evaluation/tests/unit/test_plot_tools.py,sha256=POdypGWjV2NA4DCU7w8Unk_IdPfOpUb1qBDhfA3x1Bw,9222
101
+ cloudnetpy/model_evaluation/tests/unit/test_plotting.py,sha256=5hkhtqX-JQ8-Yy6DA-ZT6g7yQv5JqySXxiYa2Vi0M-Y,3257
102
+ cloudnetpy/model_evaluation/tests/unit/test_statistical_methods.py,sha256=Ra3r4V0qbqkpDuaTYvEIbaasl0nZ5gmTLR4eGC0glBQ,9724
103
+ cloudnetpy/model_evaluation/tests/unit/test_tools.py,sha256=Ia_VrLdV2NstX5gbx_3AZTOAlrgLAy_xFZ8fHYVX0xI,3817
104
+ cloudnetpy/plotting/__init__.py,sha256=lg9Smn4BI0dVBgnDLC3JVJ4GmwoSnO-qoSd4ApvwV6Y,107
105
+ cloudnetpy/plotting/plot_meta.py,sha256=qfyZJNis937uM-NJseer8i4FO7I_v5jhQPyFl5Uszi8,17390
106
+ cloudnetpy/plotting/plotting.py,sha256=ROoxpVQGs3tyMf-JYsfslQMr1REpq3IxuZ7BrccpV90,38977
107
+ cloudnetpy/products/__init__.py,sha256=cBJdJBYltz5ZTKDqnRo-0StytAZK8gE3RYxxriFA4ak,295
108
+ cloudnetpy/products/classification.py,sha256=yg2XThN8ESr2hz0WvfHzAus5QUyLp7oHytR7nZJ0u18,8560
109
+ cloudnetpy/products/der.py,sha256=UXdAxmmwChVVWSI4QSGAXphfMnbymGRTtGdKWEvh-J4,13162
110
+ cloudnetpy/products/drizzle.py,sha256=0h1N_WVjC2GgIkAN-4ydOwl7WJn3psxeqmPHfX8WHhQ,11935
111
+ cloudnetpy/products/drizzle_error.py,sha256=QN98Io9UsBoEYxKBqfwoS88OGBiK5U5RYnVQjyTWHCI,6220
112
+ cloudnetpy/products/drizzle_tools.py,sha256=xYMB8Qxp-_wKzMv_XC6u6iMfRnEhEtmDpCHSQAbDToo,11201
113
+ cloudnetpy/products/epsilon.py,sha256=ctD5BBuyM69y3YvBCkEqt2HsZ6JiX3cePT8fiuogWmY,7763
114
+ cloudnetpy/products/ier.py,sha256=Eb5AK-6l5mN_7vWP1cxcXQzj886zAwDDsHXueUju0N0,6262
115
+ cloudnetpy/products/iwc.py,sha256=pXl0xOFDD6AzGaAp_GzD2yapjOc7hXKTno9Q5G6HCOo,9826
116
+ cloudnetpy/products/lwc.py,sha256=xsNiiG6dGKIkWaFk0xWTabc1bZ4ULf6SqcqHs7itAUk,19339
117
+ cloudnetpy/products/mie_lu_tables.nc,sha256=It4fYpqJXlqOgL8jeZ-PxGzP08PMrELIDVe55y9ob58,16637951
118
+ cloudnetpy/products/mwr_tools.py,sha256=ZIpeeH3qYPrujmITMtnS8H8PfQIPWJYlz4AdaUSSs28,6452
119
+ cloudnetpy/products/product_tools.py,sha256=eyqIw_0KhlpmmYQE69RpGdRIAOW7JVPlEgkTBp2kdps,11302
120
+ cloudnetpy-1.81.0.dist-info/licenses/LICENSE,sha256=wcZF72bdaoG9XugpyE95Juo7lBQOwLuTKBOhhtANZMM,1094
121
+ docs/source/conf.py,sha256=IKiFWw6xhUd8NrCg0q7l596Ck1d61XWeVjIFHVSG9Og,1490
122
+ cloudnetpy-1.81.0.dist-info/METADATA,sha256=uC45DzJsJ3MBc4HulJzhLQEFJi6QEIb80HgJGBNYXMw,5836
123
+ cloudnetpy-1.81.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
124
+ cloudnetpy-1.81.0.dist-info/entry_points.txt,sha256=HhY7LwCFk4qFgDlXx_Fy983ZTd831WlhtdPIzV-Y3dY,51
125
+ cloudnetpy-1.81.0.dist-info/top_level.txt,sha256=ibSPWRr6ojS1i11rtBFz2_gkIe68mggj7aeswYfaOo0,16
126
+ cloudnetpy-1.81.0.dist-info/RECORD,,