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,7 +1,7 @@
1
1
  import netCDF4
2
2
  import numpy as np
3
- from matplotlib import cm
4
- from matplotlib.colors import ListedColormap
3
+ import numpy.typing as npt
4
+ from matplotlib.axes import Axes
5
5
  from numpy import ma
6
6
 
7
7
  from cloudnetpy.model_evaluation.model_metadata import MODELS
@@ -12,17 +12,15 @@ def parse_wanted_names(
12
12
  name: str,
13
13
  model: str,
14
14
  variables: list | None = None,
15
+ *,
15
16
  advance: bool = False,
16
17
  ) -> tuple[list, list]:
17
- """Returns standard and advection lists of product types to plot"""
18
- if variables:
19
- names = variables
20
- else:
21
- names = parse_dataset_keys(nc_file, name, advance, model)
18
+ """Returns standard and advection lists of product types to plot."""
19
+ names = variables or parse_dataset_keys(nc_file, name, advance=advance, model=model)
22
20
  standard_n = [n for n in names if name in n and "adv" not in n]
23
21
  standard_n = sort_model2first_element(standard_n, model)
24
22
  advection_n = [n for n in names if name in n and "adv" in n]
25
- model_names = [n for n in names if f"{model}_" in n and not f"_{model}_" in n]
23
+ model_names = [n for n in names if f"{model}_" in n and f"_{model}_" not in n]
26
24
  for i, model_n in enumerate(model_names):
27
25
  advection_n.insert(0 + i, model_n)
28
26
  if len(advection_n) < len(standard_n):
@@ -33,18 +31,18 @@ def parse_wanted_names(
33
31
 
34
32
 
35
33
  def parse_dataset_keys(
36
- nc_file: str, product: str, advance: bool, model: str = ""
34
+ nc_file: str,
35
+ product: str,
36
+ *,
37
+ advance: bool,
38
+ model: str,
37
39
  ) -> list:
38
40
  names = list(netCDF4.Dataset(nc_file).variables.keys())
39
41
  a_names = ["cirrus", "snow"]
40
42
  model_vars = []
41
43
  for n in names:
42
- if model not in n:
43
- model_vars.append(n)
44
- elif model in n and product not in n:
44
+ if model not in n or (model in n and product not in n):
45
45
  model_vars.append(n)
46
- else:
47
- continue
48
46
  if not advance:
49
47
  for a in a_names:
50
48
  for n in names:
@@ -77,7 +75,7 @@ def sort_cycles(names: list, model: str) -> tuple[list, list]:
77
75
 
78
76
 
79
77
  def read_data_characters(nc_file: str, name: str, model: str) -> tuple:
80
- """Gets dimensions and data for plotting"""
78
+ """Gets dimensions and data for plotting."""
81
79
  nc = netCDF4.Dataset(nc_file)
82
80
  data = nc.variables[name][:]
83
81
  data = mask_small_values(data, name)
@@ -85,10 +83,12 @@ def read_data_characters(nc_file: str, name: str, model: str) -> tuple:
85
83
  x = reshape_1d2nd(x, data)
86
84
  try:
87
85
  y = nc.variables[f"{model}_height"][:]
88
- except KeyError:
86
+ except KeyError as err:
89
87
  model_info = MODELS[model]
90
88
  cycles = model_info.cycle
91
- assert cycles is not None
89
+ if cycles is None:
90
+ msg = f"Invalid model: {model}"
91
+ raise RuntimeError(msg) from err
92
92
  cycles_split = [x.strip() for x in cycles.split(",")]
93
93
  cycle = [cycle for cycle in cycles_split if cycle in name]
94
94
  y = nc.variables[f"{model}_{cycle[0]}_height"][:]
@@ -96,13 +96,13 @@ def read_data_characters(nc_file: str, name: str, model: str) -> tuple:
96
96
  try:
97
97
  mask = y.mask
98
98
  if mask.any():
99
- x, y, data = change2one_dim_axes(x, y, data)
99
+ x, y, data = change2one_dim_axes(ma.array(x), y, data)
100
100
  except AttributeError:
101
101
  return data, x, y
102
102
  return data, x, y
103
103
 
104
104
 
105
- def mask_small_values(data: ma.MaskedArray, name: str):
105
+ def mask_small_values(data: ma.MaskedArray, name: str) -> ma.MaskedArray:
106
106
  data[data <= 0] = ma.masked
107
107
  if "lwc" in name:
108
108
  data[data < 1e-5] = ma.masked
@@ -111,35 +111,28 @@ def mask_small_values(data: ma.MaskedArray, name: str):
111
111
  return data
112
112
 
113
113
 
114
- def reshape_1d2nd(one_d: np.ndarray, two_d: np.ndarray) -> np.ndarray:
114
+ def reshape_1d2nd(one_d: npt.NDArray, two_d: npt.NDArray) -> npt.NDArray:
115
115
  new_arr = np.zeros(two_d.shape)
116
116
  for i in range(len(two_d[0])):
117
117
  new_arr[:, i] = one_d
118
118
  return new_arr
119
119
 
120
120
 
121
- def create_segment_values(arrays: list) -> tuple:
122
- # 0=no data, 1=model, 2=intersection, 3=observation
123
- new_array = np.zeros(arrays[0].shape, dtype=int)
124
- for i, array in enumerate(arrays):
125
- new_array[~array] = new_array[~array] + i + 1
126
- new_array[new_array == 2] = 4
127
- new_array[new_array == 3] = 2
128
- new_array[new_array == 4] = 3
129
-
130
- colors = cm.get_cmap("YlGnBu", 256)
131
- newcolors = colors(np.linspace(0, 1, 256))
132
- # No data, model, both, observation
133
- cmap = ListedColormap(["white", "khaki", newcolors[90], newcolors[140]])
134
- return new_array, cmap
121
+ def create_segment_values(model: ma.MaskedArray, obs: ma.MaskedArray) -> npt.NDArray:
122
+ new_array = np.zeros(model.shape, dtype=int)
123
+ new_array[model.mask & obs.mask] = 0 # No data
124
+ new_array[~model.mask & obs.mask] = 1 # Only model
125
+ new_array[~obs.mask & model.mask] = 3 # Only observation
126
+ new_array[(~model.mask == 1) & (~obs.mask == 1)] = 2 # Both
127
+ return new_array
135
128
 
136
129
 
137
- def set_yaxis(ax, max_y: float, min_y: float = 0.0):
130
+ def set_yaxis(ax: Axes, max_y: float, min_y: float = 0.0) -> None:
138
131
  ax.set_ylim(min_y, max_y)
139
132
  ax.set_ylabel("Height (km)", fontsize=13)
140
133
 
141
134
 
142
- def rolling_mean(data: ma.MaskedArray, n: int = 4) -> np.ndarray:
135
+ def rolling_mean(data: ma.MaskedArray, n: int = 4) -> npt.NDArray:
143
136
  mmr = []
144
137
  for i in range(len(data)):
145
138
  if not data[i : i + n].mask.all():
@@ -150,7 +143,9 @@ def rolling_mean(data: ma.MaskedArray, n: int = 4) -> np.ndarray:
150
143
 
151
144
 
152
145
  def change2one_dim_axes(
153
- x: ma.MaskedArray, y: ma.MaskedArray, data: np.ndarray
146
+ x: ma.MaskedArray,
147
+ y: ma.MaskedArray,
148
+ data: npt.NDArray,
154
149
  ) -> tuple:
155
150
  # If any mask in x or y, change 2d to 1d axes values
156
151
  # Common shape need to match 2d data.