cloudnetpy 1.55.20__py3-none-any.whl → 1.55.22__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 (95) hide show
  1. cloudnetpy/categorize/atmos.py +46 -14
  2. cloudnetpy/categorize/atmos_utils.py +11 -1
  3. cloudnetpy/categorize/categorize.py +38 -21
  4. cloudnetpy/categorize/classify.py +31 -9
  5. cloudnetpy/categorize/containers.py +19 -7
  6. cloudnetpy/categorize/droplet.py +24 -8
  7. cloudnetpy/categorize/falling.py +17 -7
  8. cloudnetpy/categorize/freezing.py +19 -5
  9. cloudnetpy/categorize/insects.py +27 -14
  10. cloudnetpy/categorize/lidar.py +38 -36
  11. cloudnetpy/categorize/melting.py +19 -9
  12. cloudnetpy/categorize/model.py +28 -9
  13. cloudnetpy/categorize/mwr.py +4 -2
  14. cloudnetpy/categorize/radar.py +58 -22
  15. cloudnetpy/cloudnetarray.py +15 -6
  16. cloudnetpy/concat_lib.py +39 -16
  17. cloudnetpy/constants.py +7 -0
  18. cloudnetpy/datasource.py +39 -19
  19. cloudnetpy/instruments/basta.py +6 -2
  20. cloudnetpy/instruments/campbell_scientific.py +33 -16
  21. cloudnetpy/instruments/ceilo.py +30 -13
  22. cloudnetpy/instruments/ceilometer.py +76 -37
  23. cloudnetpy/instruments/cl61d.py +8 -3
  24. cloudnetpy/instruments/cloudnet_instrument.py +2 -1
  25. cloudnetpy/instruments/copernicus.py +27 -14
  26. cloudnetpy/instruments/disdrometer/common.py +51 -32
  27. cloudnetpy/instruments/disdrometer/parsivel.py +79 -48
  28. cloudnetpy/instruments/disdrometer/thies.py +10 -6
  29. cloudnetpy/instruments/galileo.py +23 -12
  30. cloudnetpy/instruments/hatpro.py +27 -11
  31. cloudnetpy/instruments/instruments.py +4 -1
  32. cloudnetpy/instruments/lufft.py +20 -11
  33. cloudnetpy/instruments/mira.py +60 -49
  34. cloudnetpy/instruments/mrr.py +31 -20
  35. cloudnetpy/instruments/nc_lidar.py +15 -6
  36. cloudnetpy/instruments/nc_radar.py +31 -22
  37. cloudnetpy/instruments/pollyxt.py +36 -21
  38. cloudnetpy/instruments/radiometrics.py +32 -18
  39. cloudnetpy/instruments/rpg.py +48 -22
  40. cloudnetpy/instruments/rpg_reader.py +39 -30
  41. cloudnetpy/instruments/vaisala.py +39 -27
  42. cloudnetpy/instruments/weather_station.py +15 -11
  43. cloudnetpy/metadata.py +3 -1
  44. cloudnetpy/model_evaluation/file_handler.py +31 -21
  45. cloudnetpy/model_evaluation/metadata.py +3 -1
  46. cloudnetpy/model_evaluation/model_metadata.py +1 -1
  47. cloudnetpy/model_evaluation/plotting/plot_tools.py +20 -15
  48. cloudnetpy/model_evaluation/plotting/plotting.py +114 -64
  49. cloudnetpy/model_evaluation/products/advance_methods.py +48 -28
  50. cloudnetpy/model_evaluation/products/grid_methods.py +44 -19
  51. cloudnetpy/model_evaluation/products/model_products.py +22 -18
  52. cloudnetpy/model_evaluation/products/observation_products.py +15 -9
  53. cloudnetpy/model_evaluation/products/product_resampling.py +14 -4
  54. cloudnetpy/model_evaluation/products/tools.py +16 -7
  55. cloudnetpy/model_evaluation/statistics/statistical_methods.py +28 -15
  56. cloudnetpy/model_evaluation/tests/e2e/conftest.py +3 -3
  57. cloudnetpy/model_evaluation/tests/e2e/process_cf/main.py +9 -5
  58. cloudnetpy/model_evaluation/tests/e2e/process_cf/tests.py +14 -13
  59. cloudnetpy/model_evaluation/tests/e2e/process_iwc/main.py +9 -5
  60. cloudnetpy/model_evaluation/tests/e2e/process_iwc/tests.py +14 -13
  61. cloudnetpy/model_evaluation/tests/e2e/process_lwc/main.py +9 -5
  62. cloudnetpy/model_evaluation/tests/e2e/process_lwc/tests.py +14 -13
  63. cloudnetpy/model_evaluation/tests/unit/conftest.py +11 -11
  64. cloudnetpy/model_evaluation/tests/unit/test_advance_methods.py +33 -27
  65. cloudnetpy/model_evaluation/tests/unit/test_grid_methods.py +83 -83
  66. cloudnetpy/model_evaluation/tests/unit/test_model_products.py +23 -21
  67. cloudnetpy/model_evaluation/tests/unit/test_observation_products.py +24 -25
  68. cloudnetpy/model_evaluation/tests/unit/test_plot_tools.py +40 -39
  69. cloudnetpy/model_evaluation/tests/unit/test_plotting.py +12 -11
  70. cloudnetpy/model_evaluation/tests/unit/test_statistical_methods.py +30 -30
  71. cloudnetpy/model_evaluation/tests/unit/test_tools.py +18 -17
  72. cloudnetpy/model_evaluation/utils.py +3 -2
  73. cloudnetpy/output.py +45 -19
  74. cloudnetpy/plotting/plot_meta.py +35 -11
  75. cloudnetpy/plotting/plotting.py +172 -104
  76. cloudnetpy/products/classification.py +20 -8
  77. cloudnetpy/products/der.py +25 -10
  78. cloudnetpy/products/drizzle.py +41 -26
  79. cloudnetpy/products/drizzle_error.py +10 -5
  80. cloudnetpy/products/drizzle_tools.py +43 -24
  81. cloudnetpy/products/ier.py +10 -5
  82. cloudnetpy/products/iwc.py +16 -9
  83. cloudnetpy/products/lwc.py +34 -12
  84. cloudnetpy/products/mwr_multi.py +4 -1
  85. cloudnetpy/products/mwr_single.py +4 -1
  86. cloudnetpy/products/product_tools.py +33 -10
  87. cloudnetpy/utils.py +175 -74
  88. cloudnetpy/version.py +1 -1
  89. {cloudnetpy-1.55.20.dist-info → cloudnetpy-1.55.22.dist-info}/METADATA +11 -10
  90. cloudnetpy-1.55.22.dist-info/RECORD +114 -0
  91. docs/source/conf.py +2 -2
  92. cloudnetpy-1.55.20.dist-info/RECORD +0 -114
  93. {cloudnetpy-1.55.20.dist-info → cloudnetpy-1.55.22.dist-info}/LICENSE +0 -0
  94. {cloudnetpy-1.55.20.dist-info → cloudnetpy-1.55.22.dist-info}/WHEEL +0 -0
  95. {cloudnetpy-1.55.20.dist-info → cloudnetpy-1.55.22.dist-info}/top_level.txt +0 -0
