cloudnetpy 1.55.20__tar.gz → 1.55.22__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.55.20/cloudnetpy.egg-info → cloudnetpy-1.55.22}/PKG-INFO +11 -10
- {cloudnetpy-1.55.20 → cloudnetpy-1.55.22}/README.md +8 -7
- {cloudnetpy-1.55.20 → cloudnetpy-1.55.22}/cloudnetpy/categorize/atmos.py +46 -14
- {cloudnetpy-1.55.20 → cloudnetpy-1.55.22}/cloudnetpy/categorize/atmos_utils.py +11 -1
- {cloudnetpy-1.55.20 → cloudnetpy-1.55.22}/cloudnetpy/categorize/categorize.py +38 -21
- {cloudnetpy-1.55.20 → cloudnetpy-1.55.22}/cloudnetpy/categorize/classify.py +31 -9
- {cloudnetpy-1.55.20 → cloudnetpy-1.55.22}/cloudnetpy/categorize/containers.py +19 -7
- {cloudnetpy-1.55.20 → cloudnetpy-1.55.22}/cloudnetpy/categorize/droplet.py +24 -8
- {cloudnetpy-1.55.20 → cloudnetpy-1.55.22}/cloudnetpy/categorize/falling.py +17 -7
- {cloudnetpy-1.55.20 → cloudnetpy-1.55.22}/cloudnetpy/categorize/freezing.py +19 -5
- {cloudnetpy-1.55.20 → cloudnetpy-1.55.22}/cloudnetpy/categorize/insects.py +27 -14
- cloudnetpy-1.55.22/cloudnetpy/categorize/lidar.py +78 -0
- {cloudnetpy-1.55.20 → cloudnetpy-1.55.22}/cloudnetpy/categorize/melting.py +19 -9
- {cloudnetpy-1.55.20 → cloudnetpy-1.55.22}/cloudnetpy/categorize/model.py +28 -9
- {cloudnetpy-1.55.20 → cloudnetpy-1.55.22}/cloudnetpy/categorize/mwr.py +4 -2
- {cloudnetpy-1.55.20 → cloudnetpy-1.55.22}/cloudnetpy/categorize/radar.py +58 -22
- {cloudnetpy-1.55.20 → cloudnetpy-1.55.22}/cloudnetpy/cloudnetarray.py +15 -6
- {cloudnetpy-1.55.20 → cloudnetpy-1.55.22}/cloudnetpy/concat_lib.py +39 -16
- {cloudnetpy-1.55.20 → cloudnetpy-1.55.22}/cloudnetpy/constants.py +7 -0
- {cloudnetpy-1.55.20 → cloudnetpy-1.55.22}/cloudnetpy/datasource.py +39 -19
- {cloudnetpy-1.55.20 → cloudnetpy-1.55.22}/cloudnetpy/instruments/basta.py +6 -2
- {cloudnetpy-1.55.20 → cloudnetpy-1.55.22}/cloudnetpy/instruments/campbell_scientific.py +33 -16
- {cloudnetpy-1.55.20 → cloudnetpy-1.55.22}/cloudnetpy/instruments/ceilo.py +30 -13
- {cloudnetpy-1.55.20 → cloudnetpy-1.55.22}/cloudnetpy/instruments/ceilometer.py +76 -37
- {cloudnetpy-1.55.20 → cloudnetpy-1.55.22}/cloudnetpy/instruments/cl61d.py +8 -3
- {cloudnetpy-1.55.20 → cloudnetpy-1.55.22}/cloudnetpy/instruments/cloudnet_instrument.py +2 -1
- {cloudnetpy-1.55.20 → cloudnetpy-1.55.22}/cloudnetpy/instruments/copernicus.py +27 -14
- {cloudnetpy-1.55.20 → cloudnetpy-1.55.22}/cloudnetpy/instruments/disdrometer/common.py +51 -32
- {cloudnetpy-1.55.20 → cloudnetpy-1.55.22}/cloudnetpy/instruments/disdrometer/parsivel.py +79 -48
- {cloudnetpy-1.55.20 → cloudnetpy-1.55.22}/cloudnetpy/instruments/disdrometer/thies.py +10 -6
- {cloudnetpy-1.55.20 → cloudnetpy-1.55.22}/cloudnetpy/instruments/galileo.py +23 -12
- {cloudnetpy-1.55.20 → cloudnetpy-1.55.22}/cloudnetpy/instruments/hatpro.py +27 -11
- {cloudnetpy-1.55.20 → cloudnetpy-1.55.22}/cloudnetpy/instruments/instruments.py +4 -1
- {cloudnetpy-1.55.20 → cloudnetpy-1.55.22}/cloudnetpy/instruments/lufft.py +20 -11
- {cloudnetpy-1.55.20 → cloudnetpy-1.55.22}/cloudnetpy/instruments/mira.py +60 -49
- {cloudnetpy-1.55.20 → cloudnetpy-1.55.22}/cloudnetpy/instruments/mrr.py +31 -20
- {cloudnetpy-1.55.20 → cloudnetpy-1.55.22}/cloudnetpy/instruments/nc_lidar.py +15 -6
- {cloudnetpy-1.55.20 → cloudnetpy-1.55.22}/cloudnetpy/instruments/nc_radar.py +31 -22
- {cloudnetpy-1.55.20 → cloudnetpy-1.55.22}/cloudnetpy/instruments/pollyxt.py +36 -21
- {cloudnetpy-1.55.20 → cloudnetpy-1.55.22}/cloudnetpy/instruments/radiometrics.py +32 -18
- {cloudnetpy-1.55.20 → cloudnetpy-1.55.22}/cloudnetpy/instruments/rpg.py +48 -22
- {cloudnetpy-1.55.20 → cloudnetpy-1.55.22}/cloudnetpy/instruments/rpg_reader.py +39 -30
- {cloudnetpy-1.55.20 → cloudnetpy-1.55.22}/cloudnetpy/instruments/vaisala.py +39 -27
- {cloudnetpy-1.55.20 → cloudnetpy-1.55.22}/cloudnetpy/instruments/weather_station.py +15 -11
- {cloudnetpy-1.55.20 → cloudnetpy-1.55.22}/cloudnetpy/metadata.py +3 -1
- {cloudnetpy-1.55.20 → cloudnetpy-1.55.22}/cloudnetpy/model_evaluation/file_handler.py +31 -21
- {cloudnetpy-1.55.20 → cloudnetpy-1.55.22}/cloudnetpy/model_evaluation/metadata.py +3 -1
- {cloudnetpy-1.55.20 → cloudnetpy-1.55.22}/cloudnetpy/model_evaluation/model_metadata.py +1 -1
- {cloudnetpy-1.55.20 → cloudnetpy-1.55.22}/cloudnetpy/model_evaluation/plotting/plot_tools.py +20 -15
- {cloudnetpy-1.55.20 → cloudnetpy-1.55.22}/cloudnetpy/model_evaluation/plotting/plotting.py +114 -64
- {cloudnetpy-1.55.20 → cloudnetpy-1.55.22}/cloudnetpy/model_evaluation/products/advance_methods.py +48 -28
- {cloudnetpy-1.55.20 → cloudnetpy-1.55.22}/cloudnetpy/model_evaluation/products/grid_methods.py +44 -19
- {cloudnetpy-1.55.20 → cloudnetpy-1.55.22}/cloudnetpy/model_evaluation/products/model_products.py +22 -18
- {cloudnetpy-1.55.20 → cloudnetpy-1.55.22}/cloudnetpy/model_evaluation/products/observation_products.py +15 -9
- {cloudnetpy-1.55.20 → cloudnetpy-1.55.22}/cloudnetpy/model_evaluation/products/product_resampling.py +14 -4
- {cloudnetpy-1.55.20 → cloudnetpy-1.55.22}/cloudnetpy/model_evaluation/products/tools.py +16 -7
- {cloudnetpy-1.55.20 → cloudnetpy-1.55.22}/cloudnetpy/model_evaluation/statistics/statistical_methods.py +28 -15
- {cloudnetpy-1.55.20 → cloudnetpy-1.55.22}/cloudnetpy/model_evaluation/tests/e2e/conftest.py +3 -3
- {cloudnetpy-1.55.20 → cloudnetpy-1.55.22}/cloudnetpy/model_evaluation/tests/e2e/process_cf/main.py +9 -5
- {cloudnetpy-1.55.20 → cloudnetpy-1.55.22}/cloudnetpy/model_evaluation/tests/e2e/process_cf/tests.py +14 -13
- {cloudnetpy-1.55.20 → cloudnetpy-1.55.22}/cloudnetpy/model_evaluation/tests/e2e/process_iwc/main.py +9 -5
- {cloudnetpy-1.55.20 → cloudnetpy-1.55.22}/cloudnetpy/model_evaluation/tests/e2e/process_iwc/tests.py +14 -13
- {cloudnetpy-1.55.20 → cloudnetpy-1.55.22}/cloudnetpy/model_evaluation/tests/e2e/process_lwc/main.py +9 -5
- {cloudnetpy-1.55.20 → cloudnetpy-1.55.22}/cloudnetpy/model_evaluation/tests/e2e/process_lwc/tests.py +14 -13
- {cloudnetpy-1.55.20 → cloudnetpy-1.55.22}/cloudnetpy/model_evaluation/tests/unit/conftest.py +11 -11
- {cloudnetpy-1.55.20 → cloudnetpy-1.55.22}/cloudnetpy/model_evaluation/tests/unit/test_advance_methods.py +33 -27
- {cloudnetpy-1.55.20 → cloudnetpy-1.55.22}/cloudnetpy/model_evaluation/tests/unit/test_grid_methods.py +83 -83
- {cloudnetpy-1.55.20 → cloudnetpy-1.55.22}/cloudnetpy/model_evaluation/tests/unit/test_model_products.py +23 -21
- {cloudnetpy-1.55.20 → cloudnetpy-1.55.22}/cloudnetpy/model_evaluation/tests/unit/test_observation_products.py +24 -25
- {cloudnetpy-1.55.20 → cloudnetpy-1.55.22}/cloudnetpy/model_evaluation/tests/unit/test_plot_tools.py +40 -39
- {cloudnetpy-1.55.20 → cloudnetpy-1.55.22}/cloudnetpy/model_evaluation/tests/unit/test_plotting.py +12 -11
- {cloudnetpy-1.55.20 → cloudnetpy-1.55.22}/cloudnetpy/model_evaluation/tests/unit/test_statistical_methods.py +30 -30
- {cloudnetpy-1.55.20 → cloudnetpy-1.55.22}/cloudnetpy/model_evaluation/tests/unit/test_tools.py +18 -17
- cloudnetpy-1.55.22/cloudnetpy/model_evaluation/utils.py +6 -0
- {cloudnetpy-1.55.20 → cloudnetpy-1.55.22}/cloudnetpy/output.py +45 -19
- {cloudnetpy-1.55.20 → cloudnetpy-1.55.22}/cloudnetpy/plotting/plot_meta.py +35 -11
- {cloudnetpy-1.55.20 → cloudnetpy-1.55.22}/cloudnetpy/plotting/plotting.py +172 -104
- {cloudnetpy-1.55.20 → cloudnetpy-1.55.22}/cloudnetpy/products/classification.py +20 -8
- {cloudnetpy-1.55.20 → cloudnetpy-1.55.22}/cloudnetpy/products/der.py +25 -10
- {cloudnetpy-1.55.20 → cloudnetpy-1.55.22}/cloudnetpy/products/drizzle.py +41 -26
- {cloudnetpy-1.55.20 → cloudnetpy-1.55.22}/cloudnetpy/products/drizzle_error.py +10 -5
- {cloudnetpy-1.55.20 → cloudnetpy-1.55.22}/cloudnetpy/products/drizzle_tools.py +43 -24
- {cloudnetpy-1.55.20 → cloudnetpy-1.55.22}/cloudnetpy/products/ier.py +10 -5
- {cloudnetpy-1.55.20 → cloudnetpy-1.55.22}/cloudnetpy/products/iwc.py +16 -9
- {cloudnetpy-1.55.20 → cloudnetpy-1.55.22}/cloudnetpy/products/lwc.py +34 -12
- {cloudnetpy-1.55.20 → cloudnetpy-1.55.22}/cloudnetpy/products/mwr_multi.py +4 -1
- {cloudnetpy-1.55.20 → cloudnetpy-1.55.22}/cloudnetpy/products/mwr_single.py +4 -1
- {cloudnetpy-1.55.20 → cloudnetpy-1.55.22}/cloudnetpy/products/product_tools.py +33 -10
- {cloudnetpy-1.55.20 → cloudnetpy-1.55.22}/cloudnetpy/utils.py +175 -74
- {cloudnetpy-1.55.20 → cloudnetpy-1.55.22}/cloudnetpy/version.py +1 -1
- {cloudnetpy-1.55.20 → cloudnetpy-1.55.22/cloudnetpy.egg-info}/PKG-INFO +11 -10
- {cloudnetpy-1.55.20 → cloudnetpy-1.55.22}/cloudnetpy.egg-info/requires.txt +2 -2
- {cloudnetpy-1.55.20 → cloudnetpy-1.55.22}/docs/source/conf.py +2 -2
- {cloudnetpy-1.55.20 → cloudnetpy-1.55.22}/pyproject.toml +29 -2
- cloudnetpy-1.55.20/cloudnetpy/categorize/lidar.py +0 -76
- cloudnetpy-1.55.20/cloudnetpy/model_evaluation/utils.py +0 -5
- {cloudnetpy-1.55.20 → cloudnetpy-1.55.22}/LICENSE +0 -0
- {cloudnetpy-1.55.20 → cloudnetpy-1.55.22}/MANIFEST.in +0 -0
- {cloudnetpy-1.55.20 → cloudnetpy-1.55.22}/cloudnetpy/__init__.py +0 -0
- {cloudnetpy-1.55.20 → cloudnetpy-1.55.22}/cloudnetpy/categorize/__init__.py +0 -0
- {cloudnetpy-1.55.20 → cloudnetpy-1.55.22}/cloudnetpy/exceptions.py +0 -0
- {cloudnetpy-1.55.20 → cloudnetpy-1.55.22}/cloudnetpy/instruments/__init__.py +0 -0
- {cloudnetpy-1.55.20 → cloudnetpy-1.55.22}/cloudnetpy/instruments/disdrometer/__init__.py +0 -0
- {cloudnetpy-1.55.20 → cloudnetpy-1.55.22}/cloudnetpy/model_evaluation/__init__.py +0 -0
- {cloudnetpy-1.55.20 → cloudnetpy-1.55.22}/cloudnetpy/model_evaluation/plotting/__init__.py +0 -0
- {cloudnetpy-1.55.20 → cloudnetpy-1.55.22}/cloudnetpy/model_evaluation/plotting/plot_meta.py +0 -0
- {cloudnetpy-1.55.20 → cloudnetpy-1.55.22}/cloudnetpy/model_evaluation/products/__init__.py +0 -0
- {cloudnetpy-1.55.20 → cloudnetpy-1.55.22}/cloudnetpy/model_evaluation/statistics/__init__.py +0 -0
- {cloudnetpy-1.55.20 → cloudnetpy-1.55.22}/cloudnetpy/model_evaluation/tests/__init__.py +0 -0
- {cloudnetpy-1.55.20 → cloudnetpy-1.55.22}/cloudnetpy/model_evaluation/tests/e2e/__init__.py +0 -0
- {cloudnetpy-1.55.20 → cloudnetpy-1.55.22}/cloudnetpy/model_evaluation/tests/e2e/process_cf/__init__.py +0 -0
- {cloudnetpy-1.55.20 → cloudnetpy-1.55.22}/cloudnetpy/model_evaluation/tests/e2e/process_iwc/__init__.py +0 -0
- {cloudnetpy-1.55.20 → cloudnetpy-1.55.22}/cloudnetpy/model_evaluation/tests/e2e/process_lwc/__init__.py +0 -0
- {cloudnetpy-1.55.20 → cloudnetpy-1.55.22}/cloudnetpy/model_evaluation/tests/unit/__init__.py +0 -0
- {cloudnetpy-1.55.20 → cloudnetpy-1.55.22}/cloudnetpy/plotting/__init__.py +0 -0
- {cloudnetpy-1.55.20 → cloudnetpy-1.55.22}/cloudnetpy/products/__init__.py +0 -0
- {cloudnetpy-1.55.20 → cloudnetpy-1.55.22}/cloudnetpy/products/mie_lu_tables.nc +0 -0
- {cloudnetpy-1.55.20 → cloudnetpy-1.55.22}/cloudnetpy/py.typed +0 -0
- {cloudnetpy-1.55.20 → cloudnetpy-1.55.22}/cloudnetpy.egg-info/SOURCES.txt +0 -0
- {cloudnetpy-1.55.20 → cloudnetpy-1.55.22}/cloudnetpy.egg-info/dependency_links.txt +0 -0
- {cloudnetpy-1.55.20 → cloudnetpy-1.55.22}/cloudnetpy.egg-info/top_level.txt +0 -0
- {cloudnetpy-1.55.20 → cloudnetpy-1.55.22}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: cloudnetpy
|
3
|
-
Version: 1.55.
|
3
|
+
Version: 1.55.22
|
4
4
|
Summary: Python package for Cloudnet processing
|
5
5
|
Author: Simo Tukiainen
|
6
6
|
License: MIT License
|
@@ -39,7 +39,7 @@ Classifier: Topic :: Scientific/Engineering
|
|
39
39
|
Requires-Python: >=3.10
|
40
40
|
Description-Content-Type: text/markdown
|
41
41
|
License-File: LICENSE
|
42
|
-
Requires-Dist: cloudnetpy_qc>=1.
|
42
|
+
Requires-Dist: cloudnetpy_qc>=1.15.0
|
43
43
|
Requires-Dist: matplotlib
|
44
44
|
Requires-Dist: mwrpy>=0.4.3
|
45
45
|
Requires-Dist: netCDF4
|
@@ -49,9 +49,9 @@ Requires-Dist: scikit-image
|
|
49
49
|
Requires-Dist: scipy
|
50
50
|
Provides-Extra: test
|
51
51
|
Requires-Dist: mypy; extra == "test"
|
52
|
-
Requires-Dist: pylint; extra == "test"
|
53
52
|
Requires-Dist: pytest; extra == "test"
|
54
53
|
Requires-Dist: pytest-flakefinder; extra == "test"
|
54
|
+
Requires-Dist: ruff; extra == "test"
|
55
55
|
Requires-Dist: types-requests; extra == "test"
|
56
56
|
Provides-Extra: dev
|
57
57
|
Requires-Dist: pre-commit; extra == "dev"
|
@@ -67,14 +67,15 @@ Requires-Dist: voodoonet>=0.1.1; extra == "extras"
|
|
67
67
|
[](https://zenodo.org/badge/latestdoi/233602651)
|
68
68
|
[](https://joss.theoj.org/papers/959971f196f617dddc0e7d8333ff22b7)
|
69
69
|
|
70
|
-
CloudnetPy is
|
71
|
-
remote sensing measurements. The Cloudnet processing combines cloud radar, optical lidar,
|
72
|
-
radiometer and
|
70
|
+
CloudnetPy is Python software designed for producing vertical profiles of cloud properties from ground-based
|
71
|
+
remote sensing measurements. The Cloudnet processing combines data from cloud radar, optical lidar,
|
72
|
+
microwave radiometer, and numerical weather prediction models.
|
73
|
+
Measurements and model data are brought into a common grid and
|
73
74
|
classified as ice, liquid, aerosol, insects, and so on.
|
74
|
-
|
75
|
-
retrieved in
|
75
|
+
Subsequently, geophysical products such as ice water content can be
|
76
|
+
retrieved in further processing steps. See [Illingworth et al. (2007)](https://doi.org/10.1175/BAMS-88-6-883) for more details about the concept.
|
76
77
|
|
77
|
-
CloudnetPy is a rewritten version of the original Cloudnet Matlab code.
|
78
|
+
CloudnetPy is a rewritten version of the original Cloudnet Matlab code. It features several revised methods, extensive documentation, and more.
|
78
79
|
|
79
80
|
- CloudnetPy documentation: https://cloudnetpy.readthedocs.io/en/latest/
|
80
81
|
- Cloudnet data portal: https://cloudnet.fmi.fi
|
@@ -141,7 +142,7 @@ python3 tests/e2e_test.py
|
|
141
142
|
for f in cloudnetpy/model_evaluation/tests/e2e/*/main.py; do $f; done
|
142
143
|
```
|
143
144
|
|
144
|
-
Force `pre-commit` checks (`
|
145
|
+
Force `pre-commit` checks (`ruff`, `mypy`, etc.) for all files:
|
145
146
|
|
146
147
|
```sh
|
147
148
|
pre-commit run --all
|
@@ -6,14 +6,15 @@
|
|
6
6
|
[](https://zenodo.org/badge/latestdoi/233602651)
|
7
7
|
[](https://joss.theoj.org/papers/959971f196f617dddc0e7d8333ff22b7)
|
8
8
|
|
9
|
-
CloudnetPy is
|
10
|
-
remote sensing measurements. The Cloudnet processing combines cloud radar, optical lidar,
|
11
|
-
radiometer and
|
9
|
+
CloudnetPy is Python software designed for producing vertical profiles of cloud properties from ground-based
|
10
|
+
remote sensing measurements. The Cloudnet processing combines data from cloud radar, optical lidar,
|
11
|
+
microwave radiometer, and numerical weather prediction models.
|
12
|
+
Measurements and model data are brought into a common grid and
|
12
13
|
classified as ice, liquid, aerosol, insects, and so on.
|
13
|
-
|
14
|
-
retrieved in
|
14
|
+
Subsequently, geophysical products such as ice water content can be
|
15
|
+
retrieved in further processing steps. See [Illingworth et al. (2007)](https://doi.org/10.1175/BAMS-88-6-883) for more details about the concept.
|
15
16
|
|
16
|
-
CloudnetPy is a rewritten version of the original Cloudnet Matlab code.
|
17
|
+
CloudnetPy is a rewritten version of the original Cloudnet Matlab code. It features several revised methods, extensive documentation, and more.
|
17
18
|
|
18
19
|
- CloudnetPy documentation: https://cloudnetpy.readthedocs.io/en/latest/
|
19
20
|
- Cloudnet data portal: https://cloudnet.fmi.fi
|
@@ -80,7 +81,7 @@ python3 tests/e2e_test.py
|
|
80
81
|
for f in cloudnetpy/model_evaluation/tests/e2e/*/main.py; do $f; done
|
81
82
|
```
|
82
83
|
|
83
|
-
Force `pre-commit` checks (`
|
84
|
+
Force `pre-commit` checks (`ruff`, `mypy`, etc.) for all files:
|
84
85
|
|
85
86
|
```sh
|
86
87
|
pre-commit run --all
|
@@ -1,4 +1,4 @@
|
|
1
|
-
"""
|
1
|
+
"""This module contains functions to calculate
|
2
2
|
various atmospheric parameters.
|
3
3
|
"""
|
4
4
|
from typing import Final
|
@@ -27,13 +27,16 @@ def calc_lwc_change_rate(temperature: np.ndarray, pressure: np.ndarray) -> np.nd
|
|
27
27
|
with height, given the cloud base temperature and pressure.
|
28
28
|
|
29
29
|
Args:
|
30
|
+
----
|
30
31
|
temperature: Temperature of cloud base (K).
|
31
32
|
pressure: Pressure of cloud base (Pa).
|
32
33
|
|
33
34
|
Returns:
|
35
|
+
-------
|
34
36
|
dlwc/dz (kg m-3 m-1)
|
35
37
|
|
36
38
|
References:
|
39
|
+
----------
|
37
40
|
Brenguier, 1991, https://bit.ly/2QCSJtb
|
38
41
|
|
39
42
|
"""
|
@@ -49,18 +52,19 @@ def calc_lwc_change_rate(temperature: np.ndarray, pressure: np.ndarray) -> np.nd
|
|
49
52
|
)
|
50
53
|
f3 = con.MW_RATIO * svp * pressure_difference**-2
|
51
54
|
dqs_dp = f1 * f2 * f3
|
52
|
-
|
53
|
-
return dqs_dz
|
55
|
+
return dqs_dp * air_density**2 * -scipy.constants.g
|
54
56
|
|
55
57
|
|
56
58
|
def calc_mixing_ratio(svp: np.ndarray, pressure: np.ndarray) -> np.ndarray:
|
57
59
|
"""Calculates mixing ratio from saturation vapor pressure and pressure.
|
58
60
|
|
59
61
|
Args:
|
62
|
+
----
|
60
63
|
svp: Saturation vapor pressure (Pa).
|
61
64
|
pressure: Atmospheric pressure (Pa).
|
62
65
|
|
63
66
|
Returns:
|
67
|
+
-------
|
64
68
|
Mixing ratio (kg kg-1).
|
65
69
|
|
66
70
|
"""
|
@@ -68,16 +72,20 @@ def calc_mixing_ratio(svp: np.ndarray, pressure: np.ndarray) -> np.ndarray:
|
|
68
72
|
|
69
73
|
|
70
74
|
def calc_air_density(
|
71
|
-
pressure: np.ndarray,
|
75
|
+
pressure: np.ndarray,
|
76
|
+
temperature: np.ndarray,
|
77
|
+
svp_mixing_ratio: np.ndarray,
|
72
78
|
) -> np.ndarray:
|
73
79
|
"""Calculates air density (kg m-3).
|
74
80
|
|
75
81
|
Args:
|
82
|
+
----
|
76
83
|
pressure: Pressure (Pa).
|
77
84
|
temperature: Temperature (K).
|
78
85
|
svp_mixing_ratio: Saturation vapor pressure mixing ratio (kg/kg).
|
79
86
|
|
80
87
|
Returns:
|
88
|
+
-------
|
81
89
|
Air density (kg m-3).
|
82
90
|
|
83
91
|
"""
|
@@ -88,10 +96,12 @@ def get_attenuations(data: dict, classification: ClassificationResult) -> dict:
|
|
88
96
|
"""Calculates attenuations due to atmospheric gases and liquid water.
|
89
97
|
|
90
98
|
Args:
|
99
|
+
----
|
91
100
|
data: Containing :class:`Model` and :class:`Mwr` instances.
|
92
101
|
classification: A :class:`ClassificationResult` instance.
|
93
102
|
|
94
103
|
Returns:
|
104
|
+
-------
|
95
105
|
Dictionary containing `radar_gas_atten`, `radar_liquid_atten`,
|
96
106
|
`liquid_atten_err`, `liquid_corrected` and `liquid_uncorrected` fields.
|
97
107
|
|
@@ -111,10 +121,12 @@ class Attenuation:
|
|
111
121
|
"""Base class for gas and liquid attenuations.
|
112
122
|
|
113
123
|
Args:
|
124
|
+
----
|
114
125
|
model: The :class:`Model` instance.
|
115
126
|
classification: The :class:`ClassificationResult` instance.
|
116
127
|
|
117
128
|
Attributes:
|
129
|
+
----------
|
118
130
|
classification (ClassificationResult): The :class:`ClassificationResult`
|
119
131
|
instance.
|
120
132
|
|
@@ -131,10 +143,12 @@ class GasAttenuation(Attenuation):
|
|
131
143
|
"""Radar gas attenuation class. Child of Attenuation.
|
132
144
|
|
133
145
|
Args:
|
146
|
+
----
|
134
147
|
data: Containing :class:`Model` instance.
|
135
148
|
classification: The :class:`ClassificationResult` instance.
|
136
149
|
|
137
150
|
Attributes:
|
151
|
+
----------
|
138
152
|
atten (ndarray): Gas attenuation (dB).
|
139
153
|
|
140
154
|
"""
|
@@ -146,8 +160,7 @@ class GasAttenuation(Attenuation):
|
|
146
160
|
def _calc_gas_atten(self) -> np.ndarray:
|
147
161
|
specific_atten = ma.copy(self._model["specific_gas_atten"])
|
148
162
|
specific_atten_corrected = self._fix_atten_in_liquid(specific_atten)
|
149
|
-
|
150
|
-
return gas_atten
|
163
|
+
return self._specific_to_gas_atten(specific_atten_corrected)
|
151
164
|
|
152
165
|
def _fix_atten_in_liquid(self, atten: np.ndarray) -> np.ndarray:
|
153
166
|
saturated_atten = self._model["specific_saturated_gas_atten"]
|
@@ -167,10 +180,12 @@ class LiquidAttenuation(Attenuation):
|
|
167
180
|
"""Radar liquid attenuation class. Child of Attenuation.
|
168
181
|
|
169
182
|
Args:
|
183
|
+
----
|
170
184
|
data: Containing :class:`Model` and :class:`Mwr` instances.
|
171
185
|
classification: The :class:`ClassificationResult` instance.
|
172
186
|
|
173
187
|
Attributes:
|
188
|
+
----------
|
174
189
|
atten (ndarray): Radar liquid attenuation (dB).
|
175
190
|
atten_err (ndarray): Error of radar liquid attenuation (dB).
|
176
191
|
uncorrected (ndarray): Boolean array denoting uncorrected pixels.
|
@@ -203,7 +218,8 @@ class LiquidAttenuation(Attenuation):
|
|
203
218
|
def _get_liquid_atten_err(self) -> ma.MaskedArray:
|
204
219
|
"""Finds radar liquid attenuation error."""
|
205
220
|
lwc_err_scaled = distribute_lwp_to_liquid_clouds(
|
206
|
-
self._lwc_dz_err,
|
221
|
+
self._lwc_dz_err,
|
222
|
+
self._mwr["lwp_error"][:],
|
207
223
|
)
|
208
224
|
return self._calc_attenuation(lwc_err_scaled)
|
209
225
|
|
@@ -224,9 +240,9 @@ class LiquidAttenuation(Attenuation):
|
|
224
240
|
return hard_to_correct
|
225
241
|
|
226
242
|
def _find_corrected_pixels(self) -> np.ndarray:
|
227
|
-
proper_values = self.atten > 0
|
228
|
-
|
229
|
-
return proper_values.filled(
|
243
|
+
proper_values = ma.array(self.atten > 0)
|
244
|
+
filled = False
|
245
|
+
return proper_values.filled(filled) & ~self.uncorrected
|
230
246
|
|
231
247
|
def _mask_uncorrected_attenuation(self) -> None:
|
232
248
|
self.atten[self.uncorrected] = ma.masked
|
@@ -239,10 +255,12 @@ def fill_clouds_with_lwc_dz(atmosphere: tuple, is_liquid: np.ndarray) -> np.ndar
|
|
239
255
|
"""Fills liquid clouds with lwc change rate at the cloud bases.
|
240
256
|
|
241
257
|
Args:
|
258
|
+
----
|
242
259
|
atmosphere: 2-element tuple containing temperature (K) and pressure (Pa).
|
243
260
|
is_liquid: Boolean array indicating presence of liquid clouds.
|
244
261
|
|
245
262
|
Returns:
|
263
|
+
-------
|
246
264
|
Liquid water content change rate (kg/m3/m), so that for each cloud the base
|
247
265
|
value is filled for the whole cloud.
|
248
266
|
|
@@ -254,22 +272,26 @@ def fill_clouds_with_lwc_dz(atmosphere: tuple, is_liquid: np.ndarray) -> np.ndar
|
|
254
272
|
|
255
273
|
|
256
274
|
def get_lwc_change_rate_at_bases(
|
257
|
-
atmosphere: tuple,
|
275
|
+
atmosphere: tuple,
|
276
|
+
is_liquid: np.ndarray,
|
258
277
|
) -> np.ndarray:
|
259
278
|
"""Finds LWC change rate in liquid cloud bases.
|
260
279
|
|
261
280
|
Args:
|
281
|
+
----
|
262
282
|
atmosphere: 2-element tuple containing temperature (K) and pressure (Pa).
|
263
283
|
is_liquid: Boolean array indicating presence of liquid clouds.
|
264
284
|
|
265
285
|
Returns:
|
286
|
+
-------
|
266
287
|
Liquid water content change rate at cloud bases (kg/m3/m).
|
267
288
|
|
268
289
|
"""
|
269
290
|
liquid_bases = find_cloud_bases(is_liquid)
|
270
291
|
lwc_dz = ma.zeros(liquid_bases.shape)
|
271
292
|
lwc_dz[liquid_bases] = calc_lwc_change_rate(
|
272
|
-
atmosphere[0][liquid_bases],
|
293
|
+
atmosphere[0][liquid_bases],
|
294
|
+
atmosphere[1][liquid_bases],
|
273
295
|
)
|
274
296
|
return lwc_dz
|
275
297
|
|
@@ -278,9 +300,11 @@ def find_cloud_bases(array: np.ndarray) -> np.ndarray:
|
|
278
300
|
"""Finds bases of clouds.
|
279
301
|
|
280
302
|
Args:
|
303
|
+
----
|
281
304
|
array: 2D boolean array denoting clouds or some other similar field.
|
282
305
|
|
283
306
|
Returns:
|
307
|
+
-------
|
284
308
|
Boolean array indicating bases of the individual clouds.
|
285
309
|
|
286
310
|
"""
|
@@ -293,9 +317,11 @@ def find_cloud_tops(array: np.ndarray) -> np.ndarray:
|
|
293
317
|
"""Finds tops of clouds.
|
294
318
|
|
295
319
|
Args:
|
320
|
+
----
|
296
321
|
array: 2D boolean array denoting clouds or some other similar field.
|
297
322
|
|
298
323
|
Returns:
|
324
|
+
-------
|
299
325
|
Boolean array indicating tops of the individual clouds.
|
300
326
|
|
301
327
|
"""
|
@@ -305,7 +331,8 @@ def find_cloud_tops(array: np.ndarray) -> np.ndarray:
|
|
305
331
|
|
306
332
|
|
307
333
|
def find_lowest_cloud_bases(
|
308
|
-
cloud_mask: np.ndarray,
|
334
|
+
cloud_mask: np.ndarray,
|
335
|
+
height: np.ndarray,
|
309
336
|
) -> ma.MaskedArray:
|
310
337
|
"""Finds altitudes of cloud bases."""
|
311
338
|
cloud_heights = cloud_mask * height
|
@@ -313,7 +340,8 @@ def find_lowest_cloud_bases(
|
|
313
340
|
|
314
341
|
|
315
342
|
def find_highest_cloud_tops(
|
316
|
-
cloud_mask: np.ndarray,
|
343
|
+
cloud_mask: np.ndarray,
|
344
|
+
height: np.ndarray,
|
317
345
|
) -> ma.MaskedArray:
|
318
346
|
"""Finds altitudes of cloud tops."""
|
319
347
|
cloud_heights = cloud_mask * height
|
@@ -331,11 +359,13 @@ def calc_adiabatic_lwc(lwc_change_rate: np.ndarray, dheight: float) -> np.ndarra
|
|
331
359
|
"""Calculates adiabatic liquid water content (kg/m3).
|
332
360
|
|
333
361
|
Args:
|
362
|
+
----
|
334
363
|
lwc_change_rate: Liquid water content change rate (kg/m3/m) calculated at the
|
335
364
|
base of each cloud and filled to that cloud.
|
336
365
|
dheight: Median difference of the height vector (m).
|
337
366
|
|
338
367
|
Returns:
|
368
|
+
-------
|
339
369
|
Liquid water content (kg/m3).
|
340
370
|
|
341
371
|
"""
|
@@ -352,10 +382,12 @@ def distribute_lwp_to_liquid_clouds(lwc: np.ndarray, lwp: np.ndarray) -> np.ndar
|
|
352
382
|
theoretical proportion, i.e., sum(scaled LWC) = measured LWP.
|
353
383
|
|
354
384
|
Args:
|
385
|
+
----
|
355
386
|
lwc: 2D liquid water content (kg/m3).
|
356
387
|
lwp: 1D liquid water path (kg/m2).
|
357
388
|
|
358
389
|
Returns:
|
390
|
+
-------
|
359
391
|
2D LWP-weighted, normalized LWC (kg/m2).
|
360
392
|
|
361
393
|
"""
|
@@ -17,12 +17,15 @@ def calc_wet_bulb_temperature(model_data: dict) -> np.ndarray:
|
|
17
17
|
expansion of a simple expression for the saturated vapour pressure.
|
18
18
|
|
19
19
|
Args:
|
20
|
+
----
|
20
21
|
model_data: Model variables `temperature`, `pressure`, `rh`.
|
21
22
|
|
22
23
|
Returns:
|
24
|
+
-------
|
23
25
|
Wet bulb temperature (K).
|
24
26
|
|
25
27
|
References:
|
28
|
+
----------
|
26
29
|
J. Sullivan and L. D. Sanders: Method for obtaining wet-bulb
|
27
30
|
temperatures by modifying the psychrometric formula.
|
28
31
|
|
@@ -63,9 +66,11 @@ def calc_saturation_vapor_pressure(temperature: np.ndarray) -> np.ndarray:
|
|
63
66
|
"""Goff-Gratch formula for saturation vapor pressure over water adopted by WMO.
|
64
67
|
|
65
68
|
Args:
|
69
|
+
----
|
66
70
|
temperature: Temperature (K).
|
67
71
|
|
68
72
|
Returns:
|
73
|
+
-------
|
69
74
|
Saturation vapor pressure (Pa).
|
70
75
|
|
71
76
|
"""
|
@@ -90,9 +95,11 @@ def calc_psychrometric_constant(pressure: np.ndarray) -> np.ndarray:
|
|
90
95
|
of water in air to the air temperature.
|
91
96
|
|
92
97
|
Args:
|
98
|
+
----
|
93
99
|
pressure: Atmospheric pressure (Pa).
|
94
100
|
|
95
101
|
Returns:
|
102
|
+
-------
|
96
103
|
Psychrometric constant value (Pa K-1)
|
97
104
|
|
98
105
|
"""
|
@@ -103,12 +110,15 @@ def calc_dew_point_temperature(vapor_pressure: np.ndarray) -> np.ndarray:
|
|
103
110
|
"""Returns dew point temperature.
|
104
111
|
|
105
112
|
Args:
|
113
|
+
----
|
106
114
|
vapor_pressure: Water vapor pressure (Pa).
|
107
115
|
|
108
116
|
Returns:
|
117
|
+
-------
|
109
118
|
Dew point temperature (K).
|
110
119
|
|
111
120
|
Notes:
|
121
|
+
-----
|
112
122
|
Method from Vaisala's white paper: "Humidity conversion formulas".
|
113
123
|
|
114
124
|
"""
|
@@ -130,4 +140,4 @@ def k2c(temp: np.ndarray) -> np.ndarray:
|
|
130
140
|
|
131
141
|
def mmh2ms(data: np.ndarray) -> np.ndarray:
|
132
142
|
"""Converts mm h-1 to m s-1"""
|
133
|
-
return data /
|
143
|
+
return data / con.SEC_IN_HOUR * con.MM_TO_M
|
@@ -10,7 +10,9 @@ from cloudnetpy.metadata import MetaData
|
|
10
10
|
|
11
11
|
|
12
12
|
def generate_categorize(
|
13
|
-
input_files: dict,
|
13
|
+
input_files: dict,
|
14
|
+
output_file: str,
|
15
|
+
uuid: str | None = None,
|
14
16
|
) -> str:
|
15
17
|
"""Generates Cloudnet Level 1c categorize file.
|
16
18
|
|
@@ -21,6 +23,7 @@ def generate_categorize(
|
|
21
23
|
in *ouput_file* which is a compressed netCDF4 file.
|
22
24
|
|
23
25
|
Args:
|
26
|
+
----
|
24
27
|
input_files: dict containing file names for calibrated `radar`, `lidar`,
|
25
28
|
`model` and `mwr` files. Optionally also `lv0_files`, a list of
|
26
29
|
RPG level 0 files.
|
@@ -28,12 +31,15 @@ def generate_categorize(
|
|
28
31
|
uuid: Set specific UUID for the file.
|
29
32
|
|
30
33
|
Returns:
|
34
|
+
-------
|
31
35
|
UUID of the generated file.
|
32
36
|
|
33
37
|
Raises:
|
38
|
+
------
|
34
39
|
RuntimeError: Failed to create the categorize file.
|
35
40
|
|
36
41
|
Notes:
|
42
|
+
-----
|
37
43
|
Separate mwr-file is not needed when using RPG cloud radar which
|
38
44
|
measures liquid water path. Then, the radar file can be used as
|
39
45
|
a mwr-file as well, i.e. {'mwr': 'radar.nc'}.
|
@@ -42,6 +48,7 @@ def generate_categorize(
|
|
42
48
|
to detect liquid droplets.
|
43
49
|
|
44
50
|
Examples:
|
51
|
+
--------
|
45
52
|
>>> from cloudnetpy.categorize import generate_categorize
|
46
53
|
>>> input_files = {'radar': 'radar.nc',
|
47
54
|
'lidar': 'lidar.nc',
|
@@ -56,14 +63,13 @@ def generate_categorize(
|
|
56
63
|
|
57
64
|
def _interpolate_to_cloudnet_grid() -> list:
|
58
65
|
wl_band = utils.get_wl_band(data["radar"].radar_frequency)
|
59
|
-
data["model"].interpolate_to_common_height(wl_band)
|
60
|
-
data["model"].interpolate_to_grid(time, height)
|
61
66
|
data["mwr"].rebin_to_grid(time)
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
+
data["model"].interpolate_to_common_height(wl_band)
|
68
|
+
model_gap_ind = data["model"].interpolate_to_grid(time, height)
|
69
|
+
radar_gap_ind = data["radar"].rebin_to_grid(time)
|
70
|
+
lidar_gap_ind = data["lidar"].interpolate_to_grid(time, height)
|
71
|
+
gap_indices = set(radar_gap_ind + lidar_gap_ind + model_gap_ind)
|
72
|
+
return [ind for ind in range(len(time)) if ind not in gap_indices]
|
67
73
|
|
68
74
|
def _screen_bad_time_indices(valid_indices: list) -> None:
|
69
75
|
n_time_full = len(time)
|
@@ -102,10 +108,10 @@ def generate_categorize(
|
|
102
108
|
**data["mwr"].data,
|
103
109
|
}
|
104
110
|
|
105
|
-
def _define_dense_grid():
|
111
|
+
def _define_dense_grid() -> tuple:
|
106
112
|
return utils.time_grid(), data["radar"].height
|
107
113
|
|
108
|
-
def _close_all():
|
114
|
+
def _close_all() -> None:
|
109
115
|
for obj in data.values():
|
110
116
|
if isinstance(obj, Radar | Lidar | Mwr | Model):
|
111
117
|
obj.close()
|
@@ -117,14 +123,20 @@ def generate_categorize(
|
|
117
123
|
"mwr": Mwr(input_files["mwr"]),
|
118
124
|
"lv0_files": input_files.get("lv0_files", None),
|
119
125
|
}
|
120
|
-
|
126
|
+
if data["radar"].altitude is None:
|
127
|
+
msg = "Radar altitude not defined"
|
128
|
+
raise RuntimeError(msg)
|
121
129
|
data["model"] = Model(input_files["model"], data["radar"].altitude)
|
122
130
|
time, height = _define_dense_grid()
|
123
131
|
valid_ind = _interpolate_to_cloudnet_grid()
|
124
132
|
if not valid_ind:
|
125
|
-
|
133
|
+
msg = "No overlapping radar and lidar timestamps found"
|
134
|
+
raise ValidTimeStampError(msg)
|
126
135
|
_screen_bad_time_indices(valid_ind)
|
127
|
-
if
|
136
|
+
if (
|
137
|
+
"rpg" in data["radar"].source_type.lower()
|
138
|
+
or "basta" in data["radar"].source_type.lower()
|
139
|
+
):
|
128
140
|
data["radar"].filter_speckle_noise()
|
129
141
|
data["radar"].filter_1st_gate_artifact()
|
130
142
|
for variable in ("v", "v_sigma", "ldr"):
|
@@ -142,17 +154,18 @@ def generate_categorize(
|
|
142
154
|
attributes = output.add_time_attribute(attributes, date, "model_time")
|
143
155
|
attributes = output.add_source_attribute(attributes, data)
|
144
156
|
output.update_attributes(cloudnet_arrays, attributes)
|
145
|
-
|
146
|
-
return uuid
|
157
|
+
return _save_cat(output_file, data, cloudnet_arrays, uuid)
|
147
158
|
finally:
|
148
159
|
_close_all()
|
149
160
|
|
150
161
|
|
151
162
|
def _save_cat(
|
152
|
-
full_path: str,
|
163
|
+
full_path: str,
|
164
|
+
data_obs: dict,
|
165
|
+
cloudnet_arrays: dict,
|
166
|
+
uuid: str | None,
|
153
167
|
) -> str:
|
154
168
|
"""Creates a categorize netCDF4 file and saves all data into it."""
|
155
|
-
|
156
169
|
dims = {
|
157
170
|
"time": len(data_obs["radar"].time),
|
158
171
|
"height": len(data_obs["radar"].height),
|
@@ -165,7 +178,9 @@ def _save_cat(
|
|
165
178
|
uuid_out = nc.file_uuid
|
166
179
|
nc.cloudnet_file_type = file_type
|
167
180
|
output.copy_global(
|
168
|
-
data_obs["radar"].dataset,
|
181
|
+
data_obs["radar"].dataset,
|
182
|
+
nc,
|
183
|
+
("year", "month", "day", "location"),
|
169
184
|
)
|
170
185
|
nc.title = f"Cloud categorization products from {data_obs['radar'].location}"
|
171
186
|
nc.source_file_uuids = output.get_source_uuids(*data_obs.values())
|
@@ -174,10 +189,11 @@ def _save_cat(
|
|
174
189
|
["https://doi.org/10.5194/amt-15-5343-2022"] if is_voodoo else None
|
175
190
|
)
|
176
191
|
nc.references = output.get_references(
|
177
|
-
identifier=file_type,
|
192
|
+
identifier=file_type,
|
193
|
+
extra=extra_references,
|
178
194
|
)
|
179
195
|
if is_voodoo:
|
180
|
-
import voodoonet.version
|
196
|
+
import voodoonet.version
|
181
197
|
|
182
198
|
nc.voodoonet_version = voodoonet.version.__version__
|
183
199
|
output.add_source_instruments(nc, data_obs)
|
@@ -316,7 +332,8 @@ CATEGORIZE_ATTRIBUTES = {
|
|
316
332
|
comment=COMMENTS["Z_sensitivity"],
|
317
333
|
),
|
318
334
|
"v_sigma": MetaData(
|
319
|
-
long_name="Standard deviation of mean Doppler velocity",
|
335
|
+
long_name="Standard deviation of mean Doppler velocity",
|
336
|
+
units="m s-1",
|
320
337
|
),
|
321
338
|
# Lidar variables
|
322
339
|
"beta": MetaData(
|