cloudnetpy 1.61.3__py3-none-any.whl → 1.61.5__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.
@@ -1,4 +1,6 @@
1
1
  """Module that generates Cloudnet categorize file."""
2
+ import logging
3
+
2
4
  from cloudnetpy import output, utils
3
5
  from cloudnetpy.categorize import atmos, classify
4
6
  from cloudnetpy.categorize.disdrometer import Disdrometer
@@ -7,7 +9,7 @@ from cloudnetpy.categorize.model import Model
7
9
  from cloudnetpy.categorize.mwr import Mwr
8
10
  from cloudnetpy.categorize.radar import Radar
9
11
  from cloudnetpy.datasource import DataSource
10
- from cloudnetpy.exceptions import ValidTimeStampError
12
+ from cloudnetpy.exceptions import DisdrometerDataError, ValidTimeStampError
11
13
  from cloudnetpy.metadata import MetaData
12
14
 
13
15
 
@@ -61,7 +63,7 @@ def generate_categorize(
61
63
  def _interpolate_to_cloudnet_grid() -> list:
62
64
  wl_band = utils.get_wl_band(data["radar"].radar_frequency)
63
65
  data["mwr"].rebin_to_grid(time)
64
- if is_disdrometer:
66
+ if data["disdrometer"] is not None:
65
67
  data["disdrometer"].interpolate_to_grid(time)
66
68
  data["model"].interpolate_to_common_height(wl_band)
67
69
  model_gap_ind = data["model"].interpolate_to_grid(time, height)
@@ -94,7 +96,7 @@ def generate_categorize(
94
96
  def _prepare_output() -> dict:
95
97
  data["radar"].add_meta()
96
98
  data["model"].screen_sparse_fields()
97
- if is_disdrometer:
99
+ if data["disdrometer"] is not None:
98
100
  data["radar"].data.pop("rainfall_rate", None)
99
101
  data["disdrometer"].data.pop("n_particles", None)
100
102
  for key in ("category_bits", "insect_prob"):
@@ -111,7 +113,7 @@ def generate_categorize(
111
113
  **data["model"].data,
112
114
  **data["model"].data_sparse,
113
115
  **data["mwr"].data,
114
- **(data["disdrometer"].data if is_disdrometer else {}),
116
+ **(data["disdrometer"].data if data["disdrometer"] is not None else {}),
115
117
  }
116
118
 
117
119
  def _define_dense_grid() -> tuple:
@@ -123,17 +125,18 @@ def generate_categorize(
123
125
  obj.close()
124
126
 
125
127
  try:
126
- is_disdrometer = "disdrometer" in input_files
127
-
128
128
  data: dict = {
129
129
  "radar": Radar(input_files["radar"]),
130
130
  "lidar": Lidar(input_files["lidar"]),
131
131
  "mwr": Mwr(input_files["mwr"]),
132
132
  "lv0_files": input_files.get("lv0_files"),
133
- "disdrometer": Disdrometer(input_files["disdrometer"])
134
- if is_disdrometer
135
- else None,
133
+ "disdrometer": None,
136
134
  }
135
+ if "disdrometer" in input_files:
136
+ try:
137
+ data["disdrometer"] = Disdrometer(input_files["disdrometer"])
138
+ except DisdrometerDataError as err:
139
+ logging.warning("Unable to use disdrometer: %s", err)
137
140
  data["model"] = Model(input_files["model"], data["radar"].altitude)
138
141
  time, height = _define_dense_grid()
139
142
  valid_ind = _interpolate_to_cloudnet_grid()
@@ -7,6 +7,7 @@ from scipy.interpolate import interp1d
7
7
 
8
8
  from cloudnetpy.categorize.lidar import get_gap_ind
9
9
  from cloudnetpy.datasource import DataSource
10
+ from cloudnetpy.exceptions import DisdrometerDataError
10
11
 
11
12
 
12
13
  class Disdrometer(DataSource):
@@ -29,6 +30,9 @@ class Disdrometer(DataSource):
29
30
  def _init_rainfall_rate(self) -> None:
30
31
  keys = ("rainfall_rate", "n_particles")
31
32
  for key in keys:
33
+ if key not in self.dataset.variables:
34
+ msg = f"variable {key} is missing"
35
+ raise DisdrometerDataError(msg)
32
36
  self.append_data(self.dataset.variables[key][:], key)
33
37
 
34
38
  def _interpolate(self, y: ma.MaskedArray, x_new: np.ndarray) -> np.ndarray:
@@ -194,9 +194,13 @@ class Thies(Disdrometer):
194
194
 
195
195
  def _read_line(self, line: str, timestamp: datetime.datetime | None = None):
196
196
  raw_values = line.split(";")
197
- if len(raw_values) != 521:
197
+ # Support custom truncated format used in Leipzig LIM.
198
+ expected_columns = self.site_meta.get("truncate_columns", 521)
199
+ if len(raw_values) != expected_columns:
198
200
  return
199
201
  for i, key in TELEGRAM4:
202
+ if i >= expected_columns - 1:
203
+ break
200
204
  value: Any
201
205
  if key == "_date":
202
206
  value = _parse_date(raw_values[i])
@@ -227,11 +231,12 @@ class Thies(Disdrometer):
227
231
  else:
228
232
  value = int(raw_values[i])
229
233
  self.raw_data[key].append(value)
230
- self.raw_data["spectrum"].append(
231
- np.array(list(map(int, raw_values[79:-2])), dtype="i2").reshape(
232
- self.n_diameter, self.n_velocity
234
+ if expected_columns > 79:
235
+ self.raw_data["spectrum"].append(
236
+ np.array(list(map(int, raw_values[79:-2])), dtype="i2").reshape(
237
+ self.n_diameter, self.n_velocity
238
+ )
233
239
  )
234
- )
235
240
  if timestamp is not None:
236
241
  self.raw_data["time"].append(timestamp)
237
242
  else:
@@ -266,7 +271,9 @@ class Thies(Disdrometer):
266
271
 
267
272
  def _parse_date(date: str) -> datetime.date:
268
273
  day, month, year = map(int, date.split("."))
269
- return datetime.date(2000 + year, month, day)
274
+ if year < 100:
275
+ year += 2000
276
+ return datetime.date(year, month, day)
270
277
 
271
278
 
272
279
  def _parse_time(time: str) -> datetime.time:
cloudnetpy/version.py CHANGED
@@ -1,4 +1,4 @@
1
1
  MAJOR = 1
2
2
  MINOR = 61
3
- PATCH = 3
3
+ PATCH = 5
4
4
  __version__ = f"{MAJOR}.{MINOR}.{PATCH}"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: cloudnetpy
3
- Version: 1.61.3
3
+ Version: 1.61.5
4
4
  Summary: Python package for Cloudnet processing
5
5
  Author: Simo Tukiainen
6
6
  License: MIT License
@@ -8,14 +8,14 @@ cloudnetpy/metadata.py,sha256=v_VDo2vbdTxB0zIsfP69IcrwSKiRlLpsGdq6JPI4CoA,5306
8
8
  cloudnetpy/output.py,sha256=WoVTNuxni0DUr163vZ-_mDr1brXhY15XSlGMrq9Aoqw,14700
9
9
  cloudnetpy/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
10
10
  cloudnetpy/utils.py,sha256=0TlHm71YtSrKXBsRKctitnhQrvZPE-ulEVeAQW-oK58,27398
11
- cloudnetpy/version.py,sha256=j5-CDdAsDSNeVW2c3qchPfFYzU-EbVus4d_rAbQtybY,72
11
+ cloudnetpy/version.py,sha256=wWSbFMdT54VpsZJNxnh15y-5LNveGZg6cV6si07cF60,72
12
12
  cloudnetpy/categorize/__init__.py,sha256=gP5q3Vis1y9u9OWgA_idlbjfWXYN_S0IBSWdwBhL_uU,69
13
13
  cloudnetpy/categorize/atmos.py,sha256=fWW8ye_8HZASRAiYwURFKWzcGOYIA2RKeVxCq0lVOuM,12389
14
14
  cloudnetpy/categorize/atmos_utils.py,sha256=wndpwJxc2-QnNTkV8tc8I11Vs_WkNz9sVMX1fuGgUC4,3777
15
- cloudnetpy/categorize/categorize.py,sha256=QNSqEtpe1qtFQAKOG1suffPaYEwtOf4KMij9PdW9-Us,17477
15
+ cloudnetpy/categorize/categorize.py,sha256=p3LLBXSu5AOMrJWwAZeS6J-Xzh4PkXuPmOCZiEHzt2w,17678
16
16
  cloudnetpy/categorize/classify.py,sha256=x7aqPfhw4xuER22sqOb9ES9nijwk1E8b7HF7uaFJD7k,9218
17
17
  cloudnetpy/categorize/containers.py,sha256=j6oSKPeZcq9vFthYaocAw1m6yReRNNPYUQF5UTDq4YM,4232
18
- cloudnetpy/categorize/disdrometer.py,sha256=0Z0nvUtoZKDxiUfBZzoYZxUFOVjq-thmYfaCkskeECs,1799
18
+ cloudnetpy/categorize/disdrometer.py,sha256=daPB1JgERRqa0Ekxx_LYCP8mDe3XnUYj2VlsIKAB7sE,2003
19
19
  cloudnetpy/categorize/droplet.py,sha256=pUmB-gN0t9sVgsGLof6X9N0nuEb4EBtEUswwpoQapTY,8687
20
20
  cloudnetpy/categorize/falling.py,sha256=xES5ZdYs34tbX1p4a9kzt9r3G5s25Mpvs5WeFs1KNzo,4385
21
21
  cloudnetpy/categorize/freezing.py,sha256=684q83TPQ5hHrbbHX-E36VoTlWLSOlGfOW1FC8b3wfI,3754
@@ -51,7 +51,7 @@ cloudnetpy/instruments/weather_station.py,sha256=gTY3Y5UATqJo9Gld4hm7WdsKBwcF8Wg
51
51
  cloudnetpy/instruments/disdrometer/__init__.py,sha256=lyjwttWvFvuwYxEkusoAvgRcbBmglmOp5HJOpXUqLWo,93
52
52
  cloudnetpy/instruments/disdrometer/common.py,sha256=g52iK2aNp3Z88kovUmGVpC54NZomPa9D871gzO0AmQ4,9267
53
53
  cloudnetpy/instruments/disdrometer/parsivel.py,sha256=WiL-vCjw9Gmb5irvW3AXddsyprp8MGOfqcVAlfy0zpc,25521
54
- cloudnetpy/instruments/disdrometer/thies.py,sha256=t0RtiDbWkco8I_oJcvlqOEbK3hVdppiD6DzYNpCsqrA,9748
54
+ cloudnetpy/instruments/disdrometer/thies.py,sha256=lNR5ahOKIsO_gcpmbYZwh2UP2aawpQ5J9RrrnPKFFIE,10046
55
55
  cloudnetpy/model_evaluation/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
56
56
  cloudnetpy/model_evaluation/file_handler.py,sha256=oUGIblcEWLLv16YKUch-M5KA-dGRAcuHa-9anP3xtX4,6447
57
57
  cloudnetpy/model_evaluation/metadata.py,sha256=7ZL87iDbaQJIMu8wfnMvb01cGVPkl8RtvEm_tt9uIHE,8413
@@ -108,8 +108,8 @@ cloudnetpy/products/mie_lu_tables.nc,sha256=It4fYpqJXlqOgL8jeZ-PxGzP08PMrELIDVe5
108
108
  cloudnetpy/products/mwr_tools.py,sha256=PRm5aCULccUehU-Byk55wYhhEHseMjoAjGBu5TSyHao,4621
109
109
  cloudnetpy/products/product_tools.py,sha256=rhx_Ru9FLlQqCNM-awoiHx18-Aq1eBwL9LiUaQoJs6k,10412
110
110
  docs/source/conf.py,sha256=IKiFWw6xhUd8NrCg0q7l596Ck1d61XWeVjIFHVSG9Og,1490
111
- cloudnetpy-1.61.3.dist-info/LICENSE,sha256=wcZF72bdaoG9XugpyE95Juo7lBQOwLuTKBOhhtANZMM,1094
112
- cloudnetpy-1.61.3.dist-info/METADATA,sha256=dJ8xwncxh3pF3sT4uOHj8dnwHQ0XtJ29kSa2cUZbM2g,5784
113
- cloudnetpy-1.61.3.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
114
- cloudnetpy-1.61.3.dist-info/top_level.txt,sha256=ibSPWRr6ojS1i11rtBFz2_gkIe68mggj7aeswYfaOo0,16
115
- cloudnetpy-1.61.3.dist-info/RECORD,,
111
+ cloudnetpy-1.61.5.dist-info/LICENSE,sha256=wcZF72bdaoG9XugpyE95Juo7lBQOwLuTKBOhhtANZMM,1094
112
+ cloudnetpy-1.61.5.dist-info/METADATA,sha256=yj6xgn1999ZwuQIreZDzaDsYYfX9lnjDmA0oTL93Y4M,5784
113
+ cloudnetpy-1.61.5.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
114
+ cloudnetpy-1.61.5.dist-info/top_level.txt,sha256=ibSPWRr6ojS1i11rtBFz2_gkIe68mggj7aeswYfaOo0,16
115
+ cloudnetpy-1.61.5.dist-info/RECORD,,