@@ -10,7 +10,9 @@ from cloudnetpy.products.product_tools import CategorizeBits
10
10
 
11
11
 
12
12
  def generate_classification(
13
- categorize_file: str, output_file: str, uuid: str | None = None
13
+ categorize_file: str,
14
+ output_file: str,
15
+ uuid: str | None = None,
14
16
  ) -> str:
15
17
  """Generates Cloudnet classification product.
16
18
 
@@ -20,14 +22,17 @@ def generate_classification(
20
22
  netCDF file.
21
23
 
22
24
  Args:
25
+ ----
23
26
  categorize_file: Categorize file name.
24
27
  output_file: Output file name.
25
28
  uuid: Set specific UUID for the file.
26
29
 
27
30
  Returns:
31
+ -------
28
32
  str: UUID of the generated file.
29
33
 
30
34
  Examples:
35
+ --------
31
36
  >>> from cloudnetpy.products import generate_classification
32
37
  >>> generate_classification('categorize.nc', 'classification.nc')
33
38
 
@@ -42,18 +47,22 @@ def generate_classification(
42
47
  product_container.append_data(bases, "cloud_base_height_amsl")
43
48
  product_container.append_data(tops, "cloud_top_height_amsl")
44
49
  product_container.append_data(
45
- bases - product_container.altitude, "cloud_base_height_agl"
50
+ bases - product_container.altitude,
51
+ "cloud_base_height_agl",
46
52
  )
47
53
  product_container.append_data(
48
- tops - product_container.altitude, "cloud_top_height_agl"
54
+ tops - product_container.altitude,
55
+ "cloud_top_height_agl",
49
56
  )
50
57
  date = product_container.get_date()
51
58
  attributes = output.add_time_attribute(CLASSIFICATION_ATTRIBUTES, date)
52
59
  output.update_attributes(product_container.data, attributes)
53
- uuid = output.save_product_file(
54
- "classification", product_container, output_file, uuid
60
+ return output.save_product_file(
61
+ "classification",
62
+ product_container,
63
+ output_file,
64
+ uuid,
55
65
  )
56
- return uuid
57
66
 
58
67
 
59
68
  def _get_target_classification(
@@ -98,7 +107,8 @@ def _get_detection_status(categorize_bits: CategorizeBits) -> np.ndarray:
98
107
 
99
108
 
100
109
  def _get_cloud_base_and_top_heights(
101
- classification: np.ndarray, product_container: DataSource
110
+ classification: np.ndarray,
111
+ product_container: DataSource,
102
112
  ) -> tuple[np.ndarray, np.ndarray]:
103
113
  height = product_container.getvar("height")
104
114
  cloud_mask = _find_cloud_mask(classification)
@@ -106,7 +116,9 @@ def _get_cloud_base_and_top_heights(
106
116
  return ma.masked_all(cloud_mask.shape[0]), ma.masked_all(cloud_mask.shape[0])
107
117
  lowest_bases = atmos.find_lowest_cloud_bases(cloud_mask, height)
108
118
  highest_tops = atmos.find_highest_cloud_tops(cloud_mask, height)
109
- assert (highest_tops - lowest_bases >= 0).all()
119
+ if not (highest_tops - lowest_bases >= 0).all():
120
+ msg = "Cloud base higher than cloud top!"
121
+ raise ValueError(msg)
110
122
  return lowest_bases, highest_tops
111
123
 
112
124
 
@@ -1,7 +1,7 @@
1
1
  """Module for creating Cloudnet droplet effective radius
