cloudnetpy 1.64.5__py3-none-any.whl → 1.65.1__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.
@@ -181,7 +181,14 @@ class LiquidAttenuation(Attenuation):
181
181
 
182
182
  def __init__(self, data: dict, classification: ClassificationResult):
183
183
  super().__init__(data["model"], classification)
184
- self._mwr = data["mwr"].data
184
+ if data["mwr"] is not None:
185
+ self._mwr = data["mwr"].data
186
+ else:
187
+ n_time = data["radar"].data["Z"][:].shape[0]
188
+ self._mwr = {
189
+ "lwp": ma.masked_all(n_time),
190
+ "lwp_error": ma.masked_all(n_time),
191
+ }
185
192
  self._lwc_dz_err = self._get_lwc_change_rate_error()
186
193
  self.atten = self._get_liquid_atten()
187
194
  self.atten_err = self._get_liquid_atten_err()
@@ -20,54 +20,58 @@ def generate_categorize(
20
20
  uuid: str | None = None,
21
21
  options: dict | None = None,
22
22
  ) -> str:
23
- """Generates Cloudnet Level 1c categorize file.
23
+ """Generates a Cloudnet Level 1c categorize file.
24
24
 
25
- The measurements are rebinned into a common height / time grid,
26
- and classified as different types of scatterers such as ice, liquid,
27
- insects, etc. Next, the radar signal is corrected for atmospheric
28
- attenuation, and error estimates are computed. Results are saved
29
- in *output_file* which is a compressed netCDF4 file.
25
+ This function rebins measurements into a common height/time grid
26
+ and classifies them into different scatterer types, such as ice,
27
+ liquid, insects, etc. The radar signal is corrected for atmospheric
28
+ attenuation, and error estimates are computed. The results are saved in
29
+ *output_file*, a compressed netCDF4 file.
30
30
 
31
31
  Args:
32
- input_files: dict containing file names for calibrated `radar`, `lidar`,
33
- `model` and `mwr` files. Optionally also `lv0_files`, a list of
34
- RPG level 0 files.
35
- output_file: Full path of the output file.
36
- uuid: Set specific UUID for the file.
37
- options: Dictionary containing optional parameters.
32
+ input_files (dict): Contains filenames for calibrated `radar`, `lidar`,
33
+ and `model` files. Optionally, it can also include `disdrometer`,
34
+ `mwr` (containing the LWP variable), and `lv0_files` (a list of RPG
35
+ Level 0 files).
36
+ output_file (str): The full path of the output file.
37
+ uuid (str): Specific UUID to assign to the generated file.
38
+ options (dict): Dictionary containing optional parameters.
38
39
 
39
40
  Returns:
40
- UUID of the generated file.
41
+ str: UUID of the generated file.
41
42
 
42
43
  Raises:
43
- RuntimeError: Failed to create the categorize file.
44
+ RuntimeError: Raised if the categorize file creation fails.
44
45
 
45
46
  Notes:
46
- Separate mwr-file is not needed when using RPG cloud radar which
47
- measures liquid water path. Then, the radar file can be used as
48
- a mwr-file as well, i.e. {'mwr': 'radar.nc'}.
47
+ A separate MWR file is not required when using an RPG cloud radar that
48
+ measures liquid water path (LWP). In this case, the radar file can also
49
+ serve as the MWR file (e.g., {'mwr': 'radar.nc'}). If no MWR file
50
+ is provided, liquid attenuation correction cannot be performed.
49
51
 
50
- If RPG L0 files are provided as an additional input, Voodoo method is used
51
- to detect liquid droplets.
52
+ If RPG L0 files are included as additional input, the Voodoo method
53
+ is used to detect liquid droplets.
52
54
 
53
55
  Examples:
54
56
  >>> from cloudnetpy.categorize import generate_categorize
55
- >>> input_files = {'radar': 'radar.nc',
56
- 'lidar': 'lidar.nc',
57
- 'model': 'model.nc',
58
- 'mwr': 'mwr.nc'}
57
+ >>> input_files = {
58
+ ... 'radar': 'radar.nc',
59
+ ... 'lidar': 'lidar.nc',
60
+ ... 'model': 'model.nc',
61
+ ... 'mwr': 'mwr.nc'
62
+ ... }
59
63
  >>> generate_categorize(input_files, 'output.nc')
