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,32 +1,39 @@
|
|
|
1
1
|
"""Module for reading / converting pollyxt data."""
|
|
2
|
+
|
|
3
|
+
import datetime
|
|
2
4
|
import glob
|
|
3
5
|
import logging
|
|
6
|
+
from collections import Counter
|
|
7
|
+
from collections.abc import Sequence
|
|
8
|
+
from fnmatch import fnmatch
|
|
9
|
+
from os import PathLike
|
|
10
|
+
from uuid import UUID
|
|
4
11
|
|
|
5
12
|
import netCDF4
|
|
6
13
|
import numpy as np
|
|
14
|
+
import numpy.typing as npt
|
|
7
15
|
from numpy import ma
|
|
8
|
-
from numpy.testing import
|
|
16
|
+
from numpy.testing import assert_almost_equal
|
|
9
17
|
|
|
10
18
|
from cloudnetpy import output, utils
|
|
11
19
|
from cloudnetpy.exceptions import InconsistentDataError, ValidTimeStampError
|
|
12
20
|
from cloudnetpy.instruments import instruments
|
|
13
21
|
from cloudnetpy.instruments.ceilometer import Ceilometer
|
|
14
|
-
from cloudnetpy.metadata import MetaData
|
|
15
|
-
from cloudnetpy.utils import Epoch
|
|
22
|
+
from cloudnetpy.metadata import COMMON_ATTRIBUTES, MetaData
|
|
16
23
|
|
|
17
24
|
|
|
18
25
|
def pollyxt2nc(
|
|
19
|
-
|
|
20
|
-
output_file: str,
|
|
26
|
+
input_data: str | PathLike | Sequence[str | PathLike],
|
|
27
|
+
output_file: str | PathLike,
|
|
21
28
|
site_meta: dict,
|
|
22
|
-
uuid: str | None = None,
|
|
23
|
-
date: str | None = None,
|
|
24
|
-
) ->
|
|
25
|
-
"""
|
|
26
|
-
Converts PollyXT Raman lidar data into Cloudnet Level 1b netCDF file.
|
|
29
|
+
uuid: str | UUID | None = None,
|
|
30
|
+
date: str | datetime.date | None = None,
|
|
31
|
+
) -> UUID:
|
|
32
|
+
"""Converts PollyXT Raman lidar data into Cloudnet Level 1b netCDF file.
|
|
27
33
|
|
|
28
34
|
Args:
|
|
29
|
-
|
|
35
|
+
input_data: Path to folder containing pollyxt netCDF files
|
|
36
|
+
or a sequence of filename paths.
|
|
30
37
|
output_file: Output filename.
|
|
31
38
|
site_meta: Dictionary containing information about the site with keys:
|
|
32
39
|
|
|
@@ -49,67 +56,87 @@ def pollyxt2nc(
|
|
|
49
56
|
>>> pollyxt2nc('/path/to/files/', 'pollyxt.nc', site_meta)
|
|
50
57
|
|
|
51
58
|
"""
|
|
59
|
+
if isinstance(date, str):
|
|
60
|
+
date = datetime.date.fromisoformat(date)
|
|
61
|
+
uuid = utils.get_uuid(uuid)
|
|
52
62
|
snr_limit = site_meta.get("snr_limit", 2)
|
|
53
63
|
polly = PollyXt(site_meta, date)
|
|
54
|
-
epoch = polly.fetch_data(
|
|
64
|
+
epoch = polly.fetch_data(input_data)
|
|
55
65
|
polly.get_date_and_time(epoch)
|
|
56
66
|
polly.fetch_zenith_angle()
|
|
57
67
|
polly.calc_screened_products(snr_limit)
|
|
58
68
|
polly.mask_nan_values()
|
|
59
69
|
polly.prepare_data()
|
|
60
|
-
polly.
|
|
70
|
+
polly.screen_completely_masked_profiles()
|
|
71
|
+
polly.data_to_cloudnet_arrays(time_dtype="f8")
|
|
72
|
+
polly.add_site_geolocation()
|
|
61
73
|
attributes = output.add_time_attribute(ATTRIBUTES, polly.date)
|
|
62
74
|
output.update_attributes(polly.data, attributes)
|
|
63
75
|
polly.add_snr_info("beta", snr_limit)
|
|
64
|
-
|
|
76
|
+
output.save_level1b(polly, output_file, uuid)
|
|
65
77
|
return uuid
|
|
66
78
|
|
|
67
79
|
|
|
68
80
|
class PollyXt(Ceilometer):
|
|
69
|
-
def __init__(self, site_meta: dict, expected_date:
|
|
81
|
+
def __init__(self, site_meta: dict, expected_date: datetime.date | None) -> None:
|
|
70
82
|
super().__init__()
|
|
71
83
|
self.site_meta = site_meta
|
|
72
84
|
self.expected_date = expected_date
|
|
73
85
|
self.instrument = instruments.POLLYXT
|
|
74
86
|
|
|
75
|
-
def mask_nan_values(self):
|
|
87
|
+
def mask_nan_values(self) -> None:
|
|
76
88
|
for array in self.data.values():
|
|
77
89
|
if getattr(array, "ndim", 0) > 0:
|
|
78
90
|
array[np.isnan(array)] = ma.masked
|
|
79
91
|
|
|
80
|
-
def calc_screened_products(self, snr_limit: float = 5.0):
|
|
92
|
+
def calc_screened_products(self, snr_limit: float = 5.0) -> None:
|
|
81
93
|
keys = ("beta", "depolarisation")
|
|
82
94
|
for key in keys:
|
|
83
95
|
self.data[key] = ma.masked_where(
|
|
84
|
-
self.data["snr"] < snr_limit,
|
|
96
|
+
self.data["snr"] < snr_limit,
|
|
97
|
+
self.data[f"{key}_raw"],
|
|
85
98
|
)
|
|
86
99
|
self.data["depolarisation"][self.data["depolarisation"] > 1] = ma.masked
|
|
87
100
|
self.data["depolarisation"][self.data["depolarisation"] < 0] = ma.masked
|
|
101
|
+
self.data["beta"][self.data["beta"] < 0] = ma.masked
|
|
88
102
|
del self.data["snr"]
|
|
89
103
|
|
|
90
104
|
def fetch_zenith_angle(self) -> None:
|
|
91
105
|
default = 5
|
|
92
106
|
self.data["zenith_angle"] = float(self.metadata.get("zenith_angle", default))
|
|
93
107
|
|
|
94
|
-
def fetch_data(
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
108
|
+
def fetch_data(
|
|
109
|
+
self, input_data: str | PathLike | Sequence[str | PathLike]
|
|
110
|
+
) -> datetime.datetime:
|
|
111
|
+
att_id = "*[0-9]_att*.nc"
|
|
112
|
+
vol_id = "*[0-9]_vol*.nc"
|
|
113
|
+
if isinstance(input_data, (str, PathLike)):
|
|
114
|
+
bsc_files = glob.glob(f"{input_data}/{att_id}")
|
|
115
|
+
depol_files = glob.glob(f"{input_data}/{vol_id}")
|
|
116
|
+
else:
|
|
117
|
+
file_list = [str(f) for f in input_data]
|
|
118
|
+
bsc_files = [f for f in file_list if fnmatch(f, att_id)]
|
|
119
|
+
depol_files = [f for f in file_list if fnmatch(f, vol_id)]
|
|
120
|
+
|
|
98
121
|
bsc_files.sort()
|
|
99
122
|
depol_files.sort()
|
|
100
123
|
if not bsc_files:
|
|
101
|
-
|
|
124
|
+
msg = "No pollyxt bsc files found"
|
|
125
|
+
raise RuntimeError(msg)
|
|
102
126
|
if len(bsc_files) != len(depol_files):
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
127
|
+
msg = "Inconsistent number of pollyxt bsc / depol files"
|
|
128
|
+
raise InconsistentDataError(msg)
|
|
129
|
+
bsc_files, depol_files = _fetch_files_with_same_range(bsc_files, depol_files)
|
|
130
|
+
if not bsc_files:
|
|
131
|
+
msg = "No pollyxt files with same range found"
|
|
132
|
+
raise InconsistentDataError(msg)
|
|
133
|
+
self._fetch_attributes(bsc_files[0])
|
|
134
|
+
with netCDF4.Dataset(bsc_files[0], "r") as nc:
|
|
135
|
+
self.data["range"] = nc.variables["height"][:]
|
|
136
|
+
calibration_factors: npt.NDArray = np.array([])
|
|
110
137
|
beta_channel = self._get_valid_beta_channel(bsc_files)
|
|
111
138
|
bsc_key = f"attenuated_backscatter_{beta_channel}nm"
|
|
112
|
-
for bsc_file, depol_file in zip(bsc_files, depol_files):
|
|
139
|
+
for bsc_file, depol_file in zip(bsc_files, depol_files, strict=True):
|
|
113
140
|
with (
|
|
114
141
|
netCDF4.Dataset(bsc_file, "r") as nc_bsc,
|
|
115
142
|
netCDF4.Dataset(depol_file, "r") as nc_depol,
|
|
@@ -117,19 +144,31 @@ class PollyXt(Ceilometer):
|
|
|
117
144
|
epoch = utils.get_epoch(nc_bsc["time"].unit)
|
|
118
145
|
try:
|
|
119
146
|
time = np.array(
|
|
120
|
-
_read_array_from_file_pair(nc_bsc, nc_depol, "time")
|
|
147
|
+
_read_array_from_file_pair(nc_bsc, nc_depol, "time"),
|
|
121
148
|
)
|
|
122
149
|
except AssertionError as err:
|
|
123
150
|
logging.warning(
|
|
124
|
-
|
|
151
|
+
"Ignoring files '%s' and '%s': %s",
|
|
152
|
+
bsc_file,
|
|
153
|
+
depol_file,
|
|
154
|
+
err,
|
|
125
155
|
)
|
|
126
156
|
continue
|
|
127
157
|
beta_raw = nc_bsc.variables[bsc_key][:]
|
|
128
158
|
depol_raw = nc_depol.variables["volume_depolarization_ratio_532nm"][:]
|
|
129
|
-
|
|
159
|
+
try:
|
|
160
|
+
snr = nc_bsc.variables[f"SNR_{beta_channel}nm"][:]
|
|
161
|
+
except KeyError:
|
|
162
|
+
logging.warning(
|
|
163
|
+
"Ignoring files '%s' and '%s'",
|
|
164
|
+
bsc_file,
|
|
165
|
+
depol_file,
|
|
166
|
+
)
|
|
167
|
+
continue
|
|
130
168
|
for array, key in zip(
|
|
131
169
|
[beta_raw, depol_raw, time, snr],
|
|
132
170
|
["beta_raw", "depolarisation_raw", "time", "snr"],
|
|
171
|
+
strict=True,
|
|
133
172
|
):
|
|
134
173
|
self.data = utils.append_data(self.data, key, array)
|
|
135
174
|
calibration_factor = nc_bsc.variables[
|
|
@@ -137,11 +176,17 @@ class PollyXt(Ceilometer):
|
|
|
137
176
|
].Lidar_calibration_constant_used
|
|
138
177
|
calibration_factor = np.repeat(calibration_factor, len(time))
|
|
139
178
|
calibration_factors = np.concatenate(
|
|
140
|
-
[calibration_factors, calibration_factor]
|
|
179
|
+
[calibration_factors, calibration_factor],
|
|
141
180
|
)
|
|
142
181
|
self.data["calibration_factor"] = calibration_factors
|
|
143
182
|
return epoch
|
|
144
183
|
|
|
184
|
+
def screen_completely_masked_profiles(self) -> None:
|
|
185
|
+
valid_ind = ~np.all(np.ma.getmaskarray(self.data["beta_raw"]), axis=1)
|
|
186
|
+
for key, item in self.data.items():
|
|
187
|
+
if isinstance(item, np.ndarray) and item.shape[0] == len(valid_ind):
|
|
188
|
+
self.data[key] = item[valid_ind]
|
|
189
|
+
|
|
145
190
|
def _get_valid_beta_channel(self, files: list) -> str:
|
|
146
191
|
polly_channels = ("1064", "532", "355")
|
|
147
192
|
for channel in polly_channels:
|
|
@@ -151,35 +196,70 @@ class PollyXt(Ceilometer):
|
|
|
151
196
|
if not _only_zeros_or_masked(beta):
|
|
152
197
|
if channel != polly_channels[0]:
|
|
153
198
|
logging.warning(
|
|
154
|
-
|
|
199
|
+
"Using %s nm pollyXT channel for backscatter",
|
|
200
|
+
channel,
|
|
155
201
|
)
|
|
156
|
-
self.instrument
|
|
202
|
+
if self.instrument is None:
|
|
203
|
+
msg = "No instrument defined"
|
|
204
|
+
raise RuntimeError(msg)
|
|
205
|
+
self.instrument.wavelength = float(channel)
|
|
157
206
|
return channel
|
|
158
|
-
|
|
207
|
+
msg = "No functional pollyXT backscatter channels found"
|
|
208
|
+
raise ValidTimeStampError(msg)
|
|
209
|
+
|
|
210
|
+
def _fetch_attributes(self, file: str) -> None:
|
|
211
|
+
with netCDF4.Dataset(file, "r") as nc:
|
|
212
|
+
if hasattr(nc, "source"):
|
|
213
|
+
self.serial_number = nc.source.lower()
|
|
214
|
+
|
|
215
|
+
|
|
216
|
+
def _fetch_files_with_same_range(
|
|
217
|
+
bsc_files: list[str], depol_files: list[str]
|
|
218
|
+
) -> tuple[list[str], list[str]]:
|
|
219
|
+
def get_sum(file: str) -> float:
|
|
220
|
+
with netCDF4.Dataset(file, "r") as nc:
|
|
221
|
+
return np.sum(np.round(nc.variables["height"][:]))
|
|
222
|
+
|
|
223
|
+
bsc_sums = [get_sum(f) for f in bsc_files]
|
|
224
|
+
depol_sums = [get_sum(f) for f in depol_files]
|
|
225
|
+
all_sums = bsc_sums + depol_sums
|
|
159
226
|
|
|
227
|
+
filtered_sums = [item for item in all_sums if item is not ma.masked]
|
|
228
|
+
if not filtered_sums:
|
|
229
|
+
return [], []
|
|
160
230
|
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
231
|
+
most_common_sum = Counter(filtered_sums).most_common(1)[0][0]
|
|
232
|
+
valid_indices = [
|
|
233
|
+
i
|
|
234
|
+
for i, (bs, ds) in enumerate(zip(bsc_sums, depol_sums, strict=False))
|
|
235
|
+
if bs == most_common_sum and ds == most_common_sum
|
|
236
|
+
]
|
|
237
|
+
if len(valid_indices) != len(bsc_files):
|
|
238
|
+
n_ignored = len(bsc_files) - len(valid_indices)
|
|
239
|
+
msg = f"Ignoring {n_ignored} file(s) with different range"
|
|
240
|
+
logging.warning(msg)
|
|
241
|
+
return (
|
|
242
|
+
[bsc_files[i] for i in valid_indices],
|
|
243
|
+
[depol_files[i] for i in valid_indices],
|
|
244
|
+
)
|
|
170
245
|
|
|
171
246
|
|
|
172
247
|
def _read_array_from_file_pair(
|
|
173
|
-
nc_file1: netCDF4.Dataset,
|
|
174
|
-
|
|
248
|
+
nc_file1: netCDF4.Dataset,
|
|
249
|
+
nc_file2: netCDF4.Dataset,
|
|
250
|
+
key: str,
|
|
251
|
+
) -> npt.NDArray:
|
|
175
252
|
array1 = nc_file1.variables[key][:]
|
|
176
253
|
array2 = nc_file2.variables[key][:]
|
|
177
|
-
|
|
254
|
+
assert_almost_equal(
|
|
255
|
+
array1, array2, err_msg=f"Inconsistent variable '{key}'", decimal=2
|
|
256
|
+
)
|
|
178
257
|
return array1
|
|
179
258
|
|
|
180
259
|
|
|
181
260
|
def _only_zeros_or_masked(data: ma.MaskedArray) -> bool:
|
|
182
|
-
|
|
261
|
+
mask = ma.getmaskarray(data)
|
|
262
|
+
return bool(ma.sum(data) == 0 or mask.all())
|
|
183
263
|
|
|
184
264
|
|
|
185
265
|
ATTRIBUTES = {
|
|
@@ -187,15 +267,19 @@ ATTRIBUTES = {
|
|
|
187
267
|
long_name="Lidar volume linear depolarisation ratio",
|
|
188
268
|
units="1",
|
|
189
269
|
comment="SNR-screened lidar volume linear depolarisation ratio at 532 nm.",
|
|
270
|
+
dimensions=("time", "range"),
|
|
190
271
|
),
|
|
191
272
|
"depolarisation_raw": MetaData(
|
|
192
273
|
long_name="Lidar volume linear depolarisation ratio",
|
|
193
274
|
units="1",
|
|
194
275
|
comment="Non-screened lidar volume linear depolarisation ratio at 532 nm.",
|
|
276
|
+
dimensions=("time", "range"),
|
|
195
277
|
),
|
|
196
278
|
"calibration_factor": MetaData(
|
|
197
279
|
long_name="Attenuated backscatter calibration factor",
|
|
198
280
|
units="1",
|
|
199
281
|
comment="Calibration factor applied.",
|
|
282
|
+
dimensions=("time",),
|
|
200
283
|
),
|
|
284
|
+
"zenith_angle": COMMON_ATTRIBUTES["zenith_angle"]._replace(dimensions=None),
|
|
201
285
|
}
|