2
2
  using the Frisch et al. 2002 method.
3
3
  """
4
- from collections import namedtuple
4
+ from typing import NamedTuple
5
5
 
6
6
  import numpy as np
7
7
  from numpy import ma
@@ -16,7 +16,14 @@ from cloudnetpy.products.product_tools import (
16
16
  get_is_rain,
17
17
  )
18
18
 
19
- Parameters = namedtuple("Parameters", "ddBZ N dN sigma_x dsigma_x dQ")
19
+
20
+ class Parameters(NamedTuple):
21
+ ddBZ: float
22
+ N: float
23
+ dN: float
24
+ sigma_x: float
25
+ dsigma_x: float
26
+ dQ: float
20
27
 
21
28
 
22
29
  def generate_der(
@@ -34,6 +41,7 @@ def generate_der(
34
41
  liquid water path. The results are written in a netCDF file.
35
42
 
36
43
  Args:
44
+ ----
37
45
  categorize_file: Categorize file name.
38
46
  output_file: Output file name.
39
47
  uuid: Set specific UUID for the file.
@@ -42,9 +50,11 @@ def generate_der(
42
50
  used in Frisch approach.
43
51
 
44
52
  Returns:
53
+ -------
45
54
  UUID of the generated file.
46
55
 
47
56
  Examples:
57
+ --------
48
58
  >>> from cloudnetpy.products import generate_der
49
59
  >>> generate_der('categorize.nc', 'der.nc')
50
60
  >>>
@@ -53,6 +63,7 @@ def generate_der(
53
63
  >>> generate_der('categorize.nc', 'der.nc', parameters=params)
54
64
 
55
65
  References:
66
+ ----------
56
67
  Frisch, S., Shupe, M., Djalalova, I., Feingold, G., & Poellot, M. (2002).
57
68
  The Retrieval of Stratus Cloud Droplet Effective Radius with Cloud Radars,
58
69
  Journal of Atmospheric and Oceanic Technology, 19(6), 835-842.
@@ -113,9 +124,8 @@ class DerSource(DataSource):
113
124
  else:
114
125
  self.parameters = parameters
115
126
 
116
- def append_der(self):
127
+ def append_der(self) -> None:
117
128
  """Estimate liquid droplet effective radius using Frisch et al. 2002."""
118
-
119
129
  params = self.parameters
120
130
  rho_l = 1000 # density of liquid water(kg m-3)
121
131
 
@@ -139,7 +149,11 @@ class DerSource(DataSource):
139
149
  liquid_bases = atmos.find_cloud_bases(is_droplet)
140
150
  liquid_tops = atmos.find_cloud_tops(is_droplet)
141
151
 
142
- for base, top in zip(zip(*np.where(liquid_bases)), zip(*np.where(liquid_tops))):
152
+ for base, top in zip(
153
+ zip(*np.where(liquid_bases), strict=True),
154
+ zip(*np.where(liquid_tops), strict=True),
155
+ strict=True,
156
+ ):
143
157
  ind_t = base[0]
144
158
  idx_layer = np.arange(base[1], top[1] + 1)
145
159
  idx_layer = idx_layer[~Z[ind_t, idx_layer].mask]
@@ -159,7 +173,7 @@ class DerSource(DataSource):
159
173
  B = params.sigma_x * params.dsigma_x
160
174
  C = dZ[ind_t, idx_layer] / (6 * Z[ind_t, idx_layer])
161
175
  der_error[ind_t, idx_layer] = der[ind_t, idx_layer] * ma.sqrt(
162
- A * A + B * B + C * C
176
+ A * A + B * B + C * C,
163
177
  )
164
178
 
165
179
  # der scaled formula (6)
@@ -176,7 +190,7 @@ class DerSource(DataSource):
176
190
  B = 4 * params.sigma_x * params.dsigma_x
177
191
  C = params.dQ / (3 * lwp[ind_t])
178
192
  der_scaled_error[ind_t, idx_layer] = der_scaled[ind_t, idx_layer] * ma.sqrt(
179
- A * A + B * B + C * C
193
+ A * A + B * B + C * C,
180
194
  )
181
195
 
182
196
  N_scaled = ma.masked_less_equal(ma.masked_invalid(N_scaled), 0.0) * 1.0e-6
@@ -197,7 +211,8 @@ class DerSource(DataSource):
197
211
  self.append_data(der_scaled_error, "der_scaled_error")
198
212
 
199
213
  def append_retrieval_status(
200
- self, droplet_classification: DropletClassification
214
+ self,
215
+ droplet_classification: DropletClassification,
201
216
  ) -> None:
202
217
  """Returns information about the status of der retrieval."""
203
218
  is_retrieved = ~self.data["der"][:].mask
@@ -224,7 +239,7 @@ DEFINITIONS = {
224
239
  " of MWR but also the target reflectivity.\n"
225
240
  "Value 4: Surrounding ice: Less crucial! Ice crystals in the vicinity of a\n"
226
241
  " droplet pixel may also bias its reflectivity.\n"
227
- )
242
+ ),
228
243
  }
229
244
 
230
245
 
@@ -271,7 +286,7 @@ def _add_der_error_comment(attributes: dict, der_source: DerSource) -> dict:
271
286
  comment="This variable is an estimate of the random error in effective\n"
272
287
  f"radius assuming an error in Z of ddBZ = {params.ddBZ} in N of\n"
273
288
  f"dN = {params.dN} and in the spectral width dsigma_x = {params.dsigma_x}\n"
274
- f"and in the LWP Q of {params.dQ} kg m-3."
289
+ f"and in the LWP Q of {params.dQ} kg m-3.",
275
290
  )
276
291
  return attributes
277
292
 
@@ -16,7 +16,9 @@ from cloudnetpy.products.drizzle_tools import (
16
16
 
17
17
 
18
18
  def generate_drizzle(
19
- categorize_file: str, output_file: str, uuid: str | None = None
19
+ categorize_file: str,
20
+ output_file: str,
21
+ uuid: str | None = None,
20
22
  ) -> str:
21
23
  """Generates Cloudnet drizzle product.
