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.
Files changed (116) hide show
  1. cloudnetpy/categorize/__init__.py +1 -2
  2. cloudnetpy/categorize/atmos_utils.py +297 -67
  3. cloudnetpy/categorize/attenuation.py +31 -0
  4. cloudnetpy/categorize/attenuations/__init__.py +37 -0
  5. cloudnetpy/categorize/attenuations/gas_attenuation.py +30 -0
  6. cloudnetpy/categorize/attenuations/liquid_attenuation.py +84 -0
  7. cloudnetpy/categorize/attenuations/melting_attenuation.py +78 -0
  8. cloudnetpy/categorize/attenuations/rain_attenuation.py +84 -0
  9. cloudnetpy/categorize/categorize.py +332 -156
  10. cloudnetpy/categorize/classify.py +127 -125
  11. cloudnetpy/categorize/containers.py +107 -76
  12. cloudnetpy/categorize/disdrometer.py +40 -0
  13. cloudnetpy/categorize/droplet.py +23 -21
  14. cloudnetpy/categorize/falling.py +53 -24
  15. cloudnetpy/categorize/freezing.py +25 -12
  16. cloudnetpy/categorize/insects.py +35 -23
  17. cloudnetpy/categorize/itu.py +243 -0
  18. cloudnetpy/categorize/lidar.py +36 -41
  19. cloudnetpy/categorize/melting.py +34 -26
  20. cloudnetpy/categorize/model.py +84 -37
  21. cloudnetpy/categorize/mwr.py +18 -14
  22. cloudnetpy/categorize/radar.py +215 -102
  23. cloudnetpy/cli.py +578 -0
  24. cloudnetpy/cloudnetarray.py +43 -89
  25. cloudnetpy/concat_lib.py +218 -78
  26. cloudnetpy/constants.py +28 -10
  27. cloudnetpy/datasource.py +61 -86
  28. cloudnetpy/exceptions.py +49 -20
  29. cloudnetpy/instruments/__init__.py +5 -0
  30. cloudnetpy/instruments/basta.py +29 -12
  31. cloudnetpy/instruments/bowtie.py +135 -0
  32. cloudnetpy/instruments/ceilo.py +138 -115
  33. cloudnetpy/instruments/ceilometer.py +164 -80
  34. cloudnetpy/instruments/cl61d.py +21 -5
  35. cloudnetpy/instruments/cloudnet_instrument.py +74 -36
  36. cloudnetpy/instruments/copernicus.py +108 -30
  37. cloudnetpy/instruments/da10.py +54 -0
  38. cloudnetpy/instruments/disdrometer/common.py +126 -223
  39. cloudnetpy/instruments/disdrometer/parsivel.py +453 -94
  40. cloudnetpy/instruments/disdrometer/thies.py +254 -87
  41. cloudnetpy/instruments/fd12p.py +201 -0
  42. cloudnetpy/instruments/galileo.py +65 -23
  43. cloudnetpy/instruments/hatpro.py +123 -49
  44. cloudnetpy/instruments/instruments.py +113 -1
  45. cloudnetpy/instruments/lufft.py +39 -17
  46. cloudnetpy/instruments/mira.py +268 -61
  47. cloudnetpy/instruments/mrr.py +187 -0
  48. cloudnetpy/instruments/nc_lidar.py +19 -8
  49. cloudnetpy/instruments/nc_radar.py +109 -55
  50. cloudnetpy/instruments/pollyxt.py +135 -51
  51. cloudnetpy/instruments/radiometrics.py +313 -59
  52. cloudnetpy/instruments/rain_e_h3.py +171 -0
  53. cloudnetpy/instruments/rpg.py +321 -189
  54. cloudnetpy/instruments/rpg_reader.py +74 -40
  55. cloudnetpy/instruments/toa5.py +49 -0
  56. cloudnetpy/instruments/vaisala.py +95 -343
  57. cloudnetpy/instruments/weather_station.py +774 -105
  58. cloudnetpy/metadata.py +90 -19
  59. cloudnetpy/model_evaluation/file_handler.py +55 -52
  60. cloudnetpy/model_evaluation/metadata.py +46 -20
  61. cloudnetpy/model_evaluation/model_metadata.py +1 -1
  62. cloudnetpy/model_evaluation/plotting/plot_tools.py +32 -37
  63. cloudnetpy/model_evaluation/plotting/plotting.py +327 -117
  64. cloudnetpy/model_evaluation/products/advance_methods.py +92 -83
  65. cloudnetpy/model_evaluation/products/grid_methods.py +88 -63
  66. cloudnetpy/model_evaluation/products/model_products.py +43 -35
  67. cloudnetpy/model_evaluation/products/observation_products.py +41 -35
  68. cloudnetpy/model_evaluation/products/product_resampling.py +17 -7
  69. cloudnetpy/model_evaluation/products/tools.py +29 -20
  70. cloudnetpy/model_evaluation/statistics/statistical_methods.py +30 -20
  71. cloudnetpy/model_evaluation/tests/e2e/conftest.py +3 -3
  72. cloudnetpy/model_evaluation/tests/e2e/process_cf/main.py +9 -5
  73. cloudnetpy/model_evaluation/tests/e2e/process_cf/tests.py +15 -14
  74. cloudnetpy/model_evaluation/tests/e2e/process_iwc/main.py +9 -5
  75. cloudnetpy/model_evaluation/tests/e2e/process_iwc/tests.py +15 -14
  76. cloudnetpy/model_evaluation/tests/e2e/process_lwc/main.py +9 -5
  77. cloudnetpy/model_evaluation/tests/e2e/process_lwc/tests.py +15 -14
  78. cloudnetpy/model_evaluation/tests/unit/conftest.py +42 -41
  79. cloudnetpy/model_evaluation/tests/unit/test_advance_methods.py +41 -48
  80. cloudnetpy/model_evaluation/tests/unit/test_grid_methods.py +216 -194
  81. cloudnetpy/model_evaluation/tests/unit/test_model_products.py +23 -21
  82. cloudnetpy/model_evaluation/tests/unit/test_observation_products.py +37 -38
  83. cloudnetpy/model_evaluation/tests/unit/test_plot_tools.py +43 -40
  84. cloudnetpy/model_evaluation/tests/unit/test_plotting.py +30 -36
  85. cloudnetpy/model_evaluation/tests/unit/test_statistical_methods.py +68 -31
  86. cloudnetpy/model_evaluation/tests/unit/test_tools.py +33 -26
  87. cloudnetpy/model_evaluation/utils.py +2 -1
  88. cloudnetpy/output.py +170 -111
  89. cloudnetpy/plotting/__init__.py +2 -1
  90. cloudnetpy/plotting/plot_meta.py +562 -822
  91. cloudnetpy/plotting/plotting.py +1142 -704
  92. cloudnetpy/products/__init__.py +1 -0
  93. cloudnetpy/products/classification.py +370 -88
  94. cloudnetpy/products/der.py +85 -55
  95. cloudnetpy/products/drizzle.py +77 -34
  96. cloudnetpy/products/drizzle_error.py +15 -11
  97. cloudnetpy/products/drizzle_tools.py +79 -59
  98. cloudnetpy/products/epsilon.py +211 -0
  99. cloudnetpy/products/ier.py +27 -50
  100. cloudnetpy/products/iwc.py +55 -48
  101. cloudnetpy/products/lwc.py +96 -70
  102. cloudnetpy/products/mwr_tools.py +186 -0
  103. cloudnetpy/products/product_tools.py +170 -128
  104. cloudnetpy/utils.py +455 -240
  105. cloudnetpy/version.py +2 -2
  106. {cloudnetpy-1.49.9.dist-info → cloudnetpy-1.87.3.dist-info}/METADATA +44 -40
  107. cloudnetpy-1.87.3.dist-info/RECORD +127 -0
  108. {cloudnetpy-1.49.9.dist-info → cloudnetpy-1.87.3.dist-info}/WHEEL +1 -1
  109. cloudnetpy-1.87.3.dist-info/entry_points.txt +2 -0
  110. docs/source/conf.py +2 -2
  111. cloudnetpy/categorize/atmos.py +0 -361
  112. cloudnetpy/products/mwr_multi.py +0 -68
  113. cloudnetpy/products/mwr_single.py +0 -75
  114. cloudnetpy-1.49.9.dist-info/RECORD +0 -112
  115. {cloudnetpy-1.49.9.dist-info → cloudnetpy-1.87.3.dist-info/licenses}/LICENSE +0 -0
  116. {cloudnetpy-1.49.9.dist-info → cloudnetpy-1.87.3.dist-info}/top_level.txt +0 -0