60
64
 
61
- >>> input_files["lv0_files"] = ["file1.LV0", "file2.LV0"] # Add RGP LV0 files
62
- >>> generate_categorize(input_files, 'output.nc') # Use Voodoo method
63
-
65
+ >>> input_files['lv0_files'] = ['file1.LV0', 'file2.LV0'] # Add RPG LV0 files
66
+ >>> generate_categorize(input_files, 'output.nc') # Use the Voodoo method
64
67
  """
65
68
 
66
69
  def _interpolate_to_cloudnet_grid() -> list:
67
70
  wl_band = utils.get_wl_band(data["radar"].radar_frequency)
68
- data["mwr"].rebin_to_grid(time)
69
71
  if data["disdrometer"] is not None:
70
72
  data["disdrometer"].interpolate_to_grid(time)
73
+ if data["mwr"] is not None:
74
+ data["mwr"].rebin_to_grid(time)
71
75
  data["model"].interpolate_to_common_height(wl_band)
72
76
  model_gap_ind = data["model"].interpolate_to_grid(time, height)
73
77
  radar_gap_ind = data["radar"].rebin_to_grid(time)
@@ -115,7 +119,7 @@ def generate_categorize(
115
119
  **data["lidar"].data,
116
120
  **data["model"].data,
117
121
  **data["model"].data_sparse,
118
- **data["mwr"].data,
122
+ **(data["mwr"].data if data["mwr"] is not None else {}),
119
123
  **(data["disdrometer"].data if data["disdrometer"] is not None else {}),
120
124
  }
121
125
 
@@ -131,10 +135,12 @@ def generate_categorize(
131
135
  data: dict = {
132
136
  "radar": Radar(input_files["radar"]),
133
137
  "lidar": Lidar(input_files["lidar"]),
134
- "mwr": Mwr(input_files["mwr"]),
135
138
  "lv0_files": input_files.get("lv0_files"),
139
+ "mwr": None,
136
140
  "disdrometer": None,
137
141
  }
142
+ if "mwr" in input_files:
143
+ data["mwr"] = Mwr(input_files["mwr"])
138
144
  if "disdrometer" in input_files:
139
145
  try:
140
146
  data["disdrometer"] = Disdrometer(input_files["disdrometer"])
@@ -58,7 +58,11 @@ class ClassData:
58
58
  self.tw = data["model"].data["Tw"][:]
59
59
  self.model_type = data["model"].source_type
60
60
  self.beta = data["lidar"].data["beta"][:]
61
- self.lwp = data["mwr"].data["lwp"][:]
61
+ self.lwp = (
62
+ data["mwr"].data["lwp"][:]
63
+ if data["mwr"] is not None
64
+ else ma.masked_all(self.time.shape)
65
+ )
62
66
  self.is_rain = self._find_profiles_with_rain()
63
67
  self.is_clutter = _find_clutter(self.v, self.is_rain)
64
68
  self.altitude = data["radar"].altitude
cloudnetpy/exceptions.py CHANGED
@@ -63,3 +63,10 @@ class HatproDataError(CloudnetException):
63
63
 
64
64
  def __init__(self, msg: str = "Invalid HATPRO file"):
65
65
  super().__init__(msg)
66
+
67
+
68
+ class InvalidSourceFileError(CloudnetException):
69
+ """Internal exception class."""
70
+
71
+ def __init__(self, msg: str = "Invalid source file"):
72
+ super().__init__(msg)
@@ -60,6 +60,10 @@ def hatpro2l1c(
60
60
 
61
61
  hatpro = HatproL1c(hatpro_raw, site_meta)
62
62
 
63
+ if not np.any(hatpro.data["tb"][:]):
64
+ msg = "No valid brightness temperatures found"
65
+ raise HatproDataError(msg)
66
+
63
67
  timestamps = hatpro.data["time"][:]
64
68
  if date is not None:
65
69
  # Screen timestamps if these assertions start to fail
@@ -10,6 +10,7 @@ from numpy import ma
10
10
  from cloudnetpy import output, utils
11
11
  from cloudnetpy.categorize import atmos
12
12
  from cloudnetpy.datasource import DataSource
13
+ from cloudnetpy.exceptions import InvalidSourceFileError
13
14
  from cloudnetpy.metadata import MetaData
14
15
  from cloudnetpy.products.product_tools import (
15
16
  CategorizeBits,
@@ -113,6 +114,9 @@ class DerSource(DataSource):
113
114
 
114
115
  def __init__(self, categorize_file: str, parameters: Parameters | None = None):
115
116
  super().__init__(categorize_file)
117
+ if "lwp" not in self.dataset.variables:
118
+ msg = "Liquid water path missing from the categorize file."
119
+ raise InvalidSourceFileError(msg)
116
120
  self.is_rain = get_is_rain(categorize_file)
117
121
  self.categorize_bits = CategorizeBits(categorize_file)
118
122
  if parameters is None:
@@ -8,6 +8,7 @@ from numpy import ma
8
8
  from cloudnetpy import output, utils
9
9
  from cloudnetpy.categorize import atmos
10
10
  from cloudnetpy.datasource import DataSource
11
+ from cloudnetpy.exceptions import InvalidSourceFileError
11
12
  from cloudnetpy.metadata import MetaData
12
13
  from cloudnetpy.products import product_tools as p_tools
13
14
  from cloudnetpy.products.product_tools import CategorizeBits, get_is_rain
@@ -88,6 +89,9 @@ class LwcSource(DataSource):
88
89
 
89
90
  def __init__(self, categorize_file: str):
90
91
  super().__init__(categorize_file)
92
+ if "lwp" not in self.dataset.variables:
93
+ msg = "Liquid water path missing from the categorize file."
94
+ raise InvalidSourceFileError(msg)
91
95
  self.lwp = self.getvar("lwp")
92
96
  self.lwp[self.lwp < 0] = 0
93
97
  self.lwp_error = self.getvar("lwp_error")
cloudnetpy/version.py CHANGED
@@ -1,4 +1,4 @@
1
1
  MAJOR = 1
2
- MINOR = 64
3
- PATCH = 5
2
+ MINOR = 65
3
+ PATCH = 1
4
4
  __version__ = f"{MAJOR}.{MINOR}.{PATCH}"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: cloudnetpy
3
- Version: 1.64.5
3
+ Version: 1.65.1
4
4
  Summary: Python package for Cloudnet processing
5
5
  Author: Simo Tukiainen
6
6
  License: MIT License
@@ -3,18 +3,18 @@ cloudnetpy/cloudnetarray.py,sha256=Ol1ha4RPAmFZANL__U5CaMKX4oYMXYR6OnjoCZ9w3eo,7
3
3
  cloudnetpy/concat_lib.py,sha256=8Ek059RMLAfbbXCkX90cgnhw_8ZpcDrxw1yPvwtuitU,9846
4
4
  cloudnetpy/constants.py,sha256=YVbi2porUnKIzO_PdGeH9pEO9gKa95vDcj6TBMSreoY,734
5
5
  cloudnetpy/datasource.py,sha256=j7N4g59HPvOBWle-W9bOUF0BfRLgvR4zwOi_B50cI7Q,7921
6
- cloudnetpy/exceptions.py,sha256=wrI0bZTwmS5C_cqOmvlJ8XJSEFyzuD1eD4voGJc_Gjg,1584
6
+ cloudnetpy/exceptions.py,sha256=ns48useL9RN3mPh7CqIiLA19VI9OmVbyRsKTkwbThF8,1760
7
7
  cloudnetpy/metadata.py,sha256=v_VDo2vbdTxB0zIsfP69IcrwSKiRlLpsGdq6JPI4CoA,5306
8
8
  cloudnetpy/output.py,sha256=YkCaxVkG_Mt2hng_IVnhygHteV4UMKzKALkeFZwFJL8,14822
9
9
  cloudnetpy/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
10
10
  cloudnetpy/utils.py,sha256=JV0Fawnme1HoZgoiidV3eIzsn6vx0AEjBNmI1CcrBsA,28517
11
- cloudnetpy/version.py,sha256=HFcyqxYPsSTDqsoOFkLobAWVqsMpVLEgMyJIizNnV8U,72
11
+ cloudnetpy/version.py,sha256=jw9H3ZZS4YhETjavFqda9t2WtO2jSz4WsOUzbwSTTvk,72
12
12
  cloudnetpy/categorize/__init__.py,sha256=gP5q3Vis1y9u9OWgA_idlbjfWXYN_S0IBSWdwBhL_uU,69
13
- cloudnetpy/categorize/atmos.py,sha256=G4DmEJCt1FAPYyt7oXzBH47JTeb5lUOGDakkviOXblE,12390
13
+ cloudnetpy/categorize/atmos.py,sha256=vavMC_WQQyGH14eL4vAzKLKDDZt8tBrMYimztYHOjH8,12639
14
14
  cloudnetpy/categorize/atmos_utils.py,sha256=64uenj2uxj3P3Blaq_pBN1pBjcF-X4LYNt-uTOjvevg,3778
15
- cloudnetpy/categorize/categorize.py,sha256=owM4ebqJCHnCWHDMELv6Qa8zM_7qKcBpzJOfPva1Py0,17929
15
+ cloudnetpy/categorize/categorize.py,sha256=VcxSs22icYDG3R5x9jTX7uuSjPU8tyc5bIz0Zj5F9z0,18303
16
16
  cloudnetpy/categorize/classify.py,sha256=a-0bVCtynGfORnDGTsPuzqkuDeOOR_OMz5ai9NsMuic,9870
17
- cloudnetpy/categorize/containers.py,sha256=L4UaihDfeMCADZiKdII5NCP49ZNlodCoM9X3yxEfJ_A,4748
17
+ cloudnetpy/categorize/containers.py,sha256=g3SQHoqlY1uJ8b-MG-BbW3oWz5IyacA8kJBeIPy_4EA,4859
18
18
  cloudnetpy/categorize/disdrometer.py,sha256=keU3pFvKtk840A0oLwAyNDuqOCswBPJEKf2bV0YWyA8,2004
19
19
  cloudnetpy/categorize/droplet.py,sha256=894VHdL9ScaB8f1oxXwM2la4ShXd-uWywQDINoaoiD8,8687
20
20
  cloudnetpy/categorize/falling.py,sha256=Wz49mbw0pubnbhoekYTqGT0S9UNaE88jWOjSPEsCIaI,4386
@@ -34,7 +34,7 @@ cloudnetpy/instruments/cl61d.py,sha256=g6DNBFju3wYhLFl32DKmC8pUup7y-EupXoUU0fuoG
34
34
  cloudnetpy/instruments/cloudnet_instrument.py,sha256=RG5HJxGM6p0F-IGyr85fvOizcMmgx48OeD_XeIsrgSU,3367
35
35
  cloudnetpy/instruments/copernicus.py,sha256=nmgqGOjVQFngj7BNbpcuCwA-W3yksvBbqn__iq7MyDk,6469
36
36
  cloudnetpy/instruments/galileo.py,sha256=yQBedd7dmDnwuWi1MtXOsg4-RyRx0uRAXumCY4YuH9k,4686
37
- cloudnetpy/instruments/hatpro.py,sha256=PD2wLmzzbeOticvg44cT3aJzQYsRnLekW9pBPOzjFLc,8514
37
+ cloudnetpy/instruments/hatpro.py,sha256=9A7H-SEDGp-1zuLFskd8WRp4nU3ZI70Bkq5_GBpIx9I,8646
38
38
  cloudnetpy/instruments/instruments.py,sha256=jG5TYnZ8bdCZXnI303ZsaJBEdSKaIjKMbkGtnq6kQX0,3261
39
39
  cloudnetpy/instruments/lufft.py,sha256=ugXF6pssHAAz1Y_hqPdpKuluAjxxHSR88xBmQuS6RlI,3705
40
40
  cloudnetpy/instruments/mira.py,sha256=EyzEBTpWfDlgaspZVuIfaP4l73GYSVnSzEzBZc0lZNg,9333
@@ -97,19 +97,19 @@ cloudnetpy/plotting/plot_meta.py,sha256=JHrr-4A9fhqdi_tQFe6mR4Fdry3hkI-lmmVu5Ny2
97
97
  cloudnetpy/plotting/plotting.py,sha256=rVaCsXTrhb0ahdXerSPLZWRASs_QktyLUbjyHoVuam8,33584
98
98
  cloudnetpy/products/__init__.py,sha256=2hRb5HG9hNrxH1if5laJkLeFeaZCd5W1q3hh4ewsX0E,273
99
99
  cloudnetpy/products/classification.py,sha256=bNG8W1CMgGoUBpXopQjYAW3F-uEJGyojXb4A5jmErHo,7921
100
- cloudnetpy/products/der.py,sha256=sITzQbvutU5u1D16hDG2Ke7XB9gBxSP22OLy2Yhi1zI,12446
100
+ cloudnetpy/products/der.py,sha256=1LDBbnbUg8feMUTGWJq3bObBhEcZ_Ee17MB1x0GwRdo,12669
101
101
  cloudnetpy/products/drizzle.py,sha256=58C9Mo6oRXR8KpbVPghbJvHvFX9GfS3xUp058pbf0qw,10804
102
102
  cloudnetpy/products/drizzle_error.py,sha256=4GwlHRtNbk9ks7bGtXCco-wXbcDOKeAQwKmbhzut6Qk,6132
103
103
  cloudnetpy/products/drizzle_tools.py,sha256=LR2AtbFQRGFrJ2LGyiLxOfbnlznVLydXvb8RFDR0_4E,10848
104
104
  cloudnetpy/products/ier.py,sha256=ge1f_aYick20Nlznq8zbBl5umWlTP-UwMivy4Y05Sck,7839
105
105
  cloudnetpy/products/iwc.py,sha256=Q8dXV3JF3JUQgwkmQFOKakm21Tnf8oCWsH0CSqIEKl4,10209
106
- cloudnetpy/products/lwc.py,sha256=LsqEPluRW1JmFnM8GiQHfciBR6q5CXjr8D-D2qcGQeM,18774
106
+ cloudnetpy/products/lwc.py,sha256=wSd3GDqELz4yyWBMiKDR-QhRK8scPheqsBcS1qzxYOI,18997
107
107
  cloudnetpy/products/mie_lu_tables.nc,sha256=It4fYpqJXlqOgL8jeZ-PxGzP08PMrELIDVe55y9ob58,16637951
108
108
  cloudnetpy/products/mwr_tools.py,sha256=3esU5cG5GI2WVmOENqrJ0FbMuxLegADv7q8TB0RorGg,4674
109
109
  cloudnetpy/products/product_tools.py,sha256=VNw2diJj30POz68-3qNVkJP7r9AUspT_d1Fp0BbeIx8,10414
110
110
  docs/source/conf.py,sha256=IKiFWw6xhUd8NrCg0q7l596Ck1d61XWeVjIFHVSG9Og,1490
111
- cloudnetpy-1.64.5.dist-info/LICENSE,sha256=wcZF72bdaoG9XugpyE95Juo7lBQOwLuTKBOhhtANZMM,1094
112
- cloudnetpy-1.64.5.dist-info/METADATA,sha256=TjDw09hqeSIv3ZRqxBqgu9MIuz80Y_gFzsO9dRmrkKo,5784
113
- cloudnetpy-1.64.5.dist-info/WHEEL,sha256=R0nc6qTxuoLk7ShA2_Y-UWkN8ZdfDBG2B6Eqpz2WXbs,91
114
- cloudnetpy-1.64.5.dist-info/top_level.txt,sha256=ibSPWRr6ojS1i11rtBFz2_gkIe68mggj7aeswYfaOo0,16
115
- cloudnetpy-1.64.5.dist-info/RECORD,,
111
+ cloudnetpy-1.65.1.dist-info/LICENSE,sha256=wcZF72bdaoG9XugpyE95Juo7lBQOwLuTKBOhhtANZMM,1094
112
+ cloudnetpy-1.65.1.dist-info/METADATA,sha256=qxDqKsWNjOAd93st6zGCAqnoJB49_j1gYKLeq7yemjc,5784
113
+ cloudnetpy-1.65.1.dist-info/WHEEL,sha256=Mdi9PDNwEZptOjTlUcAth7XJDFtKrHYaQMPulZeBCiQ,91
114
+ cloudnetpy-1.65.1.dist-info/top_level.txt,sha256=ibSPWRr6ojS1i11rtBFz2_gkIe68mggj7aeswYfaOo0,16
115
+ cloudnetpy-1.65.1.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (72.1.0)
2
+ Generator: setuptools (73.0.1)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5