cloudnetpy 1.67.3__py3-none-any.whl → 1.67.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.
cloudnetpy/concat_lib.py CHANGED
@@ -1,7 +1,10 @@
1
1
  """Module for concatenating netCDF files."""
2
2
 
3
+ import logging
3
4
  import shutil
5
+ from collections.abc import Iterable
4
6
  from os import PathLike
7
+ from pathlib import Path
5
8
  from typing import Literal
6
9
 
7
10
  import netCDF4
@@ -80,14 +83,14 @@ def update_nc(old_file: str, new_file: str) -> int:
80
83
 
81
84
 
82
85
  def concatenate_files(
83
- filenames: list,
86
+ filenames: Iterable[PathLike | str],
84
87
  output_file: str,
85
88
  concat_dimension: str = "time",
86
89
  variables: list | None = None,
87
90
  new_attributes: dict | None = None,
88
91
  ignore: list | None = None,
89
92
  allow_difference: list | None = None,
90
- ) -> None:
93
+ ) -> list:
91
94
  """Concatenate netCDF files in one dimension.
92
95
 
93
96
  Args:
@@ -101,6 +104,9 @@ def concatenate_files(
101
104
  allow_difference: Names of scalar variables that can differ from one file to
102
105
  another (value from the first file is saved).
103
106
 
107
+ Returns:
108
+ List of filenames that were successfully concatenated.
109
+
104
110
  Notes:
105
111
  Arrays without 'concat_dimension', scalars, and global attributes will be taken
106
112
  from the first file. Groups, possibly present in a NETCDF4 formatted file,
@@ -110,7 +116,7 @@ def concatenate_files(
110
116
  with _Concat(filenames, output_file, concat_dimension) as concat:
111
117
  concat.get_common_variables()
112
118
  concat.create_global_attributes(new_attributes)
113
- concat.concat_data(variables, ignore, allow_difference)
119
+ return concat.concat_data(variables, ignore, allow_difference)
114
120
 
115
121
 
116
122
  class _Concat:
@@ -118,11 +124,11 @@ class _Concat:
118
124
 
119
125
  def __init__(
120
126
  self,
121
- filenames: list,
127
+ filenames: Iterable[PathLike | str],
122
128
  output_file: str,
123
129
  concat_dimension: str = "time",
124
130
  ):
125
- self.filenames = sorted(filenames)
131
+ self.filenames = sorted(map(Path, filenames), key=lambda f: f.name)
126
132
  self.concat_dimension = concat_dimension
127
133
  self.first_filename = self.filenames[0]
128
134
  self.first_file = netCDF4.Dataset(self.first_filename)
@@ -147,12 +153,22 @@ class _Concat:
147
153
  variables: list | None,
148
154
  ignore: list | None,
149
155
  allow_vary: list | None,
150
- ) -> None:
156
+ ) -> list:
151
157
  """Concatenates data arrays."""
152
158
  self._write_initial_data(variables, ignore)
159
+ output = [self.first_filename]
153
160
  if len(self.filenames) > 1:
154
161
  for filename in self.filenames[1:]:
155
- self._append_data(filename, allow_vary)
162
+ try:
163
+ self._append_data(filename, allow_vary)
164
+ except RuntimeError as e:
165
+ if "NetCDF: HDF error" in str(e):
166
+ msg = f"Caught a NetCDF HDF error. Skipping file '{filename}'."
167
+ logging.exception(msg)
168
+ continue
169
+ raise
170
+ output.append(filename)
171
+ return output
156
172
 
157
173
  def _write_initial_data(self, variables: list | None, ignore: list | None) -> None:
158
174
  for key in self.first_file.variables:
@@ -185,7 +201,7 @@ class _Concat:
185
201
  var[:] = array
186
202
  _copy_attributes(self.first_file[key], var)
187
203
 
188
- def _append_data(self, filename: str, allow_vary: list | None) -> None:
204
+ def _append_data(self, filename: str | PathLike, allow_vary: list | None) -> None:
189
205
  with netCDF4.Dataset(filename) as file:
190
206
  auto_scale = False
191
207
  file.set_auto_scale(auto_scale)
@@ -91,15 +91,19 @@ def copernicus2nc(
91
91
  copernicus.mask_corrupted_values()
92
92
  copernicus.mask_first_range_gates()
93
93
  copernicus.mask_invalid_data()
94
- copernicus.add_time_and_range()
95
94
  copernicus.fix_range_offset(site_meta)
96
95
  copernicus.screen_negative_ranges()
97
96
  copernicus.add_radar_specific_variables()
98
97
  copernicus.add_nyquist_velocity(keymap)
99
98
  copernicus.add_site_geolocation()
100
- valid_indices = copernicus.add_zenith_and_azimuth_angles()
99
+ valid_indices = copernicus.add_zenith_and_azimuth_angles(
100
+ elevation_threshold=1,
101
+ elevation_diff_threshold=0.1,
102
+ azimuth_diff_threshold=0.1,
103
+ )
101
104
  copernicus.screen_time_indices(valid_indices)
102
105
  copernicus.add_height()
106
+ copernicus.test_if_all_masked()
103
107
  attributes = output.add_time_attribute(ATTRIBUTES, copernicus.date)
104
108
  output.update_attributes(copernicus.data, attributes)
105
109
  return output.save_level1b(copernicus, output_file, uuid)
@@ -89,13 +89,17 @@ def galileo2nc(
89
89
  galileo.screen_by_snr(snr_limit=snr_limit)
90
90
  galileo.mask_clutter()
91
91
  galileo.mask_invalid_data()
92
- galileo.add_time_and_range()
93
92
  galileo.add_radar_specific_variables()
94
93
  galileo.add_nyquist_velocity(keymap)
95
94
  galileo.add_site_geolocation()
96
- valid_indices = galileo.add_zenith_and_azimuth_angles()
95
+ valid_indices = galileo.add_zenith_and_azimuth_angles(
96
+ elevation_threshold=1,
97
+ elevation_diff_threshold=0.1,
98
+ azimuth_diff_threshold=0.1,
99
+ )
97
100
  galileo.screen_time_indices(valid_indices)
98
101
  galileo.add_height()
102
+ galileo.test_if_all_masked()
99
103
  attributes = output.add_time_attribute(ATTRIBUTES, galileo.date)
100
104
  output.update_attributes(galileo.data, attributes)
101
105
  return output.save_level1b(galileo, output_file, uuid)
@@ -80,7 +80,11 @@ def mira2nc(
80
80
  mira.add_time_and_range()
81
81
  mira.add_site_geolocation()
82
82
  mira.add_radar_specific_variables()
83
- valid_indices = mira.add_zenith_and_azimuth_angles()
83
+ valid_indices = mira.add_zenith_and_azimuth_angles(
84
+ elevation_threshold=1,
85
+ elevation_diff_threshold=1e-6,
86
+ azimuth_diff_threshold=1e-3,
87
+ )
84
88
  mira.screen_time_indices(valid_indices)
85
89
  mira.add_height()
86
90
  mira.test_if_all_masked()
@@ -90,7 +90,12 @@ class NcRadar(DataSource, CloudnetInstrument):
90
90
  if len(ind) > 0:
91
91
  self.data["v"].data[:, ind] = ma.masked
92
92
 
93
- def add_zenith_and_azimuth_angles(self) -> list:
93
+ def add_zenith_and_azimuth_angles(
94
+ self,
95
+ elevation_threshold: float,
96
+ elevation_diff_threshold: float,
97
+ azimuth_diff_threshold: float,
98
+ ) -> list:
94
99
  """Adds non-varying instrument zenith and azimuth angles and returns valid
95
100
  time indices.
96
101
  """
@@ -100,9 +105,9 @@ class NcRadar(DataSource, CloudnetInstrument):
100
105
  elevation_diff = ma.diff(elevation, prepend=elevation[1])
101
106
  azimuth_diff = ma.diff(azimuth, prepend=azimuth[1])
102
107
 
103
- is_stable = np.abs(elevation - 90) < 1
104
- is_stable &= np.abs(elevation_diff) < 1e-6
105
- is_stable &= np.abs(azimuth_diff) < 1e-3
108
+ is_stable = np.abs(elevation - 90) < elevation_threshold
109
+ is_stable &= np.abs(elevation_diff) < elevation_diff_threshold
110
+ is_stable &= np.abs(azimuth_diff) < azimuth_diff_threshold
106
111
 
107
112
  # If scanning unit is broken, data are missing
108
113
  # (assume it's vertically pointing)
@@ -203,7 +203,12 @@ def _fetch_files_with_same_range(
203
203
  bsc_sums = [get_sum(f) for f in bsc_files]
204
204
  depol_sums = [get_sum(f) for f in depol_files]
205
205
  all_sums = bsc_sums + depol_sums
206
- most_common_sum = Counter(all_sums).most_common(1)[0][0]
206
+
207
+ filtered_sums = [item for item in all_sums if item is not ma.masked]
208
+ if not filtered_sums:
209
+ return [], []
210
+
211
+ most_common_sum = Counter(filtered_sums).most_common(1)[0][0]
207
212
  valid_indices = [
208
213
  i
209
214
  for i, (bs, ds) in enumerate(zip(bsc_sums, depol_sums, strict=False))
cloudnetpy/metadata.py CHANGED
@@ -121,6 +121,11 @@ COMMON_ATTRIBUTES = {
121
121
  standard_name="zenith_angle",
122
122
  comment="Angle to the local vertical. A value of zero is directly overhead.",
123
123
  ),
124
+ "ir_zenith_angle": MetaData(
125
+ long_name="Infrared sensor zenith angle",
126
+ units="degree",
127
+ comment="90=horizon, 0=zenith",
128
+ ),
124
129
  "azimuth_angle": MetaData(
125
130
  long_name="Azimuth angle",
126
131
  standard_name="sensor_azimuth_angle",
cloudnetpy/version.py CHANGED
@@ -1,4 +1,4 @@
1
1
  MAJOR = 1
2
2
  MINOR = 67
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.67.3
3
+ Version: 1.67.5
4
4
  Summary: Python package for Cloudnet processing
5
5
  Author: Simo Tukiainen
6
6
  License: MIT License
@@ -1,15 +1,15 @@
1
1
  cloudnetpy/__init__.py,sha256=X_FqY-4yg5GUj5Edo14SToLEos6JIsC3fN-v1FUgQoA,43
2
2
  cloudnetpy/cli.py,sha256=lHkeAErmAijI-Ugpd4DHRHfbZP4SXOake0LIY5Ovv_Q,20782
3
3
  cloudnetpy/cloudnetarray.py,sha256=Ol1ha4RPAmFZANL__U5CaMKX4oYMXYR6OnjoCZ9w3eo,7077
4
- cloudnetpy/concat_lib.py,sha256=lLjEC0ILPI1ghv8Wu9WVDiQoAkwwBKlW5jV8KoIde_8,11963
4
+ cloudnetpy/concat_lib.py,sha256=jcLppqAmVHVkykcXBcpwUr8MS_k8v2Xl2xBLmVRE_DI,12624
5
5
  cloudnetpy/constants.py,sha256=jjW1eO5BwmLjtCKXKGXtKF_BoKpvSNrRfpgW43fWT_0,824
6
6
  cloudnetpy/datasource.py,sha256=FcWS77jz56gIzwnbafDLdj-HjAyu0P_VtY7gkeVZThU,7952
7
7
  cloudnetpy/exceptions.py,sha256=ns48useL9RN3mPh7CqIiLA19VI9OmVbyRsKTkwbThF8,1760
8
- cloudnetpy/metadata.py,sha256=DOGt7EQLS-AVJEszrUrpXr3gHVQv655FzeCzKrOPvoU,5477
8
+ cloudnetpy/metadata.py,sha256=QhmwRDzIqT6qAceocwpNx_CZVHAb1MUVoAmihybVkIM,5631
9
9
  cloudnetpy/output.py,sha256=lq4YSeMT_d-j4rlQkKm9KIZ8boupTBBBKV1eUawpmCI,15672
10
10
  cloudnetpy/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
11
11
  cloudnetpy/utils.py,sha256=U0iMIKPiKLrLVAfs_u9pPuoWYW1RJHcM8dbLF9a4yIA,29796
12
- cloudnetpy/version.py,sha256=g8g1vACVDsZA7aoMeIfXx3LzdjPkjA1SXN6-nsmvJUM,72
12
+ cloudnetpy/version.py,sha256=1kieuJxeVgwMXQUtOdo25ewj0bWtAJPCVKU_wHSvJ5M,72
13
13
  cloudnetpy/categorize/__init__.py,sha256=s-SJaysvVpVVo5kidiruWQO6p3gv2TXwY1wEHYO5D6I,44
14
14
  cloudnetpy/categorize/atmos_utils.py,sha256=RcmbKxm2COkE7WEya0mK3yX5rzUbrewRVh3ekm01RtM,10598
15
15
  cloudnetpy/categorize/attenuation.py,sha256=Y_-fzmQTltWTqIZTulJhovC7a6ifpMcaAazDJcnMIOc,990
@@ -39,16 +39,16 @@ cloudnetpy/instruments/ceilo.py,sha256=xrI7iYNftKvGZf-3C_ESUNsu-QhXV43iWkDuKp3bi
39
39
  cloudnetpy/instruments/ceilometer.py,sha256=pdmLVljsuciyKpaGxWxJ_f1IrJK-UrkBC0lSeuirLlU,12095
40
40
  cloudnetpy/instruments/cl61d.py,sha256=g6DNBFju3wYhLFl32DKmC8pUup7y-EupXoUU0fuoGGA,1990
41
41
  cloudnetpy/instruments/cloudnet_instrument.py,sha256=NQZ_FMXh8iyzXYSCKQSpIdp0MZFAh7WqKE8mZRmVbF4,4164
42
- cloudnetpy/instruments/copernicus.py,sha256=nmgqGOjVQFngj7BNbpcuCwA-W3yksvBbqn__iq7MyDk,6469
43
- cloudnetpy/instruments/galileo.py,sha256=yQBedd7dmDnwuWi1MtXOsg4-RyRx0uRAXumCY4YuH9k,4686
42
+ cloudnetpy/instruments/copernicus.py,sha256=he15ncH6SDCidBhr0BkOJc6Rg8cMvLWN0vGmpui6nGQ,6611
43
+ cloudnetpy/instruments/galileo.py,sha256=qABO3IUdRpGFDgqKsN0Pl4TQ-CWHQz8s13PxnwdIUnU,4828
44
44
  cloudnetpy/instruments/hatpro.py,sha256=DzCWzTJxTc5BSOgoeyM8RjYkSXX6NDi3QXgKRp0uxlI,8759
45
45
  cloudnetpy/instruments/instruments.py,sha256=cHP0RN-Z8Jl9yoDHdvaOflTrzuogDTGmd-nxSOk8Uq4,3568
46
46
  cloudnetpy/instruments/lufft.py,sha256=ugXF6pssHAAz1Y_hqPdpKuluAjxxHSR88xBmQuS6RlI,3705
47
- cloudnetpy/instruments/mira.py,sha256=HXfSRIWXrsSet3mSi0hiU-m-eEA6V_Pz0vjtiG8pbUM,10263
47
+ cloudnetpy/instruments/mira.py,sha256=un7qcoJrIeZmKWmVFCV84rmYCZkyJtvYnYXEhkENrY4,10407
48
48
  cloudnetpy/instruments/mrr.py,sha256=eeAzCp3CiHGauywjwvMUAFwZ4vBOZMcd3IlF8KsrLQo,5711
49
49
  cloudnetpy/instruments/nc_lidar.py,sha256=5gQG9PApnNPrHmS9_zanl8HEYIQuGRpbnzC3wfTcOyQ,1705
50
- cloudnetpy/instruments/nc_radar.py,sha256=ZNNmPdSF4yTVhq8CpnfgecH1DuYy7psc4YTxp3BLWRw,6724
51
- cloudnetpy/instruments/pollyxt.py,sha256=TAhpwwV9EcFTg2Zb-Hjwc6PUetEkO4csGs74ghrpTe4,9899
50
+ cloudnetpy/instruments/nc_radar.py,sha256=AjPn3mkq5a1mE7YzKtZnxX5suNju9NhUq-TDvs7T_uU,6911
51
+ cloudnetpy/instruments/pollyxt.py,sha256=ra7sYQ_cmkC0T9TBYrMN6iiQEZimmWGdW9Ilv61JB-Q,10027
52
52
  cloudnetpy/instruments/radiometrics.py,sha256=ySG4a042XkgjMTG8d20oAPNvFvw9bMwwiqS3zv-JF_w,11825
53
53
  cloudnetpy/instruments/rpg.py,sha256=IozvBJ8_qXTPqtp58FQwRsoI5_aI3-kycpXugZkS0d4,17462
54
54
  cloudnetpy/instruments/rpg_reader.py,sha256=ThztFuVrWxhmWVAfZTfQDeUiKK1XMTbtv08IBe8GK98,11364
@@ -115,9 +115,9 @@ cloudnetpy/products/mie_lu_tables.nc,sha256=It4fYpqJXlqOgL8jeZ-PxGzP08PMrELIDVe5
115
115
  cloudnetpy/products/mwr_tools.py,sha256=rd7UC67O4fsIE5SaHVZ4qWvUJTj41ZGwgQWPwZzOM14,5377
116
116
  cloudnetpy/products/product_tools.py,sha256=uu4l6reuGbPcW3TgttbaSrqIKbyYGhBVTdnC7opKvmg,11101
117
117
  docs/source/conf.py,sha256=IKiFWw6xhUd8NrCg0q7l596Ck1d61XWeVjIFHVSG9Og,1490
118
- cloudnetpy-1.67.3.dist-info/LICENSE,sha256=wcZF72bdaoG9XugpyE95Juo7lBQOwLuTKBOhhtANZMM,1094
119
- cloudnetpy-1.67.3.dist-info/METADATA,sha256=QrnsmPKlK0kGbF6XogT2gmffoZ2ZEhKTjGY5ldJty0I,5793
120
- cloudnetpy-1.67.3.dist-info/WHEEL,sha256=PZUExdf71Ui_so67QXpySuHtCi3-J3wvF4ORK6k_S8U,91
121
- cloudnetpy-1.67.3.dist-info/entry_points.txt,sha256=HhY7LwCFk4qFgDlXx_Fy983ZTd831WlhtdPIzV-Y3dY,51
122
- cloudnetpy-1.67.3.dist-info/top_level.txt,sha256=ibSPWRr6ojS1i11rtBFz2_gkIe68mggj7aeswYfaOo0,16
123
- cloudnetpy-1.67.3.dist-info/RECORD,,
118
+ cloudnetpy-1.67.5.dist-info/LICENSE,sha256=wcZF72bdaoG9XugpyE95Juo7lBQOwLuTKBOhhtANZMM,1094
119
+ cloudnetpy-1.67.5.dist-info/METADATA,sha256=FEyHXhhROX3iv-iXHFwVrR7XtS0C3uCa7wfsr-sACNA,5793
120
+ cloudnetpy-1.67.5.dist-info/WHEEL,sha256=PZUExdf71Ui_so67QXpySuHtCi3-J3wvF4ORK6k_S8U,91
121
+ cloudnetpy-1.67.5.dist-info/entry_points.txt,sha256=HhY7LwCFk4qFgDlXx_Fy983ZTd831WlhtdPIzV-Y3dY,51
122
+ cloudnetpy-1.67.5.dist-info/top_level.txt,sha256=ibSPWRr6ojS1i11rtBFz2_gkIe68mggj7aeswYfaOo0,16
123
+ cloudnetpy-1.67.5.dist-info/RECORD,,