@@ -1,193 +1,66 @@
1
1
  """Module for reading / converting disdrometer data."""
2
- import logging
2
+
3
+ from typing import Literal
3
4
 
4
5
  import numpy as np
5
- from numpy import ma
6
+ import numpy.typing as npt
6
7
 
7
- from cloudnetpy import utils
8
8
  from cloudnetpy.cloudnetarray import CloudnetArray
9
- from cloudnetpy.exceptions import ValidTimeStampError
10
9
  from cloudnetpy.instruments.cloudnet_instrument import CloudnetInstrument
11
- from cloudnetpy.instruments.vaisala import values_to_dict
12
10
  from cloudnetpy.metadata import MetaData
13
11
 
14
- PARSIVEL = "OTT Parsivel-2"
15
- THIES = "Thies-LNM"
16
-
17
12
 
18
13
  class Disdrometer(CloudnetInstrument):
19
- def __init__(self, filename: str, site_meta: dict, source: str):
20
- super().__init__()
21
- self.filename = filename
22
- self.site_meta = site_meta
23
- self.source = source
24
- self.date: list[str] = []
25
- self.sensor_id = None
26
- self.n_diameter: int = 0
27
- self.n_velocity: int = 0
28
- self._file_data = self._read_file()
29
-
30
- def convert_units(self):
31
- mm_to_m = 1e3
32
- mmh_to_ms = 3600 * mm_to_m
33
- c_to_k = 273.15
34
- self._convert_data(("rainfall_rate_1min_total",), mmh_to_ms)
35
- self._convert_data(("rainfall_rate",), mmh_to_ms)
36
- self._convert_data(("rainfall_rate_1min_solid",), mmh_to_ms)
37
- self._convert_data(("diameter", "diameter_spread", "diameter_bnds"), mm_to_m)
38
- self._convert_data(("V_sensor_supply",), 10)
39
- self._convert_data(("I_mean_laser",), 100)
40
- self._convert_data(("T_sensor",), c_to_k, method="add")
41
- self._convert_data(("T_interior",), c_to_k, method="add")
42
- self._convert_data(("T_ambient",), c_to_k, method="add")
43
- self._convert_data(("T_laser_driver",), c_to_k, method="add")
44
-
45
- def add_meta(self):
14
+ def add_meta(self) -> None:
46
15
  valid_keys = ("latitude", "longitude", "altitude")
47
16
  for key, value in self.site_meta.items():
48
- key = key.lower()
49
- if key in valid_keys:
50
- self.data[key] = CloudnetArray(float(value), key)
51
-
52
- def validate_date(self, expected_date: str) -> None:
53
- valid_ind = []
54
- for ind, row in enumerate(self._file_data["scalars"]):
55
- if self.source == PARSIVEL:
56
- raise NotImplementedError
57
- date = _format_thies_date(row[3])
58
- if date == expected_date:
59
- valid_ind.append(ind)
60
- if not valid_ind:
61
- raise ValidTimeStampError
62
- for key, value in self._file_data.items():
63
- if value:
64
- self._file_data[key] = [self._file_data[key][ind] for ind in valid_ind]
65
- self.date = expected_date.split("-")
17
+ name = key.lower()
18
+ if name in valid_keys:
19
+ self.data[name] = CloudnetArray(float(value), name)
66
20
 
67
- def sort_time(self) -> None:
68
- time = self.data["time"][:]
69
- ind = time.argsort()
70
- for _, data in self.data.items():
71
- if data.data.shape[0] == len(time):
72
- data.data[:] = data.data[ind]
73
-
74
- def _read_file(self) -> dict:
75
- data: dict = {"scalars": [], "vectors": [], "spectra": []}
76
- with open(self.filename, encoding="utf8", errors="ignore") as file:
77
- for row in file:
78
- if row == "\n":
79
- continue
80
- if self.source == PARSIVEL:
81
- values = row.split(";")
82
- if "\n" in values:
83
- values.remove("\n")
84
- if len(values) != 1106:
85
- continue
86
- data["scalars"].append(values[:18])
87
- data["vectors"].append(values[18 : 18 + 64])
88
- data["spectra"].append(values[18 + 64 :])
89
- else:
90
- values = row.split(";")
91
- data["scalars"].append(values[:79])
92
- data["spectra"].append(values[79:-2])
93
- if len(data["scalars"]) == 0:
94
- raise ValueError
95
- return data
96
-
97
- def _append_data(self, column_and_key: list) -> None:
98
- indices, keys = zip(*column_and_key)
99
- data = self._parse_useful_data(indices)
100
- data_dict = values_to_dict(keys, data)
21
+ def _convert_data(
22
+ self,
23
+ keys: tuple[str, ...],
24
+ value: float,
25
+ method: Literal["divide", "add"] = "divide",
26
+ ) -> None:
101
27
  for key in keys:
102
- if key.startswith("_"):
28
+ if key not in self.data:
103
29
  continue
104
- invalid_value = -9999.0
105
- float_array = ma.array([])
106
- for value_str in data_dict[key]:
107
- try:
108
- float_array = ma.append(float_array, float(value_str))
109
- except ValueError:
110
- logging.warning(
111
- f"Invalid character: {value_str}, masking a data point"
112
- )
113
- float_array = ma.append(float_array, invalid_value)
114
- float_array[float_array == invalid_value] = ma.masked
115
- if key in (
116
- "rainfall_rate",
117
- "radar_reflectivity",
118
- "T_sensor",
119
- "I_heating",
120
- "V_power_supply",
121
- "T_interior",
122
- "T_ambient",
123
- "T_laser_driver",
124
- ):
125
- data_type = "f4"
30
+ variable = self.data[key]
31
+ if method == "divide":
32
+ variable.data = variable.data.astype("f4") / value
33
+ variable.data_type = "f4"
34
+ elif method == "add":
35
+ variable.data = variable.data.astype("f4") + value
36
+ variable.data_type = "f4"
126
37
  else:
127
- data_type = "i4"
128
- self.data[key] = CloudnetArray(float_array, key, data_type=data_type)
129
- self.data["time"] = self._convert_time(data_dict)
130
- if "_sensor_id" in data_dict:
131
- self.sensor_id = data_dict["_sensor_id"][0]
132
-
133
- def _parse_useful_data(self, indices: list) -> list:
134
- data = []
135
- for row in self._file_data["scalars"]:
136
- useful_data = [row[ind] for ind in indices]
137
- data.append(useful_data)
138
- return data
139
-
140
- def _convert_time(self, data: dict) -> CloudnetArray:
141
- seconds = []
142
- for timestamp in data["_time"]:
143
- if self.source == PARSIVEL:
144
- raise NotImplementedError
145
- hour, minute, sec = timestamp.split(":")
146
- seconds.append(int(hour) * 3600 + int(minute) * 60 + int(sec))
147
- return CloudnetArray(utils.seconds2hours(np.array(seconds)), "time")
38
+ raise ValueError
148
39
 
149
- def _convert_data(self, keys: tuple, value: float, method: str = "divide"):
150
- for key in keys:
151
- if key in self.data:
152
- if method == "divide":
153
- self.data[key].data /= value
154
- elif method == "add":
155
- self.data[key].data += value
156
- else:
157
- raise ValueError
158
-
159
- def _append_spectra(self):
160
- array = ma.masked_all(
161
- (len(self._file_data["scalars"]), self.n_diameter, self.n_velocity)
162
- )
163
- for time_ind, row in enumerate(self._file_data["spectra"]):
164
- values = _parse_int(row)
165
- array[time_ind, :, :] = np.reshape(
166
- values, (self.n_diameter, self.n_velocity)
167
- )
168
- self.data["data_raw"] = CloudnetArray(
169
- array, "data_raw", dimensions=("time", "diameter", "velocity")
170
- )
171
-
172
- @classmethod
173
40
  def store_vectors(
174
- cls, data, n_values: list, spreads: list, name: str, start: float = 0.0
175
- ):
176
- mid, bounds, spread = cls._create_vectors(n_values, spreads, start)
177
- data[name] = CloudnetArray(mid, name, dimensions=(name,))
41
+ self,
42
+ n_values: list,
43
+ spreads: list,
44
+ name: str,
45
+ start: float = 0.0,
46
+ ) -> None:
47
+ mid, bounds, spread = self._create_vectors(n_values, spreads, start)
48
+ self.data[name] = CloudnetArray(mid, name, dimensions=(name,))
178
49
  key = f"{name}_spread"
179
- data[key] = CloudnetArray(spread, key, dimensions=(name,))
50
+ self.data[key] = CloudnetArray(spread, key, dimensions=(name,))
180
51
  key = f"{name}_bnds"
181
- data[key] = CloudnetArray(bounds, key, dimensions=(name, "nv"))
52
+ self.data[key] = CloudnetArray(bounds, key, dimensions=(name, "nv"))
182
53
 
183
- @staticmethod
184
54
  def _create_vectors(
185
- n_values: list[int], spreads: list[float], start: float
55
+ self,
56
+ n_values: list[int],
57
+ spreads: list[float],
58
+ start: float,
186
59
  ) -> tuple:
187
- mid_value: np.ndarray = np.array([])
188
- lower_limit: np.ndarray = np.array([])
189
- upper_limit: np.ndarray = np.array([])
190
- for spread, n in zip(spreads, n_values):
60
+ mid_value: npt.NDArray = np.array([])
61
+ lower_limit: npt.NDArray = np.array([])
62
+ upper_limit: npt.NDArray = np.array([])
63
+ for spread, n in zip(spreads, n_values, strict=True):
191
64
  lower = np.linspace(start, start + (n - 1) * spread, n)
192
65
  upper = lower + spread
193
66
  lower_limit = np.append(lower_limit, lower)
@@ -199,219 +72,249 @@ class Disdrometer(CloudnetInstrument):
199
72
  return mid_value, bounds, spread
200
73
 
201
74
 
202
- def _format_thies_date(date: str):
203
- day, month, year = date.split(".")
204
- year = f"20{year}"
205
- return f"{year}-{month.zfill(2)}-{day.zfill(2)}"
206
-
207
-
208
- def _parse_int(row: np.ndarray) -> np.ndarray:
209
- values = ma.masked_all((len(row),))
210
- for ind, value in enumerate(row):
211
- try:
212
- value = int(value)
213
- if value != 0:
214
- values[ind] = value
215
- except ValueError:
216
- pass
217
- return values
218
-
219
-
220
75
  ATTRIBUTES = {
221
76
  "velocity": MetaData(
222
77
  long_name="Center fall velocity of precipitation particles",
223
78
  units="m s-1",
224
79
  comment="Predefined velocity classes.",
80
+ dimensions=("velocity",),
225
81
  ),
226
82
  "velocity_spread": MetaData(
227
83
  long_name="Width of velocity interval",
228
84
  units="m s-1",
229
85
  comment="Bin size of each velocity interval.",
86
+ dimensions=("velocity",),
230
87
  ),
231
88
  "velocity_bnds": MetaData(
232
89
  long_name="Velocity bounds",
233
90
  units="m s-1",
234
91
  comment="Upper and lower bounds of velocity interval.",
92
+ dimensions=("velocity", "nv"),
235
93
  ),
236
94
  "diameter": MetaData(
237
95
  long_name="Center diameter of precipitation particles",
238
96
  units="m",
239
97
  comment="Predefined diameter classes.",
98
+ dimensions=("diameter",),
240
99
  ),
241
100
  "diameter_spread": MetaData(
242
101
  long_name="Width of diameter interval",
243
102
  units="m",
244
103
  comment="Bin size of each diameter interval.",
104
+ dimensions=("diameter",),
245
105
  ),
246
106
  "diameter_bnds": MetaData(
247
107
  long_name="Diameter bounds",
248
108
  units="m",
249
109
  comment="Upper and lower bounds of diameter interval.",
110
+ dimensions=("diameter", "nv"),
250
111
  ),
251
112
  "rainfall_rate_1min_total": MetaData(
252
- long_name="Total precipitation rate",
253
- units="m s-1",
113
+ long_name="Total precipitation rate", units="m s-1", dimensions=("time",)
254
114
  ),
255
115
  "rainfall_rate": MetaData(
256
- long_name="Rainfall rate", units="m s-1", standard_name="rainfall_rate"
116
+ long_name="Rainfall rate",
117
+ units="m s-1",
118
+ standard_name="rainfall_rate",
119
+ dimensions=("time",),
257
120
  ),
258
121
  "rainfall_rate_1min_solid": MetaData(
259
- long_name="Solid precipitation rate",
260
- units="m s-1",
122
+ long_name="Solid precipitation rate", units="m s-1", dimensions=("time",)
261
123
  ),
262
124
  "snowfall_rate": MetaData(
263
125
  long_name="Snowfall rate",
264
126
  units="m s-1",
265
127
  comment="Snow depth intensity (volume equivalent)",
128
+ dimensions=("time",),
266
129
  ),
267
- "synop_WaWa": MetaData(long_name="Synop code WaWa", units="1"),
268
- "synop_WW": MetaData(long_name="Synop code WW", units="1"),
130
+ "synop_WaWa": MetaData(
131
+ long_name="Synop code WaWa", units="1", dimensions=("time",)
132
+ ),
133
+ "synop_WW": MetaData(long_name="Synop code WW", units="1", dimensions=("time",)),
269
134
  "radar_reflectivity": MetaData(
270
135
  long_name="Equivalent radar reflectivity factor",
271
136
  units="dBZ",
272
137
  standard_name="equivalent_reflectivity_factor",
138
+ dimensions=("time",),
273
139
  ),
274
140
  "visibility": MetaData(
275
- long_name="Visibility range in precipitation after MOR",
141
+ long_name="Meteorological optical range (MOR) visibility",
276
142
  units="m",
277
143
  standard_name="visibility_in_air",
144
+ comment="Visibility estimation by the disdrometer is valid\n"
145
+ "only during precipitation events.",
146
+ dimensions=("time",),
147
+ ),
148
+ "interval": MetaData(
149
+ long_name="Length of measurement interval", units="s", dimensions=("time",)
150
+ ),
151
+ "sig_laser": MetaData(
152
+ long_name="Signal amplitude of the laser strip", units="1", dimensions=("time",)
278
153
  ),
279
- "interval": MetaData(long_name="Length of measurement interval", units="s"),
280
- "sig_laser": MetaData(long_name="Signal amplitude of the laser strip", units="1"),
281
154
  "n_particles": MetaData(
282
- long_name="Number of particles in time interval", units="1"
155
+ long_name="Number of particles in time interval",
156
+ units="1",
157
+ dimensions=("time",),
283
158
  ),
284
159
  "T_sensor": MetaData(
285
- long_name="Temperature in the sensor housing",
286
- units="K",
287
- ),
288
- "I_heating": MetaData(
289
- long_name="Heating current",
290
- units="A",
160
+ long_name="Temperature in the sensor housing", units="K", dimensions=("time",)
291
161
  ),
162
+ "I_heating": MetaData(long_name="Heating current", units="A", dimensions=("time",)),
292
163
  "V_sensor_supply": MetaData(
293
- long_name="Sensor supply voltage",
294
- units="V",
164
+ long_name="Sensor supply voltage", units="V", dimensions=("time",)
295
165
  ),
296
166
  "V_power_supply": MetaData(
297
- long_name="Power supply voltage",
298
- units="V",
167
+ long_name="Power supply voltage", units="V", dimensions=("time",)
299
168
  ),
300
169
  "state_sensor": MetaData(
301
170
  long_name="State of the sensor",
302
171
  comment="0 = OK, 1 = Dirty, 2 = No measurement possible.",
303
172
  units="1",
173
+ dimensions=("time",),
304
174
  ),
305
- "error_code": MetaData(long_name="Error code", units="1"),
175
+ "error_code": MetaData(long_name="Error code", units="1", dimensions=("time",)),
306
176
  "number_concentration": MetaData(
307
177
  long_name="Number of particles per diameter class",
308
- comment="Unit is actually logarithmic log10(m-3 mm-1).",
309
178
  units="m-3 mm-1",
179
+ dimensions=("time", "diameter"),
310
180
  ),
311
181
  "fall_velocity": MetaData(
312
182
  long_name="Average velocity of each diameter class",
313
183
  units="m s-1",
184
+ dimensions=("time", "diameter"),
314
185
  ),
315
186
  "data_raw": MetaData(
316
187
  long_name="Raw data as a function of particle diameter and velocity",
317
188
  units="1",
189
+ dimensions=("time", "diameter", "velocity"),
318
190
  ),
319
191
  "kinetic_energy": MetaData(
320
- long_name="Kinetic energy of the hydrometeors", units="J m-2 h-1"
192
+ long_name="Kinetic energy of the hydrometeors",
193
+ units="J m-2 h-1",
194
+ dimensions=("time",),
321
195
  ),
322
196
  # Thies-specific:
323
- "T_ambient": MetaData(long_name="Ambient temperature", units="K"),
324
- "T_interior": MetaData(long_name="Interior temperature", units="K"),
197
+ "T_ambient": MetaData(
198
+ long_name="Ambient temperature", units="K", dimensions=("time",)
199
+ ),
200
+ "T_interior": MetaData(
201
+ long_name="Interior temperature", units="K", dimensions=("time",)
202
+ ),
325
203
  "status_T_laser_analogue": MetaData(
326
204
  long_name="Status of laser temperature (analogue)",
327
205
  comment="0 = OK , 1 = Error",
328
206
  units="1",
207
+ dimensions=("time",),
329
208
  ),
330
209
  "status_T_laser_digital": MetaData(
331
210
  long_name="Status of laser temperature (digital)",
332
211
  comment="0 = OK , 1 = Error",
333
212
  units="1",
213
+ dimensions=("time",),
334
214
  ),
335
215
  "status_I_laser_analogue": MetaData(
336
216
  long_name="Status of laser current (analogue)",
337
217
  comment="0 = OK , 1 = Error",
338
218
  units="1",
219
+ dimensions=("time",),
339
220
  ),
340
221
  "status_I_laser_digital": MetaData(
341
222
  long_name="Status of laser current (digital)",
342
223
  comment="0 = OK , 1 = Error",
343
224
  units="1",
225
+ dimensions=("time",),
344
226
  ),
345
227
  "status_sensor_supply": MetaData(
346
228
  long_name="Status of sensor supply",
347
229
  comment="0 = OK , 1 = Error",
348
230
  units="1",
231
+ dimensions=("time",),
349
232
  ),
350
233
  "status_laser_heating": MetaData(
351
234
  long_name="Status of laser heating",
352
235
  comment="0 = OK , 1 = Error",
353
236
  units="1",
237
+ dimensions=("time",),
354
238
  ),
355
239
  "status_receiver_heating": MetaData(
356
240
  long_name="Status of receiver heating",
357
241
  comment="0 = OK , 1 = Error",
358
242
  units="1",
243
+ dimensions=("time",),
359
244
  ),
360
245
  "status_temperature_sensor": MetaData(
361
246
  long_name="Status of temperature sensor",
362
247
  comment="0 = OK , 1 = Error",
363
248
  units="1",
249
+ dimensions=("time",),
364
250
  ),
365
251
  "status_heating_supply": MetaData(
366
252
  long_name="Status of heating supply",
367
253
  comment="0 = OK , 1 = Error",
368
254
  units="1",
255
+ dimensions=("time",),
369
256
  ),
370
257
  "status_heating_housing": MetaData(
371
258
  long_name="Status of heating housing",
372
259
  comment="0 = OK , 1 = Error",
373
260
  units="1",
261
+ dimensions=("time",),
374
262
  ),
375
263
  "status_heating_heads": MetaData(
376
264
  long_name="Status of heating heads",
377
265
  comment="0 = OK , 1 = Error",
378
266
  units="1",
267
+ dimensions=("time",),
379
268
  ),
380
269
  "status_heating_carriers": MetaData(
381
270
  long_name="Status of heating carriers",
382
271
  comment="0 = OK , 1 = Error",
383
272
  units="1",
273
+ dimensions=("time",),
384
274
  ),
385
275
  "status_laser_power": MetaData(
386
276
  long_name="Status of laser power",
387
277
  comment="0 = OK , 1 = Error",
388
278
  units="1",
279
+ dimensions=("time",),
389
280
  ),
390
281
  "status_laser": MetaData(
391
- long_name="Status of laser", comment="0 = OK/on , 1 = Off", units="1"
282
+ long_name="Status of laser",
283
+ comment="0 = OK/on , 1 = Off",
284
+ units="1",
285
+ dimensions=("time",),
286
+ ),
287
+ "measurement_quality": MetaData(
288
+ long_name="Measurement quality", units="%", dimensions=("time",)
289
+ ),
290
+ "maximum_hail_diameter": MetaData(
291
+ long_name="Maximum hail diameter", units="mm", dimensions=("time",)
392
292
  ),
393
- "measurement_quality": MetaData(long_name="Measurement quality", units="%"),
394
- "maximum_hail_diameter": MetaData(long_name="Maximum hail diameter", units="mm"),
395
293
  "static_signal": MetaData(
396
- long_name="Static signal", comment="0 = OK, 1 = ERROR", units="1"
294
+ long_name="Static signal",
295
+ comment="0 = OK, 1 = ERROR",
296
+ units="1",
297
+ dimensions=("time",),
298
+ ),
299
+ "T_laser_driver": MetaData(
300
+ long_name="Temperature of laser driver", units="K", dimensions=("time",)
301
+ ),
302
+ "I_mean_laser": MetaData(
303
+ long_name="Mean value of laser current", units="mA", dimensions=("time",)
397
304
  ),
398
- "T_laser_driver": MetaData(long_name="Temperature of laser driver", units="K"),
399
- "I_mean_laser": MetaData(long_name="Mean value of laser current", units="mA"),
400
305
  "V_control": MetaData(
401
306
  long_name="Control voltage",
402
307
  units="mV",
403
308
  comment="Reference value: 4010+-5",
309
+ dimensions=("time",),
404
310
  ),
405
311
  "V_optical_output": MetaData(
406
- long_name="Voltage of optical control output",
407
- units="mV",
312
+ long_name="Voltage of optical control output", units="mV", dimensions=("time",)
408
313
  ),
409
314
  "I_heating_laser_head": MetaData(
410
- long_name="Laser head heating current",
411
- units="mA",
315
+ long_name="Laser head heating current", units="mA", dimensions=("time",)
412
316
  ),
413
317
  "I_heating_receiver_head": MetaData(
414
- long_name="Receiver head heating current",
415
- units="mA",
318
+ long_name="Receiver head heating current", units="mA", dimensions=("time",)
416
319
  ),
417
320
  }