22
24
 
@@ -24,18 +26,22 @@ def generate_drizzle(
24
26
  cloud radar and lidar measurements. The results are written in a netCDF file.
25
27
 
26
28
  Args:
29
+ ----
27
30
  categorize_file: Categorize file name.
28
31
  output_file: Output file name.
29
32
  uuid: Set specific UUID for the file.
30
33
 
31
34
  Returns:
35
+ -------
32
36
  str: UUID of the generated file.
33
37
 
34
38
  Examples:
39
+ --------
35
40
  >>> from cloudnetpy.products import generate_drizzle
36
41
  >>> generate_drizzle('categorize.nc', 'drizzle.nc')
37
42
 
38
43
  References:
44
+ ----------
39
45
  O’Connor, E.J., R.J. Hogan, and A.J. Illingworth, 2005:
40
46
  Retrieving Stratocumulus Drizzle Parameters Using Doppler Radar and Lidar.
41
47
  J. Appl. Meteor., 44, 14–27, https://doi.org/10.1175/JAM-2181.1
@@ -59,18 +65,19 @@ def generate_drizzle(
59
65
  date = drizzle_source.get_date()
60
66
  attributes = output.add_time_attribute(DRIZZLE_ATTRIBUTES, date)
61
67
  output.update_attributes(drizzle_source.data, attributes)
62
- uuid = output.save_product_file("drizzle", drizzle_source, output_file, uuid)
63
- return uuid
68
+ return output.save_product_file("drizzle", drizzle_source, output_file, uuid)
64
69
 
65
70
 
66
71
  class DrizzleProducts:
67
72
  """Calculates additional quantities from the drizzle properties.
68
73
 
69
74
  Args:
75
+ ----
70
76
  drizzle_source: The :class:`DrizzleSource` instance.
71
77
  drizzle_solver: The :class:`DrizzleSolver` instance.
72
78
 
73
79
  Attributes:
80
+ ----------
74
81
  derived_products (dict): Dictionary containing derived drizzle products:
75
82
  'drizzle_N', 'drizzle_lwc', 'drizzle_lwf', 'v_drizzle', 'v_air'.
76
83
 
@@ -82,7 +89,7 @@ class DrizzleProducts:
82
89
  self._ind_drizzle, self._ind_lut = self._find_indices()
83
90
  self.derived_products = self._calc_derived_products()
84
91
 
85
- def _find_indices(self):
92
+ def _find_indices(self) -> tuple:
86
93
  drizzle_ind = np.where(self._params["Do"])
87
94
  ind_mu = np.searchsorted(self._data.mie["mu"], self._params["mu"][drizzle_ind])
88
95
  ind_dia = np.searchsorted(self._data.mie["Do"], self._params["Do"][drizzle_ind])
@@ -91,7 +98,7 @@ class DrizzleProducts:
91
98
  ind_dia[ind_dia >= n_dia] = n_dia - 1
92
99
  return drizzle_ind, (ind_mu, ind_dia)
93
100
 
94
- def _calc_derived_products(self):
101
+ def _calc_derived_products(self) -> dict:
95
102
  density = self._calc_density()
96
103
  lwc = self._calc_lwc()
97
104
  lwf = self._calc_lwf(lwc)
@@ -105,23 +112,23 @@ class DrizzleProducts:
105
112
  "v_air": v_air,
106
113
  }
107
114
 
108
- def _calc_density(self):
115
+ def _calc_density(self) -> np.ndarray:
109
116
  """Calculates drizzle number density (m-3)."""
110
117
  a = self._data.z * 3.67**6
111
118
  b = self._params["Do"] ** 6
112
119
  return np.divide(a, b, out=np.zeros_like(a), where=b != 0)
113
120
 
114
- def _calc_lwc(self):
121
+ def _calc_lwc(self) -> np.ndarray:
115
122
  """Calculates drizzle liquid water content (kg m-3)"""
116
123
  rho_water = 1000
117
- dia, mu, s = [self._params.get(key) for key in ("Do", "mu", "S")]
118
- assert isinstance(mu, np.ndarray)
119
- assert isinstance(s, np.ndarray)
120
- assert isinstance(dia, np.ndarray)
124
+ dia, mu, s = (self._params.get(key) for key in ("Do", "mu", "S"))
125
+ dia = ma.array(dia)
126
+ mu = ma.array(mu)
127
+ s = ma.array(s)
121
128
  gamma_ratio = gamma(4 + mu) / gamma(3 + mu) / (3.67 + mu)
122
129
  return rho_water / 3 * self._data.beta * s * dia * gamma_ratio
123
130
 
124
- def _calc_lwf(self, lwc_in):
131
+ def _calc_lwf(self, lwc_in) -> np.ndarray:
125
132
  """Calculates drizzle liquid water flux."""
126
133
  flux = ma.copy(lwc_in)
127
134
  flux[self._ind_drizzle] *= (
@@ -130,13 +137,13 @@ class DrizzleProducts:
130
137
  )
131
138
  return flux
132
139
 
133
- def _calc_fall_velocity(self):
140
+ def _calc_fall_velocity(self) -> np.ndarray:
134
141
  """Calculates drizzle droplet fall velocity (m s-1)."""
135
142
  velocity = np.zeros_like(self._params["Do"])
136
143
  velocity[self._ind_drizzle] = -self._data.mie["v"][self._ind_lut]
137
144
  return velocity
138
145
 
139
- def _calc_v_air(self, droplet_velocity):
146
+ def _calc_v_air(self, droplet_velocity) -> np.ndarray:
140
147
  """Calculates vertical air velocity."""
141
148
  velocity = -np.copy(droplet_velocity)
142
149
  velocity[self._ind_drizzle] += self._data.v[self._ind_drizzle]
@@ -147,9 +154,11 @@ class RetrievalStatus:
147
154
  """Estimates the status of drizzle retrievals.
148
155
 
149
156
  Args:
157
+ ----
150
158
  drizzle_class: The :class:`DrizzleClassification` instance.
151
159
 
152
160
  Attributes:
161
+ ----------
153
162
  drizzle_class: The :class:`DrizzleClassification` instance.
154
163
  retrieval_status (ndarray): 2D array containing drizzle retrieval
155
164
  status information.
@@ -160,37 +169,39 @@ class RetrievalStatus:
160
169
  self.retrieval_status: np.ndarray = np.array([])
161
170
  self._get_retrieval_status()
162
171
 
163
- def _get_retrieval_status(self):
172
+ def _get_retrieval_status(self) -> None:
164
173
  self.retrieval_status = np.copy(self.drizzle_class.drizzle).astype(int)
165
174
  self._find_retrieval_below_melting()
166
175
  self.retrieval_status[self.drizzle_class.would_be_drizzle == 1] = 3
167
176
  self._find_retrieval_in_warm_liquid()
168
177
  self.retrieval_status[self.drizzle_class.is_rain == 1, :] = 5
169
178
 
170
- def _find_retrieval_below_melting(self):
179
+ def _find_retrieval_below_melting(self) -> None:
171
180
  cold_rain = utils.transpose(self.drizzle_class.cold_rain)
172
181
  below_melting = cold_rain * self.drizzle_class.drizzle
173
182
  self.retrieval_status[below_melting == 1] = 2
174
183
 
175
- def _find_retrieval_in_warm_liquid(self):
184
+ def _find_retrieval_in_warm_liquid(self) -> None:
176
185
  in_warm_liquid = (self.retrieval_status == 0) * self.drizzle_class.warm_liquid
177
186
  self.retrieval_status[in_warm_liquid == 1] = 4
178
187
 
179
188
 
180
- def _screen_rain(results: dict, classification: DrizzleClassification):
189
+ def _screen_rain(results: dict, classification: DrizzleClassification) -> dict:
181
190
  """Removes rainy profiles from drizzle variables.."""
182
- for key in results.keys():
191
+ for key in results:
183
192
  if not utils.isscalar(results[key]):
184
193
  results[key][classification.is_rain, :] = 0
185
194
  return results
186
195
 
187
196
 
188
- def _append_data(drizzle_data: DrizzleSource, results: dict):
197
+ def _append_data(drizzle_data: DrizzleSource, results: dict) -> None:
189
198
  """Save retrieved fields to the drizzle_data object."""
190
199
  for key, value in results.items():
191
200
  if key != "drizzle_retrieval_status":
192
- value = ma.masked_where(value == 0, value)
193
- drizzle_data.append_data(value, key)
201
+ arr = ma.masked_where(value == 0, value)
202
+ else:
203
+ arr = value
204
+ drizzle_data.append_data(arr, key)
194
205
 
195
206
 
196
207
  DRIZZLE_ATTRIBUTES = {
@@ -200,7 +211,8 @@ DRIZZLE_ATTRIBUTES = {
200
211
  ancillary_variables="drizzle_N_error drizzle_N_bias",
201
212
  ),
202
213
  "drizzle_N_error": MetaData(
203
- long_name="Random error in drizzle number concentration", units="dB"
214
+ long_name="Random error in drizzle number concentration",
215
+ units="dB",
204
216
  ),
205
217
  "drizzle_N_bias": MetaData(
206
218
  long_name="Possible bias in drizzle number concentration",
@@ -240,7 +252,8 @@ DRIZZLE_ATTRIBUTES = {
240
252
  comment="Positive values are towards the ground.",
241
253
  ),
242
254
  "v_drizzle_error": MetaData(
243
- long_name="Random error in drizzle droplet fall velocity", units="dB"
255
+ long_name="Random error in drizzle droplet fall velocity",
256
+ units="dB",
244
257
  ),
245
258
  "v_drizzle_bias": MetaData(
246
259
  long_name="Possible bias in drizzle droplet fall velocity",
@@ -254,7 +267,8 @@ DRIZZLE_ATTRIBUTES = {
254
267
  standard_name="upward_air_velocity",
255
268
  ),
256
269
  "v_air_error": MetaData(
257
- long_name="Random error in vertical air velocity", units="dB"
270
+ long_name="Random error in vertical air velocity",
271
+ units="dB",
258
272
  ),
259
273
  "Do": MetaData(
260
274
  long_name="Drizzle median diameter",
@@ -289,6 +303,7 @@ DRIZZLE_ATTRIBUTES = {
289
303
  ),
290
304
  "beta_corr": MetaData(long_name="Lidar backscatter correction factor", units="1"),
291
305
  "drizzle_retrieval_status": MetaData(
292
- long_name="Drizzle parameter retrieval status", units="1"
306
+ long_name="Drizzle parameter retrieval status",
307
+ units="1",
293
308
  ),
294
309
  }
@@ -9,15 +9,18 @@ MU_ERROR_SMALL = 0.25
9
9
 
10
10
 
11
11
  def get_drizzle_error(
12
- categorize: DrizzleSource, drizzle_parameters: DrizzleSolver
12
+ categorize: DrizzleSource,
13
+ drizzle_parameters: DrizzleSolver,
13
14
  ) -> dict:
14
15
  """Estimates error and bias for drizzle classification.
15
16
 
16
17
  Args:
18
+ ----
17
19
  categorize: The :class:`DrizzleSource` instance.
18
20
  drizzle_parameters: The :class:`DrizzleSolver` instance.
19
21
 
20
22
  Returns:
23
+ -------
21
24
  dict: Dictionary containing information of estimated error and bias for drizzle
22
25
 
23
26
  """
@@ -29,8 +32,7 @@ def get_drizzle_error(
29
32
  z_error = np.full(categorize.z.shape, z_error)
30
33
  error_input = z_error, bias_error
31
34
  bias_input = _read_input_uncertainty(categorize, "bias")
32
- errors = _calc_errors(drizzle_indices, error_input, bias_input)
33
- return errors
35
+ return _calc_errors(drizzle_indices, error_input, bias_input)
34
36
 
35
37
 
36
38
  def _get_drizzle_indices(diameter: np.ndarray) -> dict:
@@ -100,7 +102,9 @@ def _calc_parameter_biases(bias_input: tuple) -> dict:
100
102
 
101
103
 
102
104
  def _add_supplementary_errors(
103
- results: dict, drizzle_indices: dict, error_input: tuple
105
+ results: dict,
106
+ drizzle_indices: dict,
107
+ error_input: tuple,
104
108
  ) -> dict:
105
109
  def _calc_n_error() -> ma.MaskedArray:
106
110
  z_error = error_input[0]
@@ -139,6 +143,7 @@ def _calc_error(
139
143
  scale: float,
140
144
  weights: tuple,
141
145
  error_input: tuple,
146
+ *,
142
147
  add_mu: bool = False,
143
148
  add_mu_small: bool = False,
144
149
  ) -> ma.MaskedArray:
@@ -156,7 +161,7 @@ def _stack_errors(
156
161
  error_small=None,
157
162
  error_tiny=None,
158
163
  ) -> ma.MaskedArray:
159
- def _add_error_component(source: np.ndarray, ind: tuple):
164
+ def _add_error_component(source: np.ndarray, ind: tuple) -> None:
160
165
  error[ind] = source[ind]
161
166
 
162
167
  error = ma.zeros(error_in.shape)