cloudnetpy 1.66.17__py3-none-any.whl → 1.66.19__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.
@@ -142,11 +142,18 @@ HALO = Instrument(
142
142
  model="StreamLine",
143
143
  )
144
144
 
145
- WINDCUBE = Instrument(
146
- manufacturer="Leosphere",
145
+ WINDCUBE_WLS200S = Instrument(
146
+ manufacturer="Vaisala",
147
+ domain="lidar",
148
+ category="Doppler lidar",
149
+ model="WindCube WLS200S",
150
+ )
151
+
152
+ WINDCUBE_WLS70 = Instrument(
153
+ manufacturer="Vaisala",
147
154
  domain="lidar",
148
155
  category="Doppler lidar",
149
- model="WindCube",
156
+ model="WindCube WLS70",
150
157
  )
151
158
 
152
159
  PARSIVEL2 = Instrument(
@@ -72,6 +72,7 @@ def mira2nc(
72
72
  mira.screen_by_snr()
73
73
  mira.screen_invalid_ldr()
74
74
  mira.mask_invalid_data()
75
+ mira.mask_bad_angles()
75
76
  mira.add_time_and_range()
76
77
  mira.add_site_geolocation()
77
78
  mira.add_radar_specific_variables()
@@ -128,6 +129,18 @@ class Mira(NcRadar):
128
129
  )
129
130
  self.data["ldr"].data[:] = ma.masked
130
131
 
132
+ def mask_bad_angles(self) -> None:
133
+ """Masks clearly bad elevation and azimuth angles."""
134
+ limits = {
135
+ "elevation": (0, 180),
136
+ "azimuth_angle": (-360, 360),
137
+ }
138
+ for key, (lower, upper) in limits.items():
139
+ if (array := self.data[key].data) is not None:
140
+ margin = (upper - lower) * 0.05
141
+ array[array < (lower - margin)] = ma.masked
142
+ array[array > (upper + margin)] = ma.masked
143
+
131
144
 
132
145
  def _parse_input_files(input_files: str | list[str], temp_dir: str) -> tuple:
133
146
  if isinstance(input_files, list) or os.path.isdir(input_files):
@@ -219,7 +232,6 @@ def _get_keymap(filetype: str) -> dict:
219
232
  ("SNRh2l", "SNR"),
220
233
  ("elv", "elevation"),
221
234
  ("azi", "azimuth_angle"),
222
- ("aziv", "azimuth_velocity"),
223
235
  ("nfft", "nfft"),
224
236
  ("nave", "nave"),
225
237
  ("prf", "prf"),
@@ -234,7 +246,6 @@ def _get_keymap(filetype: str) -> dict:
234
246
  "SNRg": "SNR",
235
247
  "elv": "elevation",
236
248
  "azi": "azimuth_angle",
237
- "aziv": "azimuth_velocity",
238
249
  "nfft": "nfft",
239
250
  "nave": "nave",
240
251
  "prf": "prf",
@@ -94,41 +94,26 @@ class NcRadar(DataSource, CloudnetInstrument):
94
94
  """Adds non-varying instrument zenith and azimuth angles and returns valid
95
95
  time indices.
96
96
  """
97
- if "azimuth_velocity" in self.data:
98
- azimuth = self.data["azimuth_velocity"].data
99
- azimuth_reference = azimuth[0] if np.all(azimuth == azimuth[0]) else 0
100
- azimuth_tolerance = 1e-6
101
- else:
102
- azimuth = self.data["azimuth_angle"].data
103
- azimuth_reference = ma.median(azimuth)
104
- azimuth_tolerance = 0.1
105
-
106
97
  elevation = self.data["elevation"].data
98
+ azimuth = self.data["azimuth_angle"].data
107
99
 
108
- # Elevation is sometimes around -1000 indicating missing value
109
- # Assume the instrument is pointing vertically in these cases
110
- elevation[elevation < 0] = 90
111
- zenith = 90 - elevation
100
+ elevation_diff = ma.diff(elevation, prepend=elevation[1])
101
+ azimuth_diff = ma.diff(azimuth, prepend=azimuth[1])
112
102
 
113
- is_valid_zenith = np.abs(zenith) < 10
114
- if not np.any(is_valid_zenith):
115
- msg = "No valid zenith angles"
116
- raise ValidTimeStampError(msg)
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
117
106
 
118
- valid_zenith = zenith[is_valid_zenith]
119
- is_stable_zenith = np.isclose(zenith, ma.median(valid_zenith), atol=0.1)
120
- is_stable_azimuth = np.isclose(
121
- azimuth,
122
- azimuth_reference,
123
- atol=azimuth_tolerance,
124
- )
125
- is_stable_profile = is_stable_zenith & is_stable_azimuth
107
+ # If scanning unit is broken, data are missing
108
+ # (assume it's vertically pointing)
109
+ missing_info = elevation.mask & azimuth.mask
110
+ is_stable[missing_info] = True
126
111
 
127
- if ma.isMaskedArray(is_stable_profile):
128
- is_stable_profile[is_stable_profile.mask] = False
129
- n_removed = np.count_nonzero(~is_stable_profile)
112
+ if ma.isMaskedArray(is_stable):
113
+ is_stable[is_stable.mask] = False
114
+ n_removed = np.count_nonzero(~is_stable)
130
115
 
131
- if n_removed >= len(zenith) - 1:
116
+ if n_removed >= len(elevation) - 1:
132
117
  msg = "Less than two profiles with valid zenith / azimuth angles"
133
118
  raise ValidTimeStampError(msg)
134
119
 
@@ -137,11 +122,10 @@ class NcRadar(DataSource, CloudnetInstrument):
137
122
  "Filtering %s profiles due to varying zenith / azimuth angle",
138
123
  n_removed,
139
124
  )
125
+ zenith = 90 - elevation
140
126
  self.append_data(zenith, "zenith_angle")
141
- for key in ("elevation", "azimuth_velocity"):
142
- if key in self.data:
143
- del self.data[key]
144
- return list(is_stable_profile)
127
+ del self.data["elevation"]
128
+ return list(is_stable)
145
129
 
146
130
  def add_radar_specific_variables(self) -> None:
147
131
  """Adds radar specific variables."""
@@ -45,6 +45,8 @@ class PlotParameters:
45
45
  plot_meta: Additional metadata for the plot.
46
46
  raise_on_empty: Whether to raise an error if no data is found for a
47
47
  plotted variable.
48
+ minor_ticks: Whether to display minor ticks on the x-axis.
49
+
48
50
  """
49
51
 
50
52
  dpi: float = 120
@@ -58,6 +60,7 @@ class PlotParameters:
58
60
  footer_text: str | None = None
59
61
  plot_meta: PlotMeta | None = None
60
62
  raise_on_empty: bool = False
63
+ minor_ticks: bool = False
61
64
 
62
65
 
63
66
  class Dimensions:
@@ -210,6 +213,9 @@ class SubPlot:
210
213
  ]
211
214
  self.ax.set_xticks(np.arange(0, 25, resolution, dtype=int))
212
215
  self.ax.set_xticklabels(x_tick_labels, fontsize=12)
216
+ if self.options.minor_ticks:
217
+ self.ax.xaxis.set_minor_locator(AutoMinorLocator(4))
218
+ self.ax.tick_params(which="minor", length=2.5)
213
219
  self.ax.set_xlim(0, 24)
214
220
 
215
221
  def set_yax(
@@ -910,6 +916,8 @@ def _get_max_gap_in_minutes(figure_data: FigureData) -> float:
910
916
  "mwr-multi": 35,
911
917
  "weather-station": 12,
912
918
  "doppler-lidar-wind": 75,
919
+ "doppler-lidar": 75,
920
+ "radar": 5,
913
921
  }
914
922
  return max_allowed_gap.get(file_type, 10)
915
923
 
cloudnetpy/version.py CHANGED
@@ -1,4 +1,4 @@
1
1
  MAJOR = 1
2
2
  MINOR = 66
3
- PATCH = 17
3
+ PATCH = 19
4
4
  __version__ = f"{MAJOR}.{MINOR}.{PATCH}"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: cloudnetpy
3
- Version: 1.66.17
3
+ Version: 1.66.19
4
4
  Summary: Python package for Cloudnet processing
5
5
  Author: Simo Tukiainen
6
6
  License: MIT License
@@ -9,7 +9,7 @@ cloudnetpy/metadata.py,sha256=DOGt7EQLS-AVJEszrUrpXr3gHVQv655FzeCzKrOPvoU,5477
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=JksYOwf9ORiR_QpoKrTe1JJwXpPYJj-wlwaZKCHoh3o,29744
12
- cloudnetpy/version.py,sha256=I_QExn3cCA9D7n_90Qiz-7ArHlSnWElngZHWc2kPtBo,73
12
+ cloudnetpy/version.py,sha256=LenpDgU7pkca-TTIRr09FikaXYR6wcpd58u4rgZjJdo,73
13
13
  cloudnetpy/categorize/__init__.py,sha256=s-SJaysvVpVVo5kidiruWQO6p3gv2TXwY1wEHYO5D6I,44
14
14
  cloudnetpy/categorize/atmos_utils.py,sha256=9-ymI6i1xASf-XAFyO87FaTfvq6bF89N1i_27OkUp-M,10104
15
15
  cloudnetpy/categorize/attenuation.py,sha256=Y_-fzmQTltWTqIZTulJhovC7a6ifpMcaAazDJcnMIOc,990
@@ -42,12 +42,12 @@ cloudnetpy/instruments/cloudnet_instrument.py,sha256=6qQSyQXHBTdOvzqTxOXtx6RYDm7
42
42
  cloudnetpy/instruments/copernicus.py,sha256=nmgqGOjVQFngj7BNbpcuCwA-W3yksvBbqn__iq7MyDk,6469
43
43
  cloudnetpy/instruments/galileo.py,sha256=yQBedd7dmDnwuWi1MtXOsg4-RyRx0uRAXumCY4YuH9k,4686
44
44
  cloudnetpy/instruments/hatpro.py,sha256=DzCWzTJxTc5BSOgoeyM8RjYkSXX6NDi3QXgKRp0uxlI,8759
45
- cloudnetpy/instruments/instruments.py,sha256=jG5TYnZ8bdCZXnI303ZsaJBEdSKaIjKMbkGtnq6kQX0,3261
45
+ cloudnetpy/instruments/instruments.py,sha256=QPhaQ6Eh6gSuPWQ97Zk3gkCwzT57u3kBlk7-BcoR-jo,3413
46
46
  cloudnetpy/instruments/lufft.py,sha256=ugXF6pssHAAz1Y_hqPdpKuluAjxxHSR88xBmQuS6RlI,3705
47
- cloudnetpy/instruments/mira.py,sha256=f679zjmIxLVVtUVSMeO5IWbEdaj6qOJu5Gf9MKQJSL8,9412
47
+ cloudnetpy/instruments/mira.py,sha256=zfpPLCJLRc11wB-ddkQC9JALdwz73EgVbknv8iDJtuE,9847
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=HP6PNR5Y4qB6Q2OhQAmxWbe5QTTwNlw39TOWpeUe_bI,7399
50
+ cloudnetpy/instruments/nc_radar.py,sha256=PM4XQm2Ri9pLOh2mt9dphjdXr1_aPKMFWp2T_hDNo3c,6730
51
51
  cloudnetpy/instruments/pollyxt.py,sha256=lkiBu8ChvLd86eCkeIGxHKwraeDQFuVSgCVlsAYTYN8,9010
52
52
  cloudnetpy/instruments/radiometrics.py,sha256=ySG4a042XkgjMTG8d20oAPNvFvw9bMwwiqS3zv-JF_w,11825
53
53
  cloudnetpy/instruments/rpg.py,sha256=IozvBJ8_qXTPqtp58FQwRsoI5_aI3-kycpXugZkS0d4,17462
@@ -101,7 +101,7 @@ cloudnetpy/model_evaluation/tests/unit/test_statistical_methods.py,sha256=Ra3r4V
101
101
  cloudnetpy/model_evaluation/tests/unit/test_tools.py,sha256=Ia_VrLdV2NstX5gbx_3AZTOAlrgLAy_xFZ8fHYVX0xI,3817
102
102
  cloudnetpy/plotting/__init__.py,sha256=lg9Smn4BI0dVBgnDLC3JVJ4GmwoSnO-qoSd4ApvwV6Y,107
103
103
  cloudnetpy/plotting/plot_meta.py,sha256=d7CIT4ltUsjKw0HNnOXPkaLdZbkSmTuq6AbKdbODfZE,16730
104
- cloudnetpy/plotting/plotting.py,sha256=ufFKChNK9Z6uRRBtMLT5AvZiyWiakPLGgC9OHWaC8Z0,35504
104
+ cloudnetpy/plotting/plotting.py,sha256=KcvYCw2FaFeunAjaisbm-zxi1YFMiJeW8ni3J_yBuD4,35812
105
105
  cloudnetpy/products/__init__.py,sha256=2hRb5HG9hNrxH1if5laJkLeFeaZCd5W1q3hh4ewsX0E,273
106
106
  cloudnetpy/products/classification.py,sha256=KwAiBSgFwDqhM114NIgYiUjj8HoYc7gAlc8E1QgcSig,8207
107
107
  cloudnetpy/products/der.py,sha256=soypE7uSEP4uHUCCQVEhyXsKY6e9mzV9B_2S5GUizqk,12729
@@ -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=01Zc6xV8CSuYcIcLpchFf5POL3_c629-YMNDZJ51udA,10853
117
117
  docs/source/conf.py,sha256=IKiFWw6xhUd8NrCg0q7l596Ck1d61XWeVjIFHVSG9Og,1490
118
- cloudnetpy-1.66.17.dist-info/LICENSE,sha256=wcZF72bdaoG9XugpyE95Juo7lBQOwLuTKBOhhtANZMM,1094
119
- cloudnetpy-1.66.17.dist-info/METADATA,sha256=oQg4KOesIN8UvulDIPye5gt2VrnZr5IcITc5yPFEot8,5794
120
- cloudnetpy-1.66.17.dist-info/WHEEL,sha256=PZUExdf71Ui_so67QXpySuHtCi3-J3wvF4ORK6k_S8U,91
121
- cloudnetpy-1.66.17.dist-info/entry_points.txt,sha256=HhY7LwCFk4qFgDlXx_Fy983ZTd831WlhtdPIzV-Y3dY,51
122
- cloudnetpy-1.66.17.dist-info/top_level.txt,sha256=ibSPWRr6ojS1i11rtBFz2_gkIe68mggj7aeswYfaOo0,16
123
- cloudnetpy-1.66.17.dist-info/RECORD,,
118
+ cloudnetpy-1.66.19.dist-info/LICENSE,sha256=wcZF72bdaoG9XugpyE95Juo7lBQOwLuTKBOhhtANZMM,1094
119
+ cloudnetpy-1.66.19.dist-info/METADATA,sha256=5qIRCwOdmWKJeIztby_B29Qz68rRRr81WJoCnmPfDBk,5794
120
+ cloudnetpy-1.66.19.dist-info/WHEEL,sha256=PZUExdf71Ui_so67QXpySuHtCi3-J3wvF4ORK6k_S8U,91
121
+ cloudnetpy-1.66.19.dist-info/entry_points.txt,sha256=HhY7LwCFk4qFgDlXx_Fy983ZTd831WlhtdPIzV-Y3dY,51
122
+ cloudnetpy-1.66.19.dist-info/top_level.txt,sha256=ibSPWRr6ojS1i11rtBFz2_gkIe68mggj7aeswYfaOo0,16
123
+ cloudnetpy-1.66.19.dist-info/RECORD,,