cloudnetpy 1.49.9__py3-none-any.whl → 1.87.3__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- cloudnetpy/categorize/__init__.py +1 -2
- cloudnetpy/categorize/atmos_utils.py +297 -67
- cloudnetpy/categorize/attenuation.py +31 -0
- cloudnetpy/categorize/attenuations/__init__.py +37 -0
- cloudnetpy/categorize/attenuations/gas_attenuation.py +30 -0
- cloudnetpy/categorize/attenuations/liquid_attenuation.py +84 -0
- cloudnetpy/categorize/attenuations/melting_attenuation.py +78 -0
- cloudnetpy/categorize/attenuations/rain_attenuation.py +84 -0
- cloudnetpy/categorize/categorize.py +332 -156
- cloudnetpy/categorize/classify.py +127 -125
- cloudnetpy/categorize/containers.py +107 -76
- cloudnetpy/categorize/disdrometer.py +40 -0
- cloudnetpy/categorize/droplet.py +23 -21
- cloudnetpy/categorize/falling.py +53 -24
- cloudnetpy/categorize/freezing.py +25 -12
- cloudnetpy/categorize/insects.py +35 -23
- cloudnetpy/categorize/itu.py +243 -0
- cloudnetpy/categorize/lidar.py +36 -41
- cloudnetpy/categorize/melting.py +34 -26
- cloudnetpy/categorize/model.py +84 -37
- cloudnetpy/categorize/mwr.py +18 -14
- cloudnetpy/categorize/radar.py +215 -102
- cloudnetpy/cli.py +578 -0
- cloudnetpy/cloudnetarray.py +43 -89
- cloudnetpy/concat_lib.py +218 -78
- cloudnetpy/constants.py +28 -10
- cloudnetpy/datasource.py +61 -86
- cloudnetpy/exceptions.py +49 -20
- cloudnetpy/instruments/__init__.py +5 -0
- cloudnetpy/instruments/basta.py +29 -12
- cloudnetpy/instruments/bowtie.py +135 -0
- cloudnetpy/instruments/ceilo.py +138 -115
- cloudnetpy/instruments/ceilometer.py +164 -80
- cloudnetpy/instruments/cl61d.py +21 -5
- cloudnetpy/instruments/cloudnet_instrument.py +74 -36
- cloudnetpy/instruments/copernicus.py +108 -30
- cloudnetpy/instruments/da10.py +54 -0
- cloudnetpy/instruments/disdrometer/common.py +126 -223
- cloudnetpy/instruments/disdrometer/parsivel.py +453 -94
- cloudnetpy/instruments/disdrometer/thies.py +254 -87
- cloudnetpy/instruments/fd12p.py +201 -0
- cloudnetpy/instruments/galileo.py +65 -23
- cloudnetpy/instruments/hatpro.py +123 -49
- cloudnetpy/instruments/instruments.py +113 -1
- cloudnetpy/instruments/lufft.py +39 -17
- cloudnetpy/instruments/mira.py +268 -61
- cloudnetpy/instruments/mrr.py +187 -0
- cloudnetpy/instruments/nc_lidar.py +19 -8
- cloudnetpy/instruments/nc_radar.py +109 -55
- cloudnetpy/instruments/pollyxt.py +135 -51
- cloudnetpy/instruments/radiometrics.py +313 -59
- cloudnetpy/instruments/rain_e_h3.py +171 -0
- cloudnetpy/instruments/rpg.py +321 -189
- cloudnetpy/instruments/rpg_reader.py +74 -40
- cloudnetpy/instruments/toa5.py +49 -0
- cloudnetpy/instruments/vaisala.py +95 -343
- cloudnetpy/instruments/weather_station.py +774 -105
- cloudnetpy/metadata.py +90 -19
- cloudnetpy/model_evaluation/file_handler.py +55 -52
- cloudnetpy/model_evaluation/metadata.py +46 -20
- cloudnetpy/model_evaluation/model_metadata.py +1 -1
- cloudnetpy/model_evaluation/plotting/plot_tools.py +32 -37
- cloudnetpy/model_evaluation/plotting/plotting.py +327 -117
- cloudnetpy/model_evaluation/products/advance_methods.py +92 -83
- cloudnetpy/model_evaluation/products/grid_methods.py +88 -63
- cloudnetpy/model_evaluation/products/model_products.py +43 -35
- cloudnetpy/model_evaluation/products/observation_products.py +41 -35
- cloudnetpy/model_evaluation/products/product_resampling.py +17 -7
- cloudnetpy/model_evaluation/products/tools.py +29 -20
- cloudnetpy/model_evaluation/statistics/statistical_methods.py +30 -20
- 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 +15 -14
- cloudnetpy/model_evaluation/tests/e2e/process_iwc/main.py +9 -5
- cloudnetpy/model_evaluation/tests/e2e/process_iwc/tests.py +15 -14
- cloudnetpy/model_evaluation/tests/e2e/process_lwc/main.py +9 -5
- cloudnetpy/model_evaluation/tests/e2e/process_lwc/tests.py +15 -14
- cloudnetpy/model_evaluation/tests/unit/conftest.py +42 -41
- cloudnetpy/model_evaluation/tests/unit/test_advance_methods.py +41 -48
- cloudnetpy/model_evaluation/tests/unit/test_grid_methods.py +216 -194
- cloudnetpy/model_evaluation/tests/unit/test_model_products.py +23 -21
- cloudnetpy/model_evaluation/tests/unit/test_observation_products.py +37 -38
- cloudnetpy/model_evaluation/tests/unit/test_plot_tools.py +43 -40
- cloudnetpy/model_evaluation/tests/unit/test_plotting.py +30 -36
- cloudnetpy/model_evaluation/tests/unit/test_statistical_methods.py +68 -31
- cloudnetpy/model_evaluation/tests/unit/test_tools.py +33 -26
- cloudnetpy/model_evaluation/utils.py +2 -1
- cloudnetpy/output.py +170 -111
- cloudnetpy/plotting/__init__.py +2 -1
- cloudnetpy/plotting/plot_meta.py +562 -822
- cloudnetpy/plotting/plotting.py +1142 -704
- cloudnetpy/products/__init__.py +1 -0
- cloudnetpy/products/classification.py +370 -88
- cloudnetpy/products/der.py +85 -55
- cloudnetpy/products/drizzle.py +77 -34
- cloudnetpy/products/drizzle_error.py +15 -11
- cloudnetpy/products/drizzle_tools.py +79 -59
- cloudnetpy/products/epsilon.py +211 -0
- cloudnetpy/products/ier.py +27 -50
- cloudnetpy/products/iwc.py +55 -48
- cloudnetpy/products/lwc.py +96 -70
- cloudnetpy/products/mwr_tools.py +186 -0
- cloudnetpy/products/product_tools.py +170 -128
- cloudnetpy/utils.py +455 -240
- cloudnetpy/version.py +2 -2
- {cloudnetpy-1.49.9.dist-info → cloudnetpy-1.87.3.dist-info}/METADATA +44 -40
- cloudnetpy-1.87.3.dist-info/RECORD +127 -0
- {cloudnetpy-1.49.9.dist-info → cloudnetpy-1.87.3.dist-info}/WHEEL +1 -1
- cloudnetpy-1.87.3.dist-info/entry_points.txt +2 -0
- docs/source/conf.py +2 -2
- cloudnetpy/categorize/atmos.py +0 -361
- cloudnetpy/products/mwr_multi.py +0 -68
- cloudnetpy/products/mwr_single.py +0 -75
- cloudnetpy-1.49.9.dist-info/RECORD +0 -112
- {cloudnetpy-1.49.9.dist-info → cloudnetpy-1.87.3.dist-info/licenses}/LICENSE +0 -0
- {cloudnetpy-1.49.9.dist-info → cloudnetpy-1.87.3.dist-info}/top_level.txt +0 -0
|
@@ -1,22 +1,27 @@
|
|
|
1
1
|
"""Module for reading raw cloud radar data."""
|
|
2
|
+
|
|
3
|
+
import datetime
|
|
2
4
|
import os
|
|
5
|
+
import tempfile
|
|
6
|
+
from os import PathLike
|
|
3
7
|
from tempfile import TemporaryDirectory
|
|
8
|
+
from uuid import UUID
|
|
4
9
|
|
|
5
10
|
import numpy as np
|
|
6
11
|
|
|
7
12
|
from cloudnetpy import concat_lib, output, utils
|
|
8
13
|
from cloudnetpy.instruments.instruments import COPERNICUS
|
|
9
14
|
from cloudnetpy.instruments.nc_radar import ChilboltonRadar
|
|
10
|
-
from cloudnetpy.metadata import MetaData
|
|
15
|
+
from cloudnetpy.metadata import COMMON_ATTRIBUTES, MetaData
|
|
11
16
|
|
|
12
17
|
|
|
13
18
|
def copernicus2nc(
|
|
14
|
-
raw_files: str,
|
|
15
|
-
output_file: str,
|
|
19
|
+
raw_files: str | PathLike,
|
|
20
|
+
output_file: str | PathLike,
|
|
16
21
|
site_meta: dict,
|
|
17
|
-
uuid: str | None = None,
|
|
18
|
-
date: str | None = None,
|
|
19
|
-
) ->
|
|
22
|
+
uuid: str | UUID | None = None,
|
|
23
|
+
date: str | datetime.date | None = None,
|
|
24
|
+
) -> UUID:
|
|
20
25
|
"""Converts 'Copernicus' cloud radar data into Cloudnet Level 1b netCDF file.
|
|
21
26
|
|
|
22
27
|
Args:
|
|
@@ -41,6 +46,10 @@ def copernicus2nc(
|
|
|
41
46
|
>>> copernicus2nc('/one/day/of/copernicus/files/', 'radar.nc', site_meta)
|
|
42
47
|
|
|
43
48
|
"""
|
|
49
|
+
if isinstance(date, str):
|
|
50
|
+
date = datetime.date.fromisoformat(date)
|
|
51
|
+
uuid = utils.get_uuid(uuid)
|
|
52
|
+
|
|
44
53
|
keymap = {
|
|
45
54
|
"ZED_HC": "Zh",
|
|
46
55
|
"VEL_HC": "v",
|
|
@@ -55,15 +64,25 @@ def copernicus2nc(
|
|
|
55
64
|
"beamwidthH": "beamwidthH",
|
|
56
65
|
}
|
|
57
66
|
|
|
67
|
+
nc_filename: str | PathLike
|
|
58
68
|
with TemporaryDirectory() as temp_dir:
|
|
59
69
|
if os.path.isdir(raw_files):
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
70
|
+
with tempfile.NamedTemporaryFile(
|
|
71
|
+
dir=temp_dir,
|
|
72
|
+
suffix=".nc",
|
|
73
|
+
delete=False,
|
|
74
|
+
) as temp_file:
|
|
75
|
+
nc_filename = temp_file.name
|
|
76
|
+
valid_filenames = utils.get_sorted_filenames(raw_files, ".nc")
|
|
77
|
+
valid_filenames = utils.get_files_with_variables(
|
|
78
|
+
valid_filenames, ["time", "ZED_HC"]
|
|
79
|
+
)
|
|
80
|
+
variables = list(keymap.keys())
|
|
81
|
+
concat_lib.concatenate_files(
|
|
82
|
+
valid_filenames,
|
|
83
|
+
nc_filename,
|
|
84
|
+
variables=variables,
|
|
85
|
+
)
|
|
67
86
|
else:
|
|
68
87
|
nc_filename = raw_files
|
|
69
88
|
|
|
@@ -75,19 +94,26 @@ def copernicus2nc(
|
|
|
75
94
|
copernicus.sort_timestamps()
|
|
76
95
|
copernicus.remove_duplicate_timestamps()
|
|
77
96
|
copernicus.calibrate_reflectivity()
|
|
78
|
-
copernicus.
|
|
97
|
+
copernicus.screen_using_top_gates_snr()
|
|
79
98
|
copernicus.mask_corrupted_values()
|
|
99
|
+
copernicus.mask_first_range_gates()
|
|
80
100
|
copernicus.mask_invalid_data()
|
|
81
|
-
copernicus.
|
|
101
|
+
copernicus.fix_range_offset(site_meta)
|
|
102
|
+
copernicus.screen_negative_ranges()
|
|
82
103
|
copernicus.add_radar_specific_variables()
|
|
83
104
|
copernicus.add_nyquist_velocity(keymap)
|
|
84
105
|
copernicus.add_site_geolocation()
|
|
85
|
-
valid_indices = copernicus.add_zenith_and_azimuth_angles(
|
|
106
|
+
valid_indices = copernicus.add_zenith_and_azimuth_angles(
|
|
107
|
+
elevation_threshold=1.1,
|
|
108
|
+
elevation_diff_threshold=0.5,
|
|
109
|
+
azimuth_diff_threshold=0.1,
|
|
110
|
+
)
|
|
86
111
|
copernicus.screen_time_indices(valid_indices)
|
|
87
112
|
copernicus.add_height()
|
|
113
|
+
copernicus.test_if_all_masked()
|
|
88
114
|
attributes = output.add_time_attribute(ATTRIBUTES, copernicus.date)
|
|
89
115
|
output.update_attributes(copernicus.data, attributes)
|
|
90
|
-
|
|
116
|
+
output.save_level1b(copernicus, output_file, uuid)
|
|
91
117
|
return uuid
|
|
92
118
|
|
|
93
119
|
|
|
@@ -100,17 +126,35 @@ class Copernicus(ChilboltonRadar):
|
|
|
100
126
|
|
|
101
127
|
"""
|
|
102
128
|
|
|
103
|
-
def __init__(self, full_path: str, site_meta: dict):
|
|
129
|
+
def __init__(self, full_path: str | PathLike, site_meta: dict) -> None:
|
|
104
130
|
super().__init__(full_path, site_meta)
|
|
105
131
|
self.instrument = COPERNICUS
|
|
106
132
|
|
|
107
|
-
def calibrate_reflectivity(self):
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
133
|
+
def calibrate_reflectivity(self) -> None:
|
|
134
|
+
zed_hc = self.dataset["ZED_HC"]
|
|
135
|
+
offset_applied = getattr(zed_hc, "applied_calibration_offset", 0)
|
|
136
|
+
|
|
137
|
+
# Estimated by comparing with MIRA-35 data:
|
|
138
|
+
default_offset = -149.5
|
|
139
|
+
zh_offset = self.site_meta.get("Zh_offset", default_offset)
|
|
140
|
+
|
|
141
|
+
self.data["Zh"].data[:] = self.data["Zh"].data[:] - offset_applied + zh_offset
|
|
142
|
+
self.append_data(np.array(zh_offset, dtype=np.float32), "Zh_offset")
|
|
143
|
+
|
|
144
|
+
def fix_range_offset(self, site_meta: dict) -> None:
|
|
145
|
+
range_var = self.dataset["range"]
|
|
146
|
+
offset_applied = getattr(range_var, "range_offset", 0)
|
|
112
147
|
|
|
113
|
-
|
|
148
|
+
# Estimated by comparing with MIRA-35 data:
|
|
149
|
+
default_offset = -720
|
|
150
|
+
range_offset = site_meta.get("range_offset", default_offset)
|
|
151
|
+
|
|
152
|
+
self.data["range"].data[:] = (
|
|
153
|
+
self.data["range"].data[:] - offset_applied + range_offset
|
|
154
|
+
)
|
|
155
|
+
self.append_data(np.array(range_offset, dtype=float), "range_offset")
|
|
156
|
+
|
|
157
|
+
def mask_corrupted_values(self) -> None:
|
|
114
158
|
"""Experimental masking of corrupted Copernicus data.
|
|
115
159
|
|
|
116
160
|
Notes:
|
|
@@ -122,14 +166,48 @@ class Copernicus(ChilboltonRadar):
|
|
|
122
166
|
ind = np.where(np.abs(self.data[key][:]) > value)
|
|
123
167
|
self.data["v"].mask_indices(ind)
|
|
124
168
|
|
|
169
|
+
def screen_negative_ranges(self) -> None:
|
|
170
|
+
"""Screens negative range values."""
|
|
171
|
+
valid_ind = np.where(self.data["range"][:] >= 0)[0]
|
|
172
|
+
for key, cloudnet_array in self.data.items():
|
|
173
|
+
try:
|
|
174
|
+
data = cloudnet_array[:]
|
|
175
|
+
if data.ndim == 2:
|
|
176
|
+
cloudnet_array.data = data[:, valid_ind]
|
|
177
|
+
elif key == "range":
|
|
178
|
+
cloudnet_array.data = data[valid_ind]
|
|
179
|
+
except IndexError:
|
|
180
|
+
continue
|
|
181
|
+
|
|
125
182
|
|
|
126
183
|
ATTRIBUTES = {
|
|
127
|
-
"
|
|
184
|
+
"Zh_offset": MetaData(
|
|
128
185
|
long_name="Radar reflectivity calibration offset",
|
|
129
|
-
units="
|
|
130
|
-
comment=
|
|
186
|
+
units="dBZ",
|
|
187
|
+
comment=(
|
|
188
|
+
"Calibration offset applied after removing the original offset "
|
|
189
|
+
"from the raw files."
|
|
190
|
+
),
|
|
191
|
+
dimensions=None,
|
|
192
|
+
),
|
|
193
|
+
"Zh": COMMON_ATTRIBUTES["Zh"]._replace(ancillary_variables="Zh_offset"),
|
|
194
|
+
"range_offset": MetaData(
|
|
195
|
+
long_name="Radar range offset",
|
|
196
|
+
units="m",
|
|
197
|
+
comment=(
|
|
198
|
+
"Range offset applied after removing the original offset "
|
|
199
|
+
"from the raw files."
|
|
200
|
+
),
|
|
201
|
+
dimensions=None,
|
|
202
|
+
),
|
|
203
|
+
"range": COMMON_ATTRIBUTES["range"]._replace(ancillary_variables="range_offset"),
|
|
204
|
+
"antenna_diameter": MetaData(
|
|
205
|
+
long_name="Antenna diameter", units="m", dimensions=("time",)
|
|
206
|
+
),
|
|
207
|
+
"beamwidthV": MetaData(
|
|
208
|
+
long_name="Vertical angular beamwidth", units="degree", dimensions=("time",)
|
|
209
|
+
),
|
|
210
|
+
"beamwidthH": MetaData(
|
|
211
|
+
long_name="Horizontal angular beamwidth", units="degree", dimensions=("time",)
|
|
131
212
|
),
|
|
132
|
-
"antenna_diameter": MetaData(long_name="Antenna diameter", units="m"),
|
|
133
|
-
"beamwidthV": MetaData(long_name="Vertical angular beamwidth", units="degree"),
|
|
134
|
-
"beamwidthH": MetaData(long_name="Horizontal angular beamwidth", units="degree"),
|
|
135
213
|
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import datetime
|
|
2
|
+
import logging
|
|
3
|
+
from os import PathLike
|
|
4
|
+
|
|
5
|
+
import netCDF4
|
|
6
|
+
|
|
7
|
+
from cloudnetpy import utils
|
|
8
|
+
from cloudnetpy.exceptions import LidarDataError
|
|
9
|
+
from cloudnetpy.instruments import instruments
|
|
10
|
+
from cloudnetpy.instruments.nc_lidar import NcLidar
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class Da10(NcLidar):
|
|
14
|
+
"""Class for Vaisala DA10 differential absorption lidar."""
|
|
15
|
+
|
|
16
|
+
def __init__(
|
|
17
|
+
self,
|
|
18
|
+
file_name: str | PathLike,
|
|
19
|
+
site_meta: dict,
|
|
20
|
+
expected_date: datetime.date | None = None,
|
|
21
|
+
) -> None:
|
|
22
|
+
super().__init__()
|
|
23
|
+
self.file_name = file_name
|
|
24
|
+
self.site_meta = site_meta
|
|
25
|
+
self.expected_date = expected_date
|
|
26
|
+
self.instrument = instruments.DA10
|
|
27
|
+
|
|
28
|
+
def read_ceilometer_file(self, calibration_factor: float | None = None) -> None:
|
|
29
|
+
with netCDF4.Dataset(self.file_name) as dataset:
|
|
30
|
+
self.dataset = dataset
|
|
31
|
+
self._fetch_attributes()
|
|
32
|
+
self._fetch_zenith_angle("tilt_angle", default=3.0)
|
|
33
|
+
self._fetch_range(reference="lower")
|
|
34
|
+
self._fetch_lidar_variables(calibration_factor)
|
|
35
|
+
self._fetch_time_and_date()
|
|
36
|
+
self.dataset = None
|
|
37
|
+
|
|
38
|
+
def _fetch_lidar_variables(self, calibration_factor: float | None = None) -> None:
|
|
39
|
+
if self.dataset is None:
|
|
40
|
+
msg = "No dataset found"
|
|
41
|
+
raise RuntimeError(msg)
|
|
42
|
+
beta_raw = self.dataset.variables["beta_att"][:]
|
|
43
|
+
if utils.is_all_masked(beta_raw):
|
|
44
|
+
msg = "All beta_raw values are masked. Check the input file(s)."
|
|
45
|
+
raise LidarDataError(msg)
|
|
46
|
+
if calibration_factor is None:
|
|
47
|
+
logging.warning("Using default calibration factor")
|
|
48
|
+
calibration_factor = 1
|
|
49
|
+
beta_raw *= calibration_factor
|
|
50
|
+
self.data["calibration_factor"] = float(calibration_factor)
|
|
51
|
+
self.data["beta_raw"] = beta_raw
|
|
52
|
+
|
|
53
|
+
def _fetch_attributes(self) -> None:
|
|
54
|
+
self.serial_number = getattr(self.dataset, "instrument_serial_number", None)
|