cloudnetpy 1.80.8__tar.gz → 1.81.0__tar.gz
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-1.80.8/cloudnetpy.egg-info → cloudnetpy-1.81.0}/PKG-INFO +2 -1
- cloudnetpy-1.81.0/cloudnetpy/categorize/__init__.py +1 -0
- {cloudnetpy-1.80.8 → cloudnetpy-1.81.0}/cloudnetpy/categorize/atmos_utils.py +31 -27
- {cloudnetpy-1.80.8 → cloudnetpy-1.81.0}/cloudnetpy/categorize/attenuations/__init__.py +4 -4
- {cloudnetpy-1.80.8 → cloudnetpy-1.81.0}/cloudnetpy/categorize/attenuations/liquid_attenuation.py +7 -5
- {cloudnetpy-1.80.8 → cloudnetpy-1.81.0}/cloudnetpy/categorize/attenuations/melting_attenuation.py +3 -3
- {cloudnetpy-1.80.8 → cloudnetpy-1.81.0}/cloudnetpy/categorize/attenuations/rain_attenuation.py +4 -4
- {cloudnetpy-1.80.8 → cloudnetpy-1.81.0}/cloudnetpy/categorize/categorize.py +25 -11
- {cloudnetpy-1.80.8 → cloudnetpy-1.81.0}/cloudnetpy/categorize/classify.py +9 -8
- {cloudnetpy-1.80.8 → cloudnetpy-1.81.0}/cloudnetpy/categorize/containers.py +13 -10
- {cloudnetpy-1.80.8 → cloudnetpy-1.81.0}/cloudnetpy/categorize/disdrometer.py +5 -3
- {cloudnetpy-1.80.8 → cloudnetpy-1.81.0}/cloudnetpy/categorize/droplet.py +12 -9
- {cloudnetpy-1.80.8 → cloudnetpy-1.81.0}/cloudnetpy/categorize/falling.py +9 -8
- {cloudnetpy-1.80.8 → cloudnetpy-1.81.0}/cloudnetpy/categorize/freezing.py +10 -7
- {cloudnetpy-1.80.8 → cloudnetpy-1.81.0}/cloudnetpy/categorize/insects.py +18 -17
- {cloudnetpy-1.80.8 → cloudnetpy-1.81.0}/cloudnetpy/categorize/lidar.py +7 -3
- {cloudnetpy-1.80.8 → cloudnetpy-1.81.0}/cloudnetpy/categorize/melting.py +16 -15
- {cloudnetpy-1.80.8 → cloudnetpy-1.81.0}/cloudnetpy/categorize/model.py +17 -10
- {cloudnetpy-1.80.8 → cloudnetpy-1.81.0}/cloudnetpy/categorize/mwr.py +5 -3
- {cloudnetpy-1.80.8 → cloudnetpy-1.81.0}/cloudnetpy/categorize/radar.py +15 -13
- {cloudnetpy-1.80.8 → cloudnetpy-1.81.0}/cloudnetpy/cli.py +10 -8
- {cloudnetpy-1.80.8 → cloudnetpy-1.81.0}/cloudnetpy/cloudnetarray.py +8 -7
- {cloudnetpy-1.80.8 → cloudnetpy-1.81.0}/cloudnetpy/concat_lib.py +29 -20
- {cloudnetpy-1.80.8 → cloudnetpy-1.81.0}/cloudnetpy/datasource.py +26 -21
- {cloudnetpy-1.80.8 → cloudnetpy-1.81.0}/cloudnetpy/exceptions.py +12 -10
- {cloudnetpy-1.80.8 → cloudnetpy-1.81.0}/cloudnetpy/instruments/basta.py +19 -9
- {cloudnetpy-1.80.8 → cloudnetpy-1.81.0}/cloudnetpy/instruments/bowtie.py +18 -11
- {cloudnetpy-1.80.8 → cloudnetpy-1.81.0}/cloudnetpy/instruments/ceilo.py +22 -10
- {cloudnetpy-1.80.8 → cloudnetpy-1.81.0}/cloudnetpy/instruments/ceilometer.py +33 -34
- {cloudnetpy-1.80.8 → cloudnetpy-1.81.0}/cloudnetpy/instruments/cl61d.py +5 -3
- {cloudnetpy-1.80.8 → cloudnetpy-1.81.0}/cloudnetpy/instruments/cloudnet_instrument.py +7 -7
- {cloudnetpy-1.80.8 → cloudnetpy-1.81.0}/cloudnetpy/instruments/copernicus.py +16 -7
- {cloudnetpy-1.80.8 → cloudnetpy-1.81.0}/cloudnetpy/instruments/disdrometer/common.py +5 -4
- {cloudnetpy-1.80.8 → cloudnetpy-1.81.0}/cloudnetpy/instruments/disdrometer/parsivel.py +14 -9
- {cloudnetpy-1.80.8 → cloudnetpy-1.81.0}/cloudnetpy/instruments/disdrometer/thies.py +11 -7
- {cloudnetpy-1.80.8 → cloudnetpy-1.81.0}/cloudnetpy/instruments/fd12p.py +7 -6
- {cloudnetpy-1.80.8 → cloudnetpy-1.81.0}/cloudnetpy/instruments/galileo.py +16 -7
- {cloudnetpy-1.80.8 → cloudnetpy-1.81.0}/cloudnetpy/instruments/hatpro.py +33 -24
- {cloudnetpy-1.80.8 → cloudnetpy-1.81.0}/cloudnetpy/instruments/lufft.py +6 -4
- {cloudnetpy-1.80.8 → cloudnetpy-1.81.0}/cloudnetpy/instruments/mira.py +33 -19
- {cloudnetpy-1.80.8 → cloudnetpy-1.81.0}/cloudnetpy/instruments/mrr.py +12 -12
- {cloudnetpy-1.80.8 → cloudnetpy-1.81.0}/cloudnetpy/instruments/nc_lidar.py +1 -1
- {cloudnetpy-1.80.8 → cloudnetpy-1.81.0}/cloudnetpy/instruments/nc_radar.py +8 -8
- {cloudnetpy-1.80.8 → cloudnetpy-1.81.0}/cloudnetpy/instruments/pollyxt.py +19 -12
- {cloudnetpy-1.80.8 → cloudnetpy-1.81.0}/cloudnetpy/instruments/radiometrics.py +17 -10
- {cloudnetpy-1.80.8 → cloudnetpy-1.81.0}/cloudnetpy/instruments/rain_e_h3.py +9 -5
- {cloudnetpy-1.80.8 → cloudnetpy-1.81.0}/cloudnetpy/instruments/rpg.py +32 -21
- {cloudnetpy-1.80.8 → cloudnetpy-1.81.0}/cloudnetpy/instruments/rpg_reader.py +15 -12
- {cloudnetpy-1.80.8 → cloudnetpy-1.81.0}/cloudnetpy/instruments/vaisala.py +32 -24
- {cloudnetpy-1.80.8 → cloudnetpy-1.81.0}/cloudnetpy/instruments/weather_station.py +22 -19
- {cloudnetpy-1.80.8 → cloudnetpy-1.81.0}/cloudnetpy/model_evaluation/file_handler.py +27 -29
- {cloudnetpy-1.80.8 → cloudnetpy-1.81.0}/cloudnetpy/model_evaluation/plotting/plot_tools.py +7 -5
- {cloudnetpy-1.80.8 → cloudnetpy-1.81.0}/cloudnetpy/model_evaluation/plotting/plotting.py +41 -32
- {cloudnetpy-1.80.8 → cloudnetpy-1.81.0}/cloudnetpy/model_evaluation/products/advance_methods.py +38 -34
- {cloudnetpy-1.80.8 → cloudnetpy-1.81.0}/cloudnetpy/model_evaluation/products/grid_methods.py +10 -9
- {cloudnetpy-1.80.8 → cloudnetpy-1.81.0}/cloudnetpy/model_evaluation/products/model_products.py +15 -9
- {cloudnetpy-1.80.8 → cloudnetpy-1.81.0}/cloudnetpy/model_evaluation/products/observation_products.py +12 -10
- {cloudnetpy-1.80.8 → cloudnetpy-1.81.0}/cloudnetpy/model_evaluation/products/product_resampling.py +11 -7
- {cloudnetpy-1.80.8 → cloudnetpy-1.81.0}/cloudnetpy/model_evaluation/products/tools.py +18 -14
- {cloudnetpy-1.80.8 → cloudnetpy-1.81.0}/cloudnetpy/model_evaluation/statistics/statistical_methods.py +6 -5
- {cloudnetpy-1.80.8 → cloudnetpy-1.81.0}/cloudnetpy/model_evaluation/tests/unit/test_plotting.py +18 -25
- cloudnetpy-1.81.0/cloudnetpy/model_evaluation/utils.py +6 -0
- {cloudnetpy-1.80.8 → cloudnetpy-1.81.0}/cloudnetpy/output.py +15 -32
- {cloudnetpy-1.80.8 → cloudnetpy-1.81.0}/cloudnetpy/plotting/plotting.py +22 -12
- {cloudnetpy-1.80.8 → cloudnetpy-1.81.0}/cloudnetpy/products/classification.py +15 -9
- {cloudnetpy-1.80.8 → cloudnetpy-1.81.0}/cloudnetpy/products/der.py +24 -19
- {cloudnetpy-1.80.8 → cloudnetpy-1.81.0}/cloudnetpy/products/drizzle.py +21 -13
- {cloudnetpy-1.80.8 → cloudnetpy-1.81.0}/cloudnetpy/products/drizzle_error.py +8 -7
- {cloudnetpy-1.80.8 → cloudnetpy-1.81.0}/cloudnetpy/products/drizzle_tools.py +27 -23
- {cloudnetpy-1.80.8 → cloudnetpy-1.81.0}/cloudnetpy/products/epsilon.py +6 -5
- {cloudnetpy-1.80.8 → cloudnetpy-1.81.0}/cloudnetpy/products/ier.py +11 -5
- {cloudnetpy-1.80.8 → cloudnetpy-1.81.0}/cloudnetpy/products/iwc.py +18 -9
- {cloudnetpy-1.80.8 → cloudnetpy-1.81.0}/cloudnetpy/products/lwc.py +41 -31
- {cloudnetpy-1.80.8 → cloudnetpy-1.81.0}/cloudnetpy/products/mwr_tools.py +30 -19
- {cloudnetpy-1.80.8 → cloudnetpy-1.81.0}/cloudnetpy/products/product_tools.py +23 -19
- {cloudnetpy-1.80.8 → cloudnetpy-1.81.0}/cloudnetpy/utils.py +84 -98
- {cloudnetpy-1.80.8 → cloudnetpy-1.81.0}/cloudnetpy/version.py +2 -2
- {cloudnetpy-1.80.8 → cloudnetpy-1.81.0/cloudnetpy.egg-info}/PKG-INFO +2 -1
- {cloudnetpy-1.80.8 → cloudnetpy-1.81.0}/cloudnetpy.egg-info/requires.txt +1 -0
- {cloudnetpy-1.80.8 → cloudnetpy-1.81.0}/pyproject.toml +1 -1
- cloudnetpy-1.80.8/cloudnetpy/categorize/__init__.py +0 -1
- cloudnetpy-1.80.8/cloudnetpy/model_evaluation/utils.py +0 -6
- {cloudnetpy-1.80.8 → cloudnetpy-1.81.0}/LICENSE +0 -0
- {cloudnetpy-1.80.8 → cloudnetpy-1.81.0}/MANIFEST.in +0 -0
- {cloudnetpy-1.80.8 → cloudnetpy-1.81.0}/README.md +0 -0
- {cloudnetpy-1.80.8 → cloudnetpy-1.81.0}/cloudnetpy/__init__.py +0 -0
- {cloudnetpy-1.80.8 → cloudnetpy-1.81.0}/cloudnetpy/categorize/attenuation.py +0 -0
- {cloudnetpy-1.80.8 → cloudnetpy-1.81.0}/cloudnetpy/categorize/attenuations/gas_attenuation.py +0 -0
- {cloudnetpy-1.80.8 → cloudnetpy-1.81.0}/cloudnetpy/categorize/itu.py +0 -0
- {cloudnetpy-1.80.8 → cloudnetpy-1.81.0}/cloudnetpy/constants.py +0 -0
- {cloudnetpy-1.80.8 → cloudnetpy-1.81.0}/cloudnetpy/instruments/__init__.py +0 -0
- {cloudnetpy-1.80.8 → cloudnetpy-1.81.0}/cloudnetpy/instruments/disdrometer/__init__.py +0 -0
- {cloudnetpy-1.80.8 → cloudnetpy-1.81.0}/cloudnetpy/instruments/instruments.py +0 -0
- {cloudnetpy-1.80.8 → cloudnetpy-1.81.0}/cloudnetpy/instruments/toa5.py +0 -0
- {cloudnetpy-1.80.8 → cloudnetpy-1.81.0}/cloudnetpy/metadata.py +0 -0
- {cloudnetpy-1.80.8 → cloudnetpy-1.81.0}/cloudnetpy/model_evaluation/__init__.py +0 -0
- {cloudnetpy-1.80.8 → cloudnetpy-1.81.0}/cloudnetpy/model_evaluation/metadata.py +0 -0
- {cloudnetpy-1.80.8 → cloudnetpy-1.81.0}/cloudnetpy/model_evaluation/model_metadata.py +0 -0
- {cloudnetpy-1.80.8 → cloudnetpy-1.81.0}/cloudnetpy/model_evaluation/plotting/__init__.py +0 -0
- {cloudnetpy-1.80.8 → cloudnetpy-1.81.0}/cloudnetpy/model_evaluation/plotting/plot_meta.py +0 -0
- {cloudnetpy-1.80.8 → cloudnetpy-1.81.0}/cloudnetpy/model_evaluation/products/__init__.py +0 -0
- {cloudnetpy-1.80.8 → cloudnetpy-1.81.0}/cloudnetpy/model_evaluation/statistics/__init__.py +0 -0
- {cloudnetpy-1.80.8 → cloudnetpy-1.81.0}/cloudnetpy/model_evaluation/tests/__init__.py +0 -0
- {cloudnetpy-1.80.8 → cloudnetpy-1.81.0}/cloudnetpy/model_evaluation/tests/e2e/__init__.py +0 -0
- {cloudnetpy-1.80.8 → cloudnetpy-1.81.0}/cloudnetpy/model_evaluation/tests/e2e/conftest.py +0 -0
- {cloudnetpy-1.80.8 → cloudnetpy-1.81.0}/cloudnetpy/model_evaluation/tests/e2e/process_cf/__init__.py +0 -0
- {cloudnetpy-1.80.8 → cloudnetpy-1.81.0}/cloudnetpy/model_evaluation/tests/e2e/process_cf/main.py +0 -0
- {cloudnetpy-1.80.8 → cloudnetpy-1.81.0}/cloudnetpy/model_evaluation/tests/e2e/process_cf/tests.py +0 -0
- {cloudnetpy-1.80.8 → cloudnetpy-1.81.0}/cloudnetpy/model_evaluation/tests/e2e/process_iwc/__init__.py +0 -0
- {cloudnetpy-1.80.8 → cloudnetpy-1.81.0}/cloudnetpy/model_evaluation/tests/e2e/process_iwc/main.py +0 -0
- {cloudnetpy-1.80.8 → cloudnetpy-1.81.0}/cloudnetpy/model_evaluation/tests/e2e/process_iwc/tests.py +0 -0
- {cloudnetpy-1.80.8 → cloudnetpy-1.81.0}/cloudnetpy/model_evaluation/tests/e2e/process_lwc/__init__.py +0 -0
- {cloudnetpy-1.80.8 → cloudnetpy-1.81.0}/cloudnetpy/model_evaluation/tests/e2e/process_lwc/main.py +0 -0
- {cloudnetpy-1.80.8 → cloudnetpy-1.81.0}/cloudnetpy/model_evaluation/tests/e2e/process_lwc/tests.py +0 -0
- {cloudnetpy-1.80.8 → cloudnetpy-1.81.0}/cloudnetpy/model_evaluation/tests/unit/__init__.py +0 -0
- {cloudnetpy-1.80.8 → cloudnetpy-1.81.0}/cloudnetpy/model_evaluation/tests/unit/conftest.py +0 -0
- {cloudnetpy-1.80.8 → cloudnetpy-1.81.0}/cloudnetpy/model_evaluation/tests/unit/test_advance_methods.py +0 -0
- {cloudnetpy-1.80.8 → cloudnetpy-1.81.0}/cloudnetpy/model_evaluation/tests/unit/test_grid_methods.py +0 -0
- {cloudnetpy-1.80.8 → cloudnetpy-1.81.0}/cloudnetpy/model_evaluation/tests/unit/test_model_products.py +0 -0
- {cloudnetpy-1.80.8 → cloudnetpy-1.81.0}/cloudnetpy/model_evaluation/tests/unit/test_observation_products.py +0 -0
- {cloudnetpy-1.80.8 → cloudnetpy-1.81.0}/cloudnetpy/model_evaluation/tests/unit/test_plot_tools.py +0 -0
- {cloudnetpy-1.80.8 → cloudnetpy-1.81.0}/cloudnetpy/model_evaluation/tests/unit/test_statistical_methods.py +0 -0
- {cloudnetpy-1.80.8 → cloudnetpy-1.81.0}/cloudnetpy/model_evaluation/tests/unit/test_tools.py +0 -0
- {cloudnetpy-1.80.8 → cloudnetpy-1.81.0}/cloudnetpy/plotting/__init__.py +0 -0
- {cloudnetpy-1.80.8 → cloudnetpy-1.81.0}/cloudnetpy/plotting/plot_meta.py +0 -0
- {cloudnetpy-1.80.8 → cloudnetpy-1.81.0}/cloudnetpy/products/__init__.py +0 -0
- {cloudnetpy-1.80.8 → cloudnetpy-1.81.0}/cloudnetpy/products/mie_lu_tables.nc +0 -0
- {cloudnetpy-1.80.8 → cloudnetpy-1.81.0}/cloudnetpy/py.typed +0 -0
- {cloudnetpy-1.80.8 → cloudnetpy-1.81.0}/cloudnetpy.egg-info/SOURCES.txt +0 -0
- {cloudnetpy-1.80.8 → cloudnetpy-1.81.0}/cloudnetpy.egg-info/dependency_links.txt +0 -0
- {cloudnetpy-1.80.8 → cloudnetpy-1.81.0}/cloudnetpy.egg-info/entry_points.txt +0 -0
- {cloudnetpy-1.80.8 → cloudnetpy-1.81.0}/cloudnetpy.egg-info/top_level.txt +0 -0
- {cloudnetpy-1.80.8 → cloudnetpy-1.81.0}/docs/source/conf.py +0 -0
- {cloudnetpy-1.80.8 → cloudnetpy-1.81.0}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: cloudnetpy
|
3
|
-
Version: 1.
|
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 @@
|
|
1
|
+
from .categorize import CategorizeInput, generate_categorize
|
@@ -9,7 +9,7 @@ import cloudnetpy.constants as con
|
|
9
9
|
from cloudnetpy import utils
|
10
10
|
|
11
11
|
|
12
|
-
def calc_wet_bulb_temperature(model_data: dict) ->
|
12
|
+
def calc_wet_bulb_temperature(model_data: dict) -> npt.NDArray:
|
13
13
|
"""Calculate wet-bulb temperature iteratively.
|
14
14
|
|
15
15
|
Args:
|
@@ -30,7 +30,7 @@ def calc_wet_bulb_temperature(model_data: dict) -> np.ndarray:
|
|
30
30
|
W = calc_mixing_ratio(vp, pressure)
|
31
31
|
L_v_0 = 2501e3 # Latent heat of vaporization at 0degC (J kg-1)
|
32
32
|
|
33
|
-
def f(tw):
|
33
|
+
def f(tw: npt.NDArray) -> npt.NDArray:
|
34
34
|
svp = calc_saturation_vapor_pressure(c2k(tw))
|
35
35
|
W_s = calc_mixing_ratio(svp, pressure)
|
36
36
|
C_p_w = 0.0265 * tw**2 - 1.7688 * tw + 4205.6 # Eq. 6 (J kg-1 C-1)
|
@@ -86,17 +86,17 @@ def calc_vapor_pressure(
|
|
86
86
|
)
|
87
87
|
|
88
88
|
|
89
|
-
def c2k(temp:
|
89
|
+
def c2k(temp: npt.NDArray) -> npt.NDArray:
|
90
90
|
"""Converts Celsius to Kelvins."""
|
91
91
|
return ma.array(temp) + 273.15
|
92
92
|
|
93
93
|
|
94
|
-
def k2c(temp:
|
94
|
+
def k2c(temp: npt.NDArray) -> npt.NDArray:
|
95
95
|
"""Converts Kelvins to Celsius."""
|
96
96
|
return ma.array(temp) - 273.15
|
97
97
|
|
98
98
|
|
99
|
-
def find_cloud_bases(array:
|
99
|
+
def find_cloud_bases(array: npt.NDArray) -> npt.NDArray:
|
100
100
|
"""Finds bases of clouds.
|
101
101
|
|
102
102
|
Args:
|
@@ -111,7 +111,7 @@ def find_cloud_bases(array: np.ndarray) -> np.ndarray:
|
|
111
111
|
return np.diff(array_padded, axis=1) == 1
|
112
112
|
|
113
113
|
|
114
|
-
def find_cloud_tops(array:
|
114
|
+
def find_cloud_tops(array: npt.NDArray) -> npt.NDArray:
|
115
115
|
"""Finds tops of clouds.
|
116
116
|
|
117
117
|
Args:
|
@@ -127,8 +127,8 @@ def find_cloud_tops(array: np.ndarray) -> np.ndarray:
|
|
127
127
|
|
128
128
|
|
129
129
|
def find_lowest_cloud_bases(
|
130
|
-
cloud_mask:
|
131
|
-
height:
|
130
|
+
cloud_mask: npt.NDArray,
|
131
|
+
height: npt.NDArray,
|
132
132
|
) -> ma.MaskedArray:
|
133
133
|
"""Finds altitudes of cloud bases."""
|
134
134
|
cloud_heights = cloud_mask * height
|
@@ -136,8 +136,8 @@ def find_lowest_cloud_bases(
|
|
136
136
|
|
137
137
|
|
138
138
|
def find_highest_cloud_tops(
|
139
|
-
cloud_mask:
|
140
|
-
height:
|
139
|
+
cloud_mask: npt.NDArray,
|
140
|
+
height: npt.NDArray,
|
141
141
|
) -> ma.MaskedArray:
|
142
142
|
"""Finds altitudes of cloud tops."""
|
143
143
|
cloud_heights = cloud_mask * height
|
@@ -145,15 +145,15 @@ def find_highest_cloud_tops(
|
|
145
145
|
return _find_lowest_heights(cloud_heights_flipped)
|
146
146
|
|
147
147
|
|
148
|
-
def _find_lowest_heights(cloud_heights:
|
148
|
+
def _find_lowest_heights(cloud_heights: npt.NDArray) -> ma.MaskedArray:
|
149
149
|
inds = (cloud_heights != 0).argmax(axis=1)
|
150
150
|
heights = np.array([cloud_heights[i, ind] for i, ind in enumerate(inds)])
|
151
151
|
return ma.masked_equal(heights, 0.0)
|
152
152
|
|
153
153
|
|
154
154
|
def fill_clouds_with_lwc_dz(
|
155
|
-
temperature:
|
156
|
-
) ->
|
155
|
+
temperature: npt.NDArray, pressure: npt.NDArray, is_liquid: npt.NDArray
|
156
|
+
) -> npt.NDArray:
|
157
157
|
"""Fills liquid clouds with lwc change rate at the cloud bases.
|
158
158
|
|
159
159
|
Args:
|
@@ -173,10 +173,10 @@ def fill_clouds_with_lwc_dz(
|
|
173
173
|
|
174
174
|
|
175
175
|
def get_lwc_change_rate_at_bases(
|
176
|
-
temperature:
|
177
|
-
pressure:
|
178
|
-
is_liquid:
|
179
|
-
) ->
|
176
|
+
temperature: npt.NDArray,
|
177
|
+
pressure: npt.NDArray,
|
178
|
+
is_liquid: npt.NDArray,
|
179
|
+
) -> npt.NDArray:
|
180
180
|
"""Finds LWC change rate in liquid cloud bases.
|
181
181
|
|
182
182
|
Args:
|
@@ -198,7 +198,9 @@ def get_lwc_change_rate_at_bases(
|
|
198
198
|
return lwc_dz
|
199
199
|
|
200
200
|
|
201
|
-
def calc_lwc_change_rate(
|
201
|
+
def calc_lwc_change_rate(
|
202
|
+
temperature: npt.NDArray, pressure: npt.NDArray
|
203
|
+
) -> npt.NDArray:
|
202
204
|
"""Returns rate of change of condensable water (LWC).
|
203
205
|
|
204
206
|
Calculates the theoretical adiabatic rate of increase of LWC
|
@@ -242,7 +244,7 @@ def calc_lwc_change_rate(temperature: np.ndarray, pressure: np.ndarray) -> np.nd
|
|
242
244
|
return dqs_dz * air_density
|
243
245
|
|
244
246
|
|
245
|
-
def calc_saturation_vapor_pressure(temperature:
|
247
|
+
def calc_saturation_vapor_pressure(temperature: npt.NDArray) -> npt.NDArray:
|
246
248
|
"""Goff-Gratch formula for saturation vapor pressure over water adopted by WMO.
|
247
249
|
|
248
250
|
Args:
|
@@ -266,7 +268,9 @@ def calc_saturation_vapor_pressure(temperature: np.ndarray) -> np.ndarray:
|
|
266
268
|
) * con.HPA_TO_PA
|
267
269
|
|
268
270
|
|
269
|
-
def calc_mixing_ratio(
|
271
|
+
def calc_mixing_ratio(
|
272
|
+
vapor_pressure: npt.NDArray, pressure: npt.NDArray
|
273
|
+
) -> npt.NDArray:
|
270
274
|
"""Calculates mixing ratio from partial vapor pressure and pressure.
|
271
275
|
|
272
276
|
Args:
|
@@ -281,10 +285,10 @@ def calc_mixing_ratio(vapor_pressure: np.ndarray, pressure: np.ndarray) -> np.nd
|
|
281
285
|
|
282
286
|
|
283
287
|
def calc_air_density(
|
284
|
-
pressure:
|
285
|
-
temperature:
|
286
|
-
svp_mixing_ratio:
|
287
|
-
) ->
|
288
|
+
pressure: npt.NDArray,
|
289
|
+
temperature: npt.NDArray,
|
290
|
+
svp_mixing_ratio: npt.NDArray,
|
291
|
+
) -> npt.NDArray:
|
288
292
|
"""Calculates air density (kg m-3).
|
289
293
|
|
290
294
|
Args:
|
@@ -299,7 +303,7 @@ def calc_air_density(
|
|
299
303
|
return pressure / (con.RS * temperature * (0.6 * svp_mixing_ratio + 1))
|
300
304
|
|
301
305
|
|
302
|
-
def calc_adiabatic_lwc(lwc_dz:
|
306
|
+
def calc_adiabatic_lwc(lwc_dz: npt.NDArray, height: npt.NDArray) -> npt.NDArray:
|
303
307
|
"""Calculates adiabatic liquid water content (kg m-3).
|
304
308
|
|
305
309
|
Args:
|
@@ -319,8 +323,8 @@ def calc_adiabatic_lwc(lwc_dz: np.ndarray, height: np.ndarray) -> np.ndarray:
|
|
319
323
|
|
320
324
|
|
321
325
|
def normalize_lwc_by_lwp(
|
322
|
-
lwc_adiabatic:
|
323
|
-
) ->
|
326
|
+
lwc_adiabatic: npt.NDArray, lwp: npt.NDArray, height: npt.NDArray
|
327
|
+
) -> npt.NDArray:
|
324
328
|
"""Finds LWC that would produce measured LWP.
|
325
329
|
|
326
330
|
Calculates LWP-weighted, normalized LWC. This is the measured
|
@@ -2,8 +2,8 @@ from dataclasses import dataclass
|
|
2
2
|
from typing import Annotated
|
3
3
|
|
4
4
|
import numpy as np
|
5
|
+
import numpy.typing as npt
|
5
6
|
from numpy import ma
|
6
|
-
from numpy.typing import NDArray
|
7
7
|
|
8
8
|
from cloudnetpy import constants as con
|
9
9
|
from cloudnetpy.utils import path_lengths_from_ground
|
@@ -13,8 +13,8 @@ from cloudnetpy.utils import path_lengths_from_ground
|
|
13
13
|
class Attenuation:
|
14
14
|
amount: Annotated[ma.MaskedArray, "float32"]
|
15
15
|
error: Annotated[ma.MaskedArray, "float32"]
|
16
|
-
attenuated: NDArray[np.bool_]
|
17
|
-
uncorrected: NDArray[np.bool_]
|
16
|
+
attenuated: npt.NDArray[np.bool_]
|
17
|
+
uncorrected: npt.NDArray[np.bool_]
|
18
18
|
|
19
19
|
|
20
20
|
@dataclass
|
@@ -26,7 +26,7 @@ class RadarAttenuation:
|
|
26
26
|
|
27
27
|
|
28
28
|
def calc_two_way_attenuation(
|
29
|
-
height:
|
29
|
+
height: npt.NDArray, specific_attenuation: ma.MaskedArray
|
30
30
|
) -> ma.MaskedArray:
|
31
31
|
"""Calculates two-way attenuation (dB) for given specific attenuation
|
32
32
|
(dB km-1) and height (m).
|
{cloudnetpy-1.80.8 → cloudnetpy-1.81.0}/cloudnetpy/categorize/attenuations/liquid_attenuation.py
RENAMED
@@ -1,4 +1,4 @@
|
|
1
|
-
import numpy as
|
1
|
+
import numpy.typing as npt
|
2
2
|
from numpy import ma
|
3
3
|
|
4
4
|
import cloudnetpy.constants as con
|
@@ -16,7 +16,9 @@ class LiquidAttenuation:
|
|
16
16
|
algorithms: the Cloudnet Instrument Synergy/Target Categorization product.
|
17
17
|
"""
|
18
18
|
|
19
|
-
def __init__(
|
19
|
+
def __init__(
|
20
|
+
self, data: Observations, classification: ClassificationResult
|
21
|
+
) -> None:
|
20
22
|
self._model = data.model.data_dense
|
21
23
|
self._liquid_in_pixel = classification.category_bits.droplet
|
22
24
|
self._height = data.radar.height
|
@@ -50,7 +52,7 @@ class LiquidAttenuation:
|
|
50
52
|
)
|
51
53
|
|
52
54
|
def _calc_liquid_atten(
|
53
|
-
self, lwp: ma.MaskedArray, lwc_dz:
|
55
|
+
self, lwp: ma.MaskedArray, lwc_dz: npt.NDArray
|
54
56
|
) -> ma.MaskedArray:
|
55
57
|
"""Finds radar liquid attenuation."""
|
56
58
|
lwp = lwp.copy()
|
@@ -60,7 +62,7 @@ class LiquidAttenuation:
|
|
60
62
|
return self._calc_two_way_attenuation(lwc_scaled)
|
61
63
|
|
62
64
|
def _calc_liquid_atten_err(
|
63
|
-
self, lwp_error: ma.MaskedArray, lwc_dz:
|
65
|
+
self, lwp_error: ma.MaskedArray, lwc_dz: npt.NDArray
|
64
66
|
) -> ma.MaskedArray:
|
65
67
|
"""Finds radar liquid attenuation error."""
|
66
68
|
lwc_err_scaled = atmos_utils.normalize_lwc_by_lwp(
|
@@ -68,7 +70,7 @@ class LiquidAttenuation:
|
|
68
70
|
)
|
69
71
|
return self._calc_two_way_attenuation(lwc_err_scaled)
|
70
72
|
|
71
|
-
def _calc_two_way_attenuation(self, lwc_scaled:
|
73
|
+
def _calc_two_way_attenuation(self, lwc_scaled: npt.NDArray) -> ma.MaskedArray:
|
72
74
|
"""Calculates liquid attenuation (dB).
|
73
75
|
|
74
76
|
Args:
|
{cloudnetpy-1.80.8 → cloudnetpy-1.81.0}/cloudnetpy/categorize/attenuations/melting_attenuation.py
RENAMED
@@ -1,4 +1,4 @@
|
|
1
|
-
import numpy as
|
1
|
+
import numpy.typing as npt
|
2
2
|
from numpy import ma
|
3
3
|
|
4
4
|
import cloudnetpy.constants as con
|
@@ -55,8 +55,8 @@ def calc_melting_attenuation(
|
|
55
55
|
|
56
56
|
|
57
57
|
def _calc_melting_attenuation(
|
58
|
-
rainfall_rate:
|
59
|
-
) ->
|
58
|
+
rainfall_rate: npt.NDArray, frequency: float
|
59
|
+
) -> npt.NDArray:
|
60
60
|
"""Calculates total attenuation due to melting layer (dB).
|
61
61
|
|
62
62
|
References:
|
{cloudnetpy-1.80.8 → cloudnetpy-1.81.0}/cloudnetpy/categorize/attenuations/rain_attenuation.py
RENAMED
@@ -1,6 +1,6 @@
|
|
1
1
|
import numpy as np
|
2
|
+
import numpy.typing as npt
|
2
3
|
from numpy import ma
|
3
|
-
from numpy.typing import NDArray
|
4
4
|
|
5
5
|
import cloudnetpy.constants as con
|
6
6
|
from cloudnetpy import utils
|
@@ -53,7 +53,7 @@ def calc_rain_attenuation(
|
|
53
53
|
|
54
54
|
def _find_regions(
|
55
55
|
classification: ClassificationResult,
|
56
|
-
) -> tuple[NDArray[np.bool_], NDArray[np.bool_]]:
|
56
|
+
) -> tuple[npt.NDArray[np.bool_], npt.NDArray[np.bool_]]:
|
57
57
|
"""Finds regions where rain attenuation is present and can be corrected or not."""
|
58
58
|
warm_region = ~classification.category_bits.freezing
|
59
59
|
is_rain = utils.transpose(classification.is_rain).astype(bool)
|
@@ -63,8 +63,8 @@ def _find_regions(
|
|
63
63
|
|
64
64
|
|
65
65
|
def _calc_rain_specific_attenuation(
|
66
|
-
rainfall_rate:
|
67
|
-
) ->
|
66
|
+
rainfall_rate: npt.NDArray, frequency: float
|
67
|
+
) -> npt.NDArray:
|
68
68
|
"""Calculates specific attenuation due to rain (dB km-1).
|
69
69
|
|
70
70
|
References:
|
@@ -2,10 +2,15 @@
|
|
2
2
|
|
3
3
|
import dataclasses
|
4
4
|
import logging
|
5
|
+
from collections.abc import Sequence
|
5
6
|
from dataclasses import fields
|
7
|
+
from os import PathLike
|
8
|
+
from typing import TypedDict
|
9
|
+
from uuid import UUID
|
6
10
|
|
7
11
|
import numpy as np
|
8
12
|
from numpy.typing import NDArray
|
13
|
+
from typing_extensions import NotRequired
|
9
14
|
|
10
15
|
from cloudnetpy import output, utils
|
11
16
|
from cloudnetpy.categorize import attenuation, classify
|
@@ -22,12 +27,21 @@ from cloudnetpy.metadata import COMMON_ATTRIBUTES, MetaData
|
|
22
27
|
from cloudnetpy.products.product_tools import CategoryBits, QualityBits
|
23
28
|
|
24
29
|
|
30
|
+
class CategorizeInput(TypedDict):
|
31
|
+
radar: str | PathLike
|
32
|
+
lidar: str | PathLike
|
33
|
+
model: str | PathLike
|
34
|
+
disdrometer: NotRequired[str | PathLike]
|
35
|
+
mwr: NotRequired[str | PathLike]
|
36
|
+
lv0_files: NotRequired[Sequence[str | PathLike]]
|
37
|
+
|
38
|
+
|
25
39
|
def generate_categorize(
|
26
|
-
input_files:
|
27
|
-
output_file: str,
|
28
|
-
uuid: str | None = None,
|
40
|
+
input_files: CategorizeInput,
|
41
|
+
output_file: str | PathLike,
|
42
|
+
uuid: str | UUID | None = None,
|
29
43
|
options: dict | None = None,
|
30
|
-
) ->
|
44
|
+
) -> UUID:
|
31
45
|
"""Generates a Cloudnet Level 1c categorize file.
|
32
46
|
|
33
47
|
This function rebins measurements into a common height/time grid
|
@@ -73,6 +87,7 @@ def generate_categorize(
|
|
73
87
|
>>> input_files['lv0_files'] = ['file1.LV0', 'file2.LV0'] # Add RPG LV0 files
|
74
88
|
>>> generate_categorize(input_files, 'output.nc') # Use the Voodoo method
|
75
89
|
"""
|
90
|
+
uuid = utils.get_uuid(uuid)
|
76
91
|
|
77
92
|
def _interpolate_to_cloudnet_grid() -> list[int]:
|
78
93
|
if data.disdrometer is not None:
|
@@ -199,17 +214,18 @@ def generate_categorize(
|
|
199
214
|
attributes = output.add_time_attribute(attributes, date, "model_time")
|
200
215
|
attributes = output.add_source_attribute(attributes, data)
|
201
216
|
output.update_attributes(cloudnet_arrays, attributes)
|
202
|
-
|
217
|
+
_save_cat(output_file, data, cloudnet_arrays, uuid)
|
218
|
+
return uuid
|
203
219
|
finally:
|
204
220
|
_close_all()
|
205
221
|
|
206
222
|
|
207
223
|
def _save_cat(
|
208
|
-
full_path: str,
|
224
|
+
full_path: str | PathLike,
|
209
225
|
data_obs: Observations,
|
210
226
|
cloudnet_arrays: dict,
|
211
|
-
uuid:
|
212
|
-
) ->
|
227
|
+
uuid: UUID,
|
228
|
+
) -> None:
|
213
229
|
"""Creates a categorize netCDF4 file and saves all data into it."""
|
214
230
|
dims = {
|
215
231
|
"time": len(data_obs.radar.time),
|
@@ -223,7 +239,6 @@ def _save_cat(
|
|
223
239
|
file_type += "-voodoo"
|
224
240
|
|
225
241
|
with output.init_file(full_path, dims, cloudnet_arrays, uuid) as nc:
|
226
|
-
uuid_out = nc.file_uuid
|
227
242
|
nc.cloudnet_file_type = file_type
|
228
243
|
output.copy_global(
|
229
244
|
data_obs.radar.dataset,
|
@@ -246,7 +261,6 @@ def _save_cat(
|
|
246
261
|
nc.voodoonet_version = voodoonet.version.__version__
|
247
262
|
output.add_source_instruments(nc, data_obs)
|
248
263
|
output.merge_history(nc, file_type, data_obs)
|
249
|
-
return uuid_out
|
250
264
|
|
251
265
|
|
252
266
|
def _classes_to_bits(data: QualityBits | CategoryBits) -> NDArray[np.int_]:
|
@@ -411,7 +425,7 @@ CATEGORIZE_ATTRIBUTES = {
|
|
411
425
|
long_name="Minimum detectable radar reflectivity",
|
412
426
|
units="dBZ",
|
413
427
|
comment=COMMENTS["Z_sensitivity"],
|
414
|
-
dimensions=("
|
428
|
+
dimensions=("height",),
|
415
429
|
),
|
416
430
|
"v": COMMON_ATTRIBUTES["v"]._replace(dimensions=("time", "height")),
|
417
431
|
"width": COMMON_ATTRIBUTES["width"]._replace(dimensions=("time", "height")),
|
@@ -1,7 +1,7 @@
|
|
1
1
|
import numpy as np
|
2
|
+
import numpy.typing as npt
|
2
3
|
import skimage
|
3
4
|
from numpy import ma
|
4
|
-
from numpy.typing import NDArray
|
5
5
|
|
6
6
|
from cloudnetpy import utils
|
7
7
|
from cloudnetpy.categorize import (
|
@@ -67,9 +67,10 @@ def classify_measurements(data: Observations) -> ClassificationResult:
|
|
67
67
|
import voodoonet # noqa: PLC0415
|
68
68
|
|
69
69
|
options = voodoonet.VoodooOptions(progress_bar=False)
|
70
|
-
|
70
|
+
dumb_date = obs.date.isoformat().split("-")
|
71
|
+
target_time = voodoonet.utils.decimal_hour2unix(dumb_date, obs.time)
|
71
72
|
liquid_prob = voodoonet.infer(
|
72
|
-
obs.lv0_files, target_time=target_time, options=options
|
73
|
+
list(obs.lv0_files), target_time=target_time, options=options
|
73
74
|
)
|
74
75
|
liquid_from_radar = liquid_prob > 0.55
|
75
76
|
liquid_from_radar = _remove_false_radar_liquid(
|
@@ -131,9 +132,9 @@ def _fix_super_cold_liquid(obs: ClassData, bits: CategoryBits) -> None:
|
|
131
132
|
|
132
133
|
|
133
134
|
def _remove_false_radar_liquid(
|
134
|
-
liquid_from_radar:
|
135
|
-
liquid_from_lidar:
|
136
|
-
) -> NDArray[np.bool_]:
|
135
|
+
liquid_from_radar: npt.NDArray,
|
136
|
+
liquid_from_lidar: npt.NDArray,
|
137
|
+
) -> npt.NDArray[np.bool_]:
|
137
138
|
"""Removes radar-liquid below lidar-detected liquid bases."""
|
138
139
|
lidar_liquid_bases = atmos_utils.find_cloud_bases(liquid_from_lidar)
|
139
140
|
for prof, base in zip(*np.where(lidar_liquid_bases), strict=True):
|
@@ -144,7 +145,7 @@ def _remove_false_radar_liquid(
|
|
144
145
|
def _find_aerosols(
|
145
146
|
obs: ClassData,
|
146
147
|
bits: CategoryBits,
|
147
|
-
) -> NDArray[np.bool_]:
|
148
|
+
) -> npt.NDArray[np.bool_]:
|
148
149
|
"""Estimates aerosols from lidar backscattering.
|
149
150
|
|
150
151
|
Aerosols are lidar signals that are: a) not falling, b) not liquid droplets.
|
@@ -167,7 +168,7 @@ def _fix_undetected_melting_layer(bits: CategoryBits) -> None:
|
|
167
168
|
bits.melting[:, 1:][transition] = True
|
168
169
|
|
169
170
|
|
170
|
-
def _find_drizzle_and_falling(bits: CategoryBits) ->
|
171
|
+
def _find_drizzle_and_falling(bits: CategoryBits) -> npt.NDArray:
|
171
172
|
"""Classifies pixels as falling, drizzle and others.
|
172
173
|
|
173
174
|
Args:
|
@@ -1,6 +1,9 @@
|
|
1
|
+
from collections.abc import Sequence
|
1
2
|
from dataclasses import dataclass
|
3
|
+
from os import PathLike
|
2
4
|
|
3
5
|
import numpy as np
|
6
|
+
import numpy.typing as npt
|
4
7
|
from numpy import ma
|
5
8
|
|
6
9
|
from cloudnetpy import utils
|
@@ -21,16 +24,16 @@ class Observations:
|
|
21
24
|
model: Model
|
22
25
|
mwr: Mwr | None = None
|
23
26
|
disdrometer: Disdrometer | None = None
|
24
|
-
lv0_files:
|
27
|
+
lv0_files: Sequence[str | PathLike] | None = None
|
25
28
|
|
26
29
|
|
27
30
|
@dataclass
|
28
31
|
class ClassificationResult:
|
29
32
|
category_bits: CategoryBits
|
30
|
-
is_rain:
|
31
|
-
is_clutter:
|
32
|
-
insect_prob:
|
33
|
-
liquid_prob:
|
33
|
+
is_rain: npt.NDArray
|
34
|
+
is_clutter: npt.NDArray
|
35
|
+
insect_prob: npt.NDArray
|
36
|
+
liquid_prob: npt.NDArray | None
|
34
37
|
|
35
38
|
|
36
39
|
class ClassData:
|
@@ -59,7 +62,7 @@ class ClassData:
|
|
59
62
|
|
60
63
|
"""
|
61
64
|
|
62
|
-
def __init__(self, data: Observations):
|
65
|
+
def __init__(self, data: Observations) -> None:
|
63
66
|
self.data = data
|
64
67
|
self.z = data.radar.data["Z"][:]
|
65
68
|
self.v = data.radar.data["v"][:]
|
@@ -84,7 +87,7 @@ class ClassData:
|
|
84
87
|
self.lv0_files = data.lv0_files
|
85
88
|
self.date = data.radar.get_date()
|
86
89
|
|
87
|
-
def _find_profiles_with_rain(self) ->
|
90
|
+
def _find_profiles_with_rain(self) -> npt.NDArray:
|
88
91
|
is_rain = self._find_rain_from_radar_echo()
|
89
92
|
rain_from_disdrometer = self._find_rain_from_disdrometer()
|
90
93
|
ind = ~rain_from_disdrometer.mask
|
@@ -94,7 +97,7 @@ class ClassData:
|
|
94
97
|
is_positive_temp = self.tw[:, first_valid_ind] > T0 + 5 # Filter snowfall
|
95
98
|
return is_rain & is_positive_temp
|
96
99
|
|
97
|
-
def _find_rain_from_radar_echo(self) ->
|
100
|
+
def _find_rain_from_radar_echo(self) -> npt.NDArray:
|
98
101
|
first_gate_with_data = np.argmin(self.z.mask.all(axis=0))
|
99
102
|
gate_number = first_gate_with_data + 3
|
100
103
|
threshold = {"z": 3, "v": 0, "ldr": -15}
|
@@ -132,10 +135,10 @@ class ClassData:
|
|
132
135
|
|
133
136
|
def _find_clutter(
|
134
137
|
v: np.ma.MaskedArray,
|
135
|
-
is_rain:
|
138
|
+
is_rain: npt.NDArray,
|
136
139
|
n_gates: int = 10,
|
137
140
|
v_lim: float = 0.05,
|
138
|
-
) ->
|
141
|
+
) -> npt.NDArray:
|
139
142
|
"""Estimates clutter from doppler velocity.
|
140
143
|
|
141
144
|
Args:
|
@@ -1,8 +1,10 @@
|
|
1
1
|
"""Mwr module, containing the :class:`Mwr` class."""
|
2
2
|
|
3
3
|
import logging
|
4
|
+
from os import PathLike
|
4
5
|
|
5
6
|
import numpy as np
|
7
|
+
import numpy.typing as npt
|
6
8
|
from numpy import ma
|
7
9
|
from scipy.interpolate import interp1d
|
8
10
|
|
@@ -20,11 +22,11 @@ class Disdrometer(DataSource):
|
|
20
22
|
|
21
23
|
"""
|
22
24
|
|
23
|
-
def __init__(self, full_path: str):
|
25
|
+
def __init__(self, full_path: str | PathLike) -> None:
|
24
26
|
super().__init__(full_path)
|
25
27
|
self._init_rainfall_rate()
|
26
28
|
|
27
|
-
def interpolate_to_grid(self, time_grid:
|
29
|
+
def interpolate_to_grid(self, time_grid: npt.NDArray) -> None:
|
28
30
|
for key, array in self.data.items():
|
29
31
|
self.data[key].data = self._interpolate(array.data, time_grid)
|
30
32
|
|
@@ -36,7 +38,7 @@ class Disdrometer(DataSource):
|
|
36
38
|
raise DisdrometerDataError(msg)
|
37
39
|
self.append_data(self.dataset.variables[key][:], key)
|
38
40
|
|
39
|
-
def _interpolate(self, y: ma.MaskedArray, x_new:
|
41
|
+
def _interpolate(self, y: ma.MaskedArray, x_new: npt.NDArray) -> npt.NDArray:
|
40
42
|
time = self.time
|
41
43
|
mask = ma.getmask(y)
|
42
44
|
if mask is not ma.nomask:
|
@@ -1,6 +1,7 @@
|
|
1
1
|
"""This module has functions for liquid layer detection."""
|
2
2
|
|
3
3
|
import numpy as np
|
4
|
+
import numpy.typing as npt
|
4
5
|
import scipy.signal
|
5
6
|
from numpy import ma
|
6
7
|
|
@@ -11,10 +12,10 @@ from cloudnetpy.categorize.containers import ClassData
|
|
11
12
|
|
12
13
|
def correct_liquid_top(
|
13
14
|
obs: ClassData,
|
14
|
-
is_liquid:
|
15
|
-
is_freezing:
|
15
|
+
is_liquid: npt.NDArray,
|
16
|
+
is_freezing: npt.NDArray,
|
16
17
|
limit: float = 200,
|
17
|
-
) ->
|
18
|
+
) -> npt.NDArray:
|
18
19
|
"""Corrects lidar detected liquid cloud top using radar data.
|
19
20
|
|
20
21
|
Args:
|
@@ -43,7 +44,7 @@ def correct_liquid_top(
|
|
43
44
|
return is_liquid_corrected
|
44
45
|
|
45
46
|
|
46
|
-
def _find_ind_above_top(is_freezing_from_peak:
|
47
|
+
def _find_ind_above_top(is_freezing_from_peak: npt.NDArray, top_above: int) -> int:
|
47
48
|
first_point_below_zero = np.where(is_freezing_from_peak)[0][0]
|
48
49
|
ind = first_point_below_zero + top_above
|
49
50
|
return min(len(is_freezing_from_peak) - 1, ind)
|
@@ -57,7 +58,7 @@ def find_liquid(
|
|
57
58
|
min_top_der: float = 1e-7,
|
58
59
|
min_lwp: float = 0,
|
59
60
|
min_alt: float = 100,
|
60
|
-
) ->
|
61
|
+
) -> npt.NDArray:
|
61
62
|
"""Estimate liquid layers from SNR-screened attenuated backscatter.
|
62
63
|
|
63
64
|
Args:
|
@@ -121,7 +122,7 @@ def find_liquid(
|
|
121
122
|
return is_liquid
|
122
123
|
|
123
124
|
|
124
|
-
def ind_base(dprof:
|
125
|
+
def ind_base(dprof: npt.NDArray, ind_peak: int, dist: int, lim: float) -> int:
|
125
126
|
"""Finds base index of a peak in profile.
|
126
127
|
|
127
128
|
Return the lowermost index of profile where 1st order differences
|
@@ -186,7 +187,9 @@ def ind_base(dprof: np.ndarray, ind_peak: int, dist: int, lim: float) -> int:
|
|
186
187
|
return start + np.where(diffs > diffs[mind] / lim)[0][0]
|
187
188
|
|
188
189
|
|
189
|
-
def ind_top(
|
190
|
+
def ind_top(
|
191
|
+
dprof: npt.NDArray, ind_peak: int, nprof: int, dist: int, lim: float
|
192
|
+
) -> int:
|
190
193
|
"""Finds top index of a peak in profile.
|
191
194
|
|
192
195
|
Return the uppermost index of profile where 1st order differences
|
@@ -222,7 +225,7 @@ def ind_top(dprof: np.ndarray, ind_peak: int, nprof: int, dist: int, lim: float)
|
|
222
225
|
return ind_peak + np.where(diffs < diffs[mind] / lim)[0][-1] + 1
|
223
226
|
|
224
227
|
|
225
|
-
def interpolate_lwp(obs: ClassData) ->
|
228
|
+
def interpolate_lwp(obs: ClassData) -> npt.NDArray:
|
226
229
|
"""Linear interpolation of liquid water path to fill masked values.
|
227
230
|
|
228
231
|
Args:
|
@@ -238,7 +241,7 @@ def interpolate_lwp(obs: ClassData) -> np.ndarray:
|
|
238
241
|
return np.interp(obs.time, obs.time[ind], obs.lwp[ind])
|
239
242
|
|
240
243
|
|
241
|
-
def _find_strong_peaks(data:
|
244
|
+
def _find_strong_peaks(data: npt.NDArray, threshold: float) -> tuple:
|
242
245
|
"""Finds local maximums from data (greater than *threshold*)."""
|
243
246
|
peaks = scipy.signal.argrelextrema(data, np.greater, order=4, axis=1)
|
244
247
|
strong_peaks = np.where(data[peaks] > threshold)
|