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.
- cloudnetpy/categorize/atmos.py +46 -14
- cloudnetpy/categorize/atmos_utils.py +11 -1
- cloudnetpy/categorize/categorize.py +38 -21
- cloudnetpy/categorize/classify.py +31 -9
- cloudnetpy/categorize/containers.py +19 -7
- cloudnetpy/categorize/droplet.py +24 -8
- cloudnetpy/categorize/falling.py +17 -7
- cloudnetpy/categorize/freezing.py +19 -5
- cloudnetpy/categorize/insects.py +27 -14
- cloudnetpy/categorize/lidar.py +38 -36
- cloudnetpy/categorize/melting.py +19 -9
- cloudnetpy/categorize/model.py +28 -9
- cloudnetpy/categorize/mwr.py +4 -2
- cloudnetpy/categorize/radar.py +58 -22
- cloudnetpy/cloudnetarray.py +15 -6
- cloudnetpy/concat_lib.py +39 -16
- cloudnetpy/constants.py +7 -0
- cloudnetpy/datasource.py +39 -19
- cloudnetpy/instruments/basta.py +6 -2
- cloudnetpy/instruments/campbell_scientific.py +33 -16
- cloudnetpy/instruments/ceilo.py +30 -13
- cloudnetpy/instruments/ceilometer.py +76 -37
- cloudnetpy/instruments/cl61d.py +8 -3
- cloudnetpy/instruments/cloudnet_instrument.py +2 -1
- cloudnetpy/instruments/copernicus.py +27 -14
- cloudnetpy/instruments/disdrometer/common.py +51 -32
- cloudnetpy/instruments/disdrometer/parsivel.py +79 -48
- cloudnetpy/instruments/disdrometer/thies.py +10 -6
- cloudnetpy/instruments/galileo.py +23 -12
- cloudnetpy/instruments/hatpro.py +27 -11
- cloudnetpy/instruments/instruments.py +4 -1
- cloudnetpy/instruments/lufft.py +20 -11
- cloudnetpy/instruments/mira.py +60 -49
- cloudnetpy/instruments/mrr.py +31 -20
- cloudnetpy/instruments/nc_lidar.py +15 -6
- cloudnetpy/instruments/nc_radar.py +31 -22
- cloudnetpy/instruments/pollyxt.py +36 -21
- cloudnetpy/instruments/radiometrics.py +32 -18
- cloudnetpy/instruments/rpg.py +48 -22
- cloudnetpy/instruments/rpg_reader.py +39 -30
- cloudnetpy/instruments/vaisala.py +39 -27
- cloudnetpy/instruments/weather_station.py +15 -11
- cloudnetpy/metadata.py +3 -1
- cloudnetpy/model_evaluation/file_handler.py +31 -21
- cloudnetpy/model_evaluation/metadata.py +3 -1
- cloudnetpy/model_evaluation/model_metadata.py +1 -1
- cloudnetpy/model_evaluation/plotting/plot_tools.py +20 -15
- cloudnetpy/model_evaluation/plotting/plotting.py +114 -64
- cloudnetpy/model_evaluation/products/advance_methods.py +48 -28
- cloudnetpy/model_evaluation/products/grid_methods.py +44 -19
- cloudnetpy/model_evaluation/products/model_products.py +22 -18
- cloudnetpy/model_evaluation/products/observation_products.py +15 -9
- cloudnetpy/model_evaluation/products/product_resampling.py +14 -4
- cloudnetpy/model_evaluation/products/tools.py +16 -7
- cloudnetpy/model_evaluation/statistics/statistical_methods.py +28 -15
- cloudnetpy/model_evaluation/tests/e2e/conftest.py +3 -3
- cloudnetpy/model_evaluation/tests/e2e/process_cf/main.py +9 -5
- cloudnetpy/model_evaluation/tests/e2e/process_cf/tests.py +14 -13
- cloudnetpy/model_evaluation/tests/e2e/process_iwc/main.py +9 -5
- cloudnetpy/model_evaluation/tests/e2e/process_iwc/tests.py +14 -13
- cloudnetpy/model_evaluation/tests/e2e/process_lwc/main.py +9 -5
- cloudnetpy/model_evaluation/tests/e2e/process_lwc/tests.py +14 -13
- cloudnetpy/model_evaluation/tests/unit/conftest.py +11 -11
- cloudnetpy/model_evaluation/tests/unit/test_advance_methods.py +33 -27
- cloudnetpy/model_evaluation/tests/unit/test_grid_methods.py +83 -83
- cloudnetpy/model_evaluation/tests/unit/test_model_products.py +23 -21
- cloudnetpy/model_evaluation/tests/unit/test_observation_products.py +24 -25
- cloudnetpy/model_evaluation/tests/unit/test_plot_tools.py +40 -39
- cloudnetpy/model_evaluation/tests/unit/test_plotting.py +12 -11
- cloudnetpy/model_evaluation/tests/unit/test_statistical_methods.py +30 -30
- cloudnetpy/model_evaluation/tests/unit/test_tools.py +18 -17
- cloudnetpy/model_evaluation/utils.py +3 -2
- cloudnetpy/output.py +45 -19
- cloudnetpy/plotting/plot_meta.py +35 -11
- cloudnetpy/plotting/plotting.py +172 -104
- cloudnetpy/products/classification.py +20 -8
- cloudnetpy/products/der.py +25 -10
- cloudnetpy/products/drizzle.py +41 -26
- cloudnetpy/products/drizzle_error.py +10 -5
- cloudnetpy/products/drizzle_tools.py +43 -24
- cloudnetpy/products/ier.py +10 -5
- cloudnetpy/products/iwc.py +16 -9
- cloudnetpy/products/lwc.py +34 -12
- cloudnetpy/products/mwr_multi.py +4 -1
- cloudnetpy/products/mwr_single.py +4 -1
- cloudnetpy/products/product_tools.py +33 -10
- cloudnetpy/utils.py +175 -74
- cloudnetpy/version.py +1 -1
- {cloudnetpy-1.55.20.dist-info → cloudnetpy-1.55.22.dist-info}/METADATA +11 -10
- cloudnetpy-1.55.22.dist-info/RECORD +114 -0
- docs/source/conf.py +2 -2
- cloudnetpy-1.55.20.dist-info/RECORD +0 -114
- {cloudnetpy-1.55.20.dist-info → cloudnetpy-1.55.22.dist-info}/LICENSE +0 -0
- {cloudnetpy-1.55.20.dist-info → cloudnetpy-1.55.22.dist-info}/WHEEL +0 -0
- {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,
|
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,
|
50
|
+
bases - product_container.altitude,
|
51
|
+
"cloud_base_height_agl",
|
46
52
|
)
|
47
53
|
product_container.append_data(
|
48
|
-
tops - product_container.altitude,
|
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
|
-
|
54
|
-
"classification",
|
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,
|
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
|
-
|
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
|
|
cloudnetpy/products/der.py
CHANGED
@@ -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
|
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
|
-
|
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(
|
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,
|
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
|
|
cloudnetpy/products/drizzle.py
CHANGED
@@ -16,7 +16,9 @@ from cloudnetpy.products.drizzle_tools import (
|
|
16
16
|
|
17
17
|
|
18
18
|
def generate_drizzle(
|
19
|
-
categorize_file: str,
|
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
|
-
|
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 =
|
118
|
-
|
119
|
-
|
120
|
-
|
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
|
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
|
-
|
193
|
-
|
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",
|
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",
|
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",
|
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",
|
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,
|
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
|
-
|
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,
|
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)
|