cloudnetpy 1.56.4__py3-none-any.whl → 1.56.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.
@@ -4,10 +4,10 @@ import logging
4
4
  from collections import defaultdict
5
5
  from pathlib import Path
6
6
 
7
- import mwrpy
8
7
  import netCDF4
9
8
  import numpy as np
10
9
  from mwrpy.level1.lev1_meta_nc import ATTRIBUTES_1B01
10
+ from mwrpy.level1.write_lev1_nc import lev1_to_nc
11
11
  from mwrpy.version import __version__ as mwrpy_version
12
12
  from numpy import ma
13
13
 
@@ -45,7 +45,7 @@ def hatpro2l1c(
45
45
  """
46
46
  coeff_files = site_meta.get("coefficientFiles", None)
47
47
 
48
- hatpro_raw = mwrpy.lev1_to_nc(
48
+ hatpro_raw = lev1_to_nc(
49
49
  "1C01",
50
50
  mwr_dir,
51
51
  output_file=output_file,
@@ -99,7 +99,7 @@ def hatpro2l1c(
99
99
 
100
100
 
101
101
  class HatproL1c:
102
- def __init__(self, hatpro: mwrpy.Rpg, site_meta: dict):
102
+ def __init__(self, hatpro, site_meta: dict):
103
103
  self.raw_data = hatpro.raw_data
104
104
  self.data = hatpro.data
105
105
  self.date = hatpro.date.split("-")
@@ -224,12 +224,19 @@ ATTRIBUTES = {
224
224
  ),
225
225
  "potential_temperature": PlotMeta(
226
226
  cmap="RdBu_r",
227
- plot_range=(260, 330),
227
+ plot_range=(260, 320),
228
+ ),
229
+ "equivalent_potential_temperature": PlotMeta(
230
+ cmap="RdBu_r",
231
+ plot_range=(260, 320),
228
232
  ),
229
233
  "absolute_humidity": PlotMeta(
230
- plot_range=(1e-5, 1e-2),
234
+ plot_range=(1e-4, 1e-2),
231
235
  log_scale=True,
232
236
  ),
237
+ "relative_humidity": PlotMeta(
238
+ plot_range=(0, 120),
239
+ ),
233
240
  "cloud_fraction": PlotMeta(
234
241
  cmap="Blues",
235
242
  plot_range=(0, 1),
@@ -143,6 +143,10 @@ class FigureData:
143
143
  return self.file.variables["range"][:] * m2km
144
144
  return None
145
145
 
146
+ def is_mwrpy_product(self) -> bool:
147
+ cloudnet_file_type = getattr(self.file, "cloudnet_file_type", "")
148
+ return cloudnet_file_type in ("mwr-single", "mwr-multi")
149
+
146
150
  def __len__(self) -> int:
147
151
  return len(self.variables)
148
152
 
@@ -177,7 +181,7 @@ class SubPlot:
177
181
  ylabel: str | None = None,
178
182
  y_limits: tuple[float, float] | None = None,
179
183
  ) -> None:
180
- label = ylabel or "Height (km)"
184
+ label = ylabel if ylabel is not None else "Height (km)"
181
185
  self.ax.set_ylabel(label, fontsize=13)
182
186
  if y_limits is not None:
183
187
  self.ax.set_ylim(*y_limits)
@@ -236,9 +240,7 @@ class SubPlot:
236
240
  if self.options.plot_meta is not None:
237
241
  return self.options.plot_meta
238
242
  fallback = ATTRIBUTES["fallback"].get(self.variable.name, PlotMeta())
239
- if file_type is None:
240
- return fallback
241
- file_attributes = ATTRIBUTES.get(file_type, {})
243
+ file_attributes = ATTRIBUTES.get(file_type or "", {})
242
244
  plot_meta = file_attributes.get(self.variable.name, fallback)
243
245
  if plot_meta.clabel is None:
244
246
  plot_meta = plot_meta._replace(clabel=_reformat_units(self.variable.units))
@@ -249,10 +251,32 @@ class Plot:
249
251
  def __init__(self, sub_plot: SubPlot):
250
252
  self.sub_plot = sub_plot
251
253
  self._data = sub_plot.variable[:]
254
+ self._data_orig = self._data.copy()
252
255
  self._plot_meta = sub_plot.plot_meta
253
256
  self._is_log = sub_plot.plot_meta.log_scale
254
257
  self._ax = sub_plot.ax
255
258
 
259
+ def _convert_units(self) -> str | None:
260
+ multiply, add = "multiply", "add"
261
+ units_conversion = {
262
+ "rainfall_rate": (multiply, 360000, "mm h$^{-1}$"),
263
+ "air_pressure": (multiply, 0.01, "hPa"),
264
+ "relative_humidity": (multiply, 100, "%"),
265
+ "rainfall_amount": (multiply, 1000, "mm"),
266
+ "air_temperature": (add, -273.15, "\u00B0C"),
267
+ }
268
+ conversion_method, conversion, units = units_conversion.get(
269
+ self.sub_plot.variable.name, (multiply, 1, None)
270
+ )
271
+ if conversion_method == multiply:
272
+ self._data *= conversion
273
+ elif conversion_method == add:
274
+ self._data += conversion
275
+ if units is not None:
276
+ return units
277
+ units = getattr(self.sub_plot.variable, "units", "")
278
+ return _reformat_units(units)
279
+
256
280
  def _get_y_limits(self) -> tuple[float, float]:
257
281
  return 0, self.sub_plot.options.max_y
258
282
 
@@ -273,6 +297,7 @@ class Plot:
273
297
  facecolor="grey",
274
298
  edgecolor="black",
275
299
  alpha=0.15,
300
+ label="_nolegend_",
276
301
  )
277
302
 
278
303
  def _mark_gaps(self, figure_data: FigureData) -> None:
@@ -282,6 +307,10 @@ class Plot:
282
307
  msg = "Time values outside the range 0-24."
283
308
  raise ValueError(msg)
284
309
  max_gap_fraction_hour = _get_max_gap_in_minutes(figure_data) / 60
310
+
311
+ if figure_data.file.cloudnet_file_type == "model":
312
+ time, data = self._get_unmasked_model_values(time, data)
313
+
285
314
  gap_indices = np.where(np.diff(time) > max_gap_fraction_hour)[0]
286
315
  if not ma.is_masked(data):
287
316
  mask_new = np.zeros(data.shape)
@@ -319,9 +348,26 @@ class Plot:
319
348
  self._data = data_new
320
349
  figure_data.time_including_gaps = time_new
321
350
 
351
+ @staticmethod
352
+ def _get_unmasked_model_values(time: np.ndarray, data: ma.MaskedArray) -> tuple:
353
+ good_ind = np.where(np.any(~data.mask, axis=1))[0]
354
+ if len(good_ind) == 0:
355
+ msg = "No unmasked values in the file."
356
+ raise ValueError(msg)
357
+ good_ind = np.append(good_ind, good_ind[-1] + 1)
358
+ good_ind = np.clip(good_ind, 0, len(time) - 1)
359
+ return time[good_ind], data[good_ind, :]
360
+
361
+ def _read_flags(self, figure_data: FigureData) -> np.ndarray:
362
+ flag_name = f"{self.sub_plot.variable.name}_quality_flag"
363
+ if flag_name not in figure_data.variables:
364
+ flag_name = "temperature_quality_flag"
365
+ return figure_data.file.variables[flag_name][:] > 0
366
+
322
367
 
323
368
  class Plot2D(Plot):
324
369
  def plot(self, figure_data: FigureData):
370
+ self._convert_units()
325
371
  self._mark_gaps(figure_data)
326
372
  if self.sub_plot.variable.name == "cloud_fraction":
327
373
  self._data[self._data == 0] = ma.masked
@@ -335,6 +381,26 @@ class Plot2D(Plot):
335
381
  if figure_data.options.mark_data_gaps:
336
382
  self._fill_between_data_gaps(figure_data)
337
383
 
384
+ if figure_data.is_mwrpy_product():
385
+ self._fill_flagged_data(figure_data)
386
+
387
+ def _fill_flagged_data(self, figure_data: FigureData) -> None:
388
+ flags = self._read_flags(figure_data)
389
+ batches = find_batches_of_ones(flags)
390
+ for batch in batches:
391
+ if batch[0] == batch[1]:
392
+ continue
393
+ time_batch = figure_data.time[batch[0]], figure_data.time[batch[1]]
394
+ self._ax.fill_between(
395
+ time_batch,
396
+ *self._get_y_limits(),
397
+ facecolor="mistyrose",
398
+ alpha=1,
399
+ hatch=r"\\",
400
+ edgecolor="lightsalmon",
401
+ label="_nolegend_",
402
+ )
403
+
338
404
  def _plot_segment_data(self, figure_data: FigureData) -> None:
339
405
  def _hide_segments(
340
406
  data_in: ma.MaskedArray,
@@ -405,20 +471,27 @@ class Plot2D(Plot):
405
471
  class Plot1D(Plot):
406
472
  def plot_tb(self, figure_data: FigureData, ind: int):
407
473
  flagged_data = self._pointing_filter(figure_data, ind)
474
+ self.plot(figure_data)
475
+ if ma.count(flagged_data) > 0:
476
+ self.plot_flag_data(figure_data.time, flagged_data)
477
+ self.add_legend()
478
+
479
+ def plot_flag_data(self, time: np.ndarray, values: np.ndarray) -> None:
408
480
  self._ax.plot(
409
- figure_data.time,
410
- flagged_data,
481
+ time,
482
+ values,
411
483
  color="salmon",
412
484
  marker=".",
413
485
  lw=0,
414
486
  markersize=3,
487
+ zorder=10,
415
488
  )
416
- self.plot(figure_data)
489
+
490
+ def add_legend(self):
417
491
  self._ax.legend(
418
- ["Flagged data", "Valid data"],
492
+ ["Flagged data"],
419
493
  markerscale=3,
420
494
  numpoints=1,
421
- reverse=True,
422
495
  frameon=False,
423
496
  )
424
497
 
@@ -428,6 +501,7 @@ class Plot1D(Plot):
428
501
  self._ax.plot(
429
502
  figure_data.time_including_gaps,
430
503
  self._data,
504
+ label="_nolegend_",
431
505
  **self._get_plot_options(),
432
506
  )
433
507
  if self._plot_meta.moving_average:
@@ -436,6 +510,11 @@ class Plot1D(Plot):
436
510
  self.sub_plot.set_yax(ylabel=units, y_limits=self._get_y_limits())
437
511
  pos = self._ax.get_position()
438
512
  self._ax.set_position((pos.x0, pos.y0, pos.width * 0.965, pos.height))
513
+ if figure_data.is_mwrpy_product():
514
+ flags = self._read_flags(figure_data)
515
+ if np.any(flags):
516
+ self.plot_flag_data(figure_data.time[flags], self._data_orig[flags])
517
+ self.add_legend()
439
518
 
440
519
  def _get_y_limits(self) -> tuple[float, float]:
441
520
  percent_gap = 0.05
@@ -452,26 +531,6 @@ class Plot1D(Plot):
452
531
  return fallback
453
532
  return min_y, max_y
454
533
 
455
- def _convert_units(self) -> str | None:
456
- multiply, add = "multiply", "add"
457
- units_conversion = {
458
- "rainfall_rate": (multiply, 360000, "mm h$^{-1}$"),
459
- "air_pressure": (multiply, 0.01, "hPa"),
460
- "relative_humidity": (multiply, 100, "%"),
461
- "rainfall_amount": (multiply, 1000, "mm"),
462
- "air_temperature": (add, -273.15, "\u00B0C"),
463
- }
464
- conversion_method, conversion, units = units_conversion.get(
465
- self.sub_plot.variable.name, (multiply, 1, None)
466
- )
467
- if conversion_method == multiply:
468
- self._data *= conversion
469
- elif conversion_method == add:
470
- self._data += conversion
471
- if units is not None:
472
- return units
473
- return _reformat_units(self.sub_plot.variable.units)
474
-
475
534
  def _get_plot_options(self) -> dict:
476
535
  default_options = {
477
536
  "color": "lightblue",
@@ -503,7 +562,7 @@ class Plot1D(Plot):
503
562
  gap_time = _get_max_gap_in_minutes(figure_data)
504
563
  gaps = self._find_time_gap_indices(time, max_gap_min=gap_time)
505
564
  sma[gaps] = np.nan
506
- self._ax.plot(time, sma, color="slateblue", lw=2)
565
+ self._ax.plot(time, sma, color="slateblue", lw=2, label="_nolegend_")
507
566
 
508
567
  @staticmethod
509
568
  def _get_unmasked_values(
@@ -633,6 +692,8 @@ def _reformat_units(unit: str) -> str:
633
692
  "sr-1 m-1": "sr$^{-1}$ m$^{-1}$",
634
693
  "kg m-2": "kg m$^{-2}$",
635
694
  "kg m-3": "kg m$^{-3}$",
695
+ "g m-3": "g m$^{-3}$",
696
+ "g m-2": "g m$^{-2}$",
636
697
  "kg m-2 s-1": "kg m$^{-2}$ s$^{-1}$",
637
698
  "dB km-1": "dB km$^{-1}$",
638
699
  "rad km-1": "rad km$^{-1}$",
@@ -682,3 +743,10 @@ def plot_2d(
682
743
  if xlim is not None:
683
744
  plt.xlim(xlim)
684
745
  plt.show()
746
+
747
+
748
+ def find_batches_of_ones(array: np.ndarray) -> list[tuple[int, int]]:
749
+ """Find batches of ones in a binary array."""
750
+ starts = np.where(np.diff(np.hstack(([0], array))) == 1)[0]
751
+ stops = np.where(np.diff(np.hstack((array, [0]))) == -1)[0]
752
+ return list(zip(starts, stops, strict=True))
@@ -4,3 +4,4 @@ from .drizzle import generate_drizzle
4
4
  from .ier import generate_ier
5
5
  from .iwc import generate_iwc
6
6
  from .lwc import generate_lwc
7
+ from .mwr_tools import generate_mwr_multi, generate_mwr_single
@@ -0,0 +1,127 @@
1
+ import tempfile
2
+ from typing import Literal
3
+
4
+ import netCDF4
5
+ from mwrpy.level2.lev2_collocated import generate_lev2_multi as gen_multi
6
+ from mwrpy.level2.lev2_collocated import generate_lev2_single as gen_single
7
+ from mwrpy.version import __version__ as mwrpy_version
8
+
9
+ from cloudnetpy import output, utils
10
+ from cloudnetpy.products import product_tools
11
+
12
+
13
+ def generate_mwr_single(
14
+ mwr_l1c_file: str, output_file: str, uuid: str | None = None
15
+ ) -> str:
16
+ """
17
+ Generates MWR single-pointing product including liquid water path, integrated
18
+ water vapor, etc. from zenith measurements.
19
+
20
+ Args:
21
+ mwr_l1c_file: The Level 1C MWR file to be processed.
22
+ output_file: The file path where the output file should be saved.
23
+ uuid: The UUID, if any, associated with the output file. Defaults to None.
24
+
25
+ Returns:
26
+ UUID of generated file.
27
+
28
+ Example:
29
+ >>> generate_mwr_single('input_mwr_l1c_file', 'output_file', 'abcdefg1234567')
30
+ """
31
+ return _generate_product(mwr_l1c_file, output_file, uuid, "single")
32
+
33
+
34
+ def generate_mwr_multi(
35
+ mwr_l1c_file: str, output_file: str, uuid: str | None = None
36
+ ) -> str:
37
+ """
38
+ Generates MWR multiple-pointing product, including relative humidity profiles,
39
+ etc. from scanning measurements.
40
+
41
+ Args:
42
+ mwr_l1c_file: The input file in MWR L1C format.
43
+ output_file: The location where the output file should be generated.
44
+ uuid: The UUID for the MWR multi product, defaults to None if
45
+ not provided.
46
+
47
+ Returns:
48
+ UUID of generated file.
49
+ """
50
+ return _generate_product(mwr_l1c_file, output_file, uuid, "multi")
51
+
52
+
53
+ def _generate_product(
54
+ mwr_l1c_file: str,
55
+ output_file: str,
56
+ uuid: str | None,
57
+ product: Literal["multi", "single"],
58
+ ) -> str:
59
+ fun = gen_multi if product == "multi" else gen_single
60
+ with tempfile.TemporaryDirectory() as temp_dir:
61
+ coeffs = product_tools.get_read_mwrpy_coeffs(mwr_l1c_file, temp_dir)
62
+ fun(None, mwr_l1c_file, output_file, coeff_files=coeffs)
63
+ with (
64
+ netCDF4.Dataset(mwr_l1c_file, "r") as nc_input,
65
+ netCDF4.Dataset(output_file, "r+") as nc_output,
66
+ ):
67
+ mwr = Mwr(nc_input, nc_output, uuid)
68
+ return mwr.harmonize(product)
69
+
70
+
71
+ class Mwr:
72
+ def __init__(
73
+ self, nc_l1c: netCDF4.Dataset, nc_l2: netCDF4.Dataset, uuid: str | None
74
+ ):
75
+ self.nc_l1c = nc_l1c
76
+ self.nc_l2 = nc_l2
77
+ self.uuid = uuid if uuid is not None else utils.get_uuid()
78
+
79
+ def harmonize(self, product: Literal["multi", "single"]) -> str:
80
+ self._truncate_global_attributes()
81
+ self._copy_variable_values()
82
+ self._copy_global_attributes()
83
+ self._fix_variable_attributes()
84
+ self._write_missing_global_attributes(product)
85
+ return self.uuid
86
+
87
+ def _truncate_global_attributes(self):
88
+ for attr in self.nc_l2.ncattrs():
89
+ delattr(self.nc_l2, attr)
90
+
91
+ def _copy_variable_values(self):
92
+ keys = ("latitude", "longitude", "altitude")
93
+ for var in keys:
94
+ if var in self.nc_l2.variables:
95
+ self.nc_l2.variables[var][:] = self.nc_l1c.variables[var][:]
96
+
97
+ def _copy_global_attributes(self):
98
+ keys = ("year", "month", "day", "location", "source")
99
+ output.copy_global(self.nc_l1c, self.nc_l2, keys)
100
+
101
+ def _fix_variable_attributes(self):
102
+ output.replace_attribute_with_standard_value(
103
+ self.nc_l2,
104
+ (
105
+ "lwp",
106
+ "iwv",
107
+ "temperature",
108
+ "azimuth_angle",
109
+ "latitude",
110
+ "longitude",
111
+ "altitude",
112
+ ),
113
+ ("units", "long_name", "standard_name"),
114
+ )
115
+
116
+ def _write_missing_global_attributes(self, product: Literal["multi", "single"]):
117
+ output.add_standard_global_attributes(self.nc_l2, self.uuid)
118
+ product_type = "multiple-pointing" if product == "multi" else "single-pointing"
119
+ self.nc_l2.title = f"MWR {product_type} from {self.nc_l1c.location}"
120
+ self.nc_l2.cloudnet_file_type = f"mwr-{product}"
121
+ output.fix_time_attributes(self.nc_l2)
122
+ self.nc_l2.history = (
123
+ f"{utils.get_time()} - MWR {product_type} file created \n"
124
+ f"{self.nc_l1c.history}"
125
+ )
126
+ self.nc_l2.source_file_uuids = self.nc_l1c.file_uuid
127
+ self.nc_l2.mwrpy_version = mwrpy_version
cloudnetpy/version.py CHANGED
@@ -1,4 +1,4 @@
1
1
  MAJOR = 1
2
2
  MINOR = 56
3
- PATCH = 4
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.56.4
3
+ Version: 1.56.5
4
4
  Summary: Python package for Cloudnet processing
5
5
  Author: Simo Tukiainen
6
6
  License: MIT License
@@ -8,7 +8,7 @@ cloudnetpy/metadata.py,sha256=Bcu1a9UyUq61jomuZ0_6hYIOzf61e5qCXeiwLm46ikw,5040
8
8
  cloudnetpy/output.py,sha256=jD1pfBb4OQhVOrlhPEk-8FAi4bUW7zjAL468r6BPkJg,14586
9
9
  cloudnetpy/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
10
10
  cloudnetpy/utils.py,sha256=yY5a5HLuAks2uzA4XbbqsGFEmXoyqECn_TjD3sMa0lI,27193
11
- cloudnetpy/version.py,sha256=lnEVFXHSKtSjA3iEu1JkOORO-IrhXQfth6GZQDdyhv4,72
11
+ cloudnetpy/version.py,sha256=6cv25AS5sFm-DzOvNw4RB7-2flKWgFkjLMkIKHBnLD0,72
12
12
  cloudnetpy/categorize/__init__.py,sha256=gP5q3Vis1y9u9OWgA_idlbjfWXYN_S0IBSWdwBhL_uU,69
13
13
  cloudnetpy/categorize/atmos.py,sha256=cax3iRmvr7S-VkUZqz0JCfAN3WEsUVbGfH4zSHy1APo,12384
14
14
  cloudnetpy/categorize/atmos_utils.py,sha256=wndpwJxc2-QnNTkV8tc8I11Vs_WkNz9sVMX1fuGgUC4,3777
@@ -33,7 +33,7 @@ cloudnetpy/instruments/cl61d.py,sha256=ycJGvUqNU2KHhECbrSehtWRnvg1vKFHhvMeQpjpdC
33
33
  cloudnetpy/instruments/cloudnet_instrument.py,sha256=RG5HJxGM6p0F-IGyr85fvOizcMmgx48OeD_XeIsrgSU,3367
34
34
  cloudnetpy/instruments/copernicus.py,sha256=AT0AtMhGSKzPWEqXsfAda6zeaw4g0Jr5dqIyfeu4FP0,6327
35
35
  cloudnetpy/instruments/galileo.py,sha256=FyFYh1JhWed1d6yvpsv3rdBzHUTjkfOPw5HEQz4Wssw,4545
36
- cloudnetpy/instruments/hatpro.py,sha256=TK-7KcpI7E1ErEq9XmQzJPEqoenjOePfkieD0ybEPW4,8099
36
+ cloudnetpy/instruments/hatpro.py,sha256=TEwPyUsT8J17uDPwcB5B8nPDo0f6UAvg5bDjG8tKLdA,8119
37
37
  cloudnetpy/instruments/instruments.py,sha256=GcUEbQFPHUhRTnp300AZ2PK0O2d2EPIGtHqCX6dy99M,3133
38
38
  cloudnetpy/instruments/lufft.py,sha256=nozeiMRMz7I6q_FwmlxDGhWeJlqTuNh6ru39-M4K3BI,3629
39
39
  cloudnetpy/instruments/mira.py,sha256=TfozpYivQAThZ_rV3gLzZpz2QyJFWOF0RXdzA4521rM,9332
@@ -91,9 +91,9 @@ cloudnetpy/model_evaluation/tests/unit/test_plotting.py,sha256=h9V8JKmrO4v9bOvv-
91
91
  cloudnetpy/model_evaluation/tests/unit/test_statistical_methods.py,sha256=Ra3r4V0qbqkpDuaTYvEIbaasl0nZ5gmTLR4eGC0glBQ,9724
92
92
  cloudnetpy/model_evaluation/tests/unit/test_tools.py,sha256=Ia_VrLdV2NstX5gbx_3AZTOAlrgLAy_xFZ8fHYVX0xI,3817
93
93
  cloudnetpy/plotting/__init__.py,sha256=2-8x8d1AfAhfU15RwWhusD0Wot_g6Ob_jJoywbrTC7A,95
94
- cloudnetpy/plotting/plot_meta.py,sha256=WNTeSEpACN5vV1omoZfXtRdIxrohYHJU3v2lHjspQRM,12823
95
- cloudnetpy/plotting/plotting.py,sha256=Br5rBWZtP14moM81LdMs0mb-NhDFVAcRizOYlg8edb8,23933
96
- cloudnetpy/products/__init__.py,sha256=hGkngQT-YAC5cmDiHkSkQw2ZBrg0hN2z40Fizz0QU5Y,210
94
+ cloudnetpy/plotting/plot_meta.py,sha256=xbiEU9Okx5L_WG7KtVnljxjpCYcgqyOLywBc49gibSQ,13033
95
+ cloudnetpy/plotting/plotting.py,sha256=jUn64USNApkL_c6FXAr30hW2Xc_M8WZthqVgjuCgN0M,26667
96
+ cloudnetpy/products/__init__.py,sha256=2hRb5HG9hNrxH1if5laJkLeFeaZCd5W1q3hh4ewsX0E,273
97
97
  cloudnetpy/products/classification.py,sha256=J_FOMUSyxvFaT-hvdKVVcKPtuQ0u3V9PsV5xaIKzMjg,7843
98
98
  cloudnetpy/products/der.py,sha256=HAdPvbJySEqkIwDrdZDPnli_wnN2qwm72_D1a82ZWIs,12398
99
99
  cloudnetpy/products/drizzle.py,sha256=BY2HvJeWt_ps6KKCGXwUUNRTy78q0cQM8bOCCoj8TWA,10803
@@ -103,12 +103,11 @@ cloudnetpy/products/ier.py,sha256=IcGPlQahbwJjp3vOOrxWSYW2FPzbSV0KQL5eYECc4kU,77
103
103
  cloudnetpy/products/iwc.py,sha256=MUPuVKWgqOuuLRCGk3QY74uBZB_7P1qlinlP8nEvz9o,10124
104
104
  cloudnetpy/products/lwc.py,sha256=TbIR6kMwjbm63ed5orB1pkqx9ZBm8C5TF2JmT8WKdKI,18794
105
105
  cloudnetpy/products/mie_lu_tables.nc,sha256=It4fYpqJXlqOgL8jeZ-PxGzP08PMrELIDVe55y9ob58,16637951
106
- cloudnetpy/products/mwr_multi.py,sha256=mRMzdDhTddhPLBcDiG_2kw_BSRL_01hA9-o4-cmaVaQ,3301
107
- cloudnetpy/products/mwr_single.py,sha256=4KyxeFg7AphEJg5P7ey8SXacyNAG3PGDOvnksvZj3R8,3168
106
+ cloudnetpy/products/mwr_tools.py,sha256=TsVEqNwzoDv90TgzUSnJjMuc3C1KQ-hwsIZ8t0IdDJ4,4407
108
107
  cloudnetpy/products/product_tools.py,sha256=E8CSijBY8cr70BH2JFa0lGQ-RzI9EcHQ0Fzt8CQ8rY4,10442
109
108
  docs/source/conf.py,sha256=IKiFWw6xhUd8NrCg0q7l596Ck1d61XWeVjIFHVSG9Og,1490
110
- cloudnetpy-1.56.4.dist-info/LICENSE,sha256=wcZF72bdaoG9XugpyE95Juo7lBQOwLuTKBOhhtANZMM,1094
111
- cloudnetpy-1.56.4.dist-info/METADATA,sha256=R6YZSD8wmlEcw9Oz2cnyWjGz5YAltO9g3OT0ZQblaH0,5733
112
- cloudnetpy-1.56.4.dist-info/WHEEL,sha256=oiQVh_5PnQM0E3gPdiz09WCNmwiHDMaGer_elqB3coM,92
113
- cloudnetpy-1.56.4.dist-info/top_level.txt,sha256=ibSPWRr6ojS1i11rtBFz2_gkIe68mggj7aeswYfaOo0,16
114
- cloudnetpy-1.56.4.dist-info/RECORD,,
109
+ cloudnetpy-1.56.5.dist-info/LICENSE,sha256=wcZF72bdaoG9XugpyE95Juo7lBQOwLuTKBOhhtANZMM,1094
110
+ cloudnetpy-1.56.5.dist-info/METADATA,sha256=x8u7BhZ4EiuxFV80zTN-LaHuqkAU8TKlOMLR0FAzCHo,5733
111
+ cloudnetpy-1.56.5.dist-info/WHEEL,sha256=oiQVh_5PnQM0E3gPdiz09WCNmwiHDMaGer_elqB3coM,92
112
+ cloudnetpy-1.56.5.dist-info/top_level.txt,sha256=ibSPWRr6ojS1i11rtBFz2_gkIe68mggj7aeswYfaOo0,16
113
+ cloudnetpy-1.56.5.dist-info/RECORD,,
@@ -1,82 +0,0 @@
1
- import tempfile
2
- from tempfile import NamedTemporaryFile
3
-
4
- import netCDF4
5
- from mwrpy.level2.write_lev2_nc import MissingInputData, lev2_to_nc
6
- from mwrpy.version import __version__ as mwrpy_version
7
-
8
- from cloudnetpy import output, utils
9
- from cloudnetpy.exceptions import MissingInputFileError
10
- from cloudnetpy.products import product_tools
11
-
12
-
13
- def generate_mwr_multi(
14
- mwr_l1c_file: str,
15
- output_file: str,
16
- uuid: str | None = None,
17
- ) -> str:
18
- file_uuid = uuid if uuid is not None else utils.get_uuid()
19
-
20
- with (
21
- NamedTemporaryFile() as temp_file,
22
- NamedTemporaryFile() as abs_hum_file,
23
- NamedTemporaryFile() as rel_hum_file,
24
- NamedTemporaryFile() as t_pot_file,
25
- NamedTemporaryFile() as eq_temp_file,
26
- tempfile.TemporaryDirectory() as temp_dir,
27
- ):
28
- coeffs = product_tools.get_read_mwrpy_coeffs(mwr_l1c_file, temp_dir)
29
-
30
- for prod, file in zip(
31
- ("2P02", "2P03", "2P04", "2P07", "2P08"),
32
- (temp_file, abs_hum_file, rel_hum_file, t_pot_file, eq_temp_file),
33
- strict=True,
34
- ):
35
- try:
36
- lev2_to_nc(
37
- prod,
38
- mwr_l1c_file,
39
- file.name,
40
- coeff_files=coeffs,
41
- temp_file=temp_file.name if prod not in ("2P02", "2P03") else None,
42
- hum_file=abs_hum_file.name
43
- if prod not in ("2P02", "2P03")
44
- else None,
45
- )
46
- except MissingInputData as err:
47
- raise MissingInputFileError from err
48
-
49
- with (
50
- netCDF4.Dataset(output_file, "w", format="NETCDF4_CLASSIC") as nc_output,
51
- netCDF4.Dataset(mwr_l1c_file, "r") as nc_l1c,
52
- netCDF4.Dataset(temp_file.name, "r") as nc_temp,
53
- netCDF4.Dataset(rel_hum_file.name, "r") as nc_rel_hum,
54
- netCDF4.Dataset(t_pot_file.name, "r") as nc_t_pot,
55
- netCDF4.Dataset(eq_temp_file.name, "r") as nc_eq_temp,
56
- ):
57
- nc_output.createDimension("time", len(nc_temp.variables["time"][:]))
58
- nc_output.createDimension("height", len(nc_temp.variables["height"][:]))
59
-
60
- for source, variables in (
61
- (nc_l1c, ("latitude", "longitude", "altitude")),
62
- (nc_temp, ("time", "height", "temperature")),
63
- (nc_rel_hum, ("relative_humidity",)),
64
- (nc_t_pot, ("potential_temperature",)),
65
- (nc_eq_temp, ("equivalent_potential_temperature",)),
66
- ):
67
- output.copy_variables(source, nc_output, variables)
68
-
69
- output.add_standard_global_attributes(nc_output, file_uuid)
70
- output.copy_global(nc_l1c, nc_output, ("year", "month", "day", "location"))
71
- nc_output.title = f"MWR multiple-pointing from {nc_l1c.location}"
72
- nc_output.cloudnet_file_type = "mwr-multi"
73
- nc_output.mwrpy_version = mwrpy_version
74
- output.fix_time_attributes(nc_output)
75
- nc_output.history = (
76
- f"{utils.get_time()} - MWR multiple-pointing product created \n"
77
- f"{nc_l1c.history}"
78
- )
79
- nc_output.source_file_uuids = nc_l1c.file_uuid
80
- nc_output.source = nc_l1c.source
81
-
82
- return file_uuid
@@ -1,83 +0,0 @@
1
- import tempfile
2
- from tempfile import NamedTemporaryFile
3
-
4
- import netCDF4
5
- from mwrpy.level2.write_lev2_nc import lev2_to_nc
6
- from mwrpy.version import __version__ as mwrpy_version
7
-
8
- from cloudnetpy import output, utils
9
- from cloudnetpy.products import product_tools
10
-
11
-
12
- def generate_mwr_single(
13
- mwr_l1c_file: str,
14
- output_file: str,
15
- uuid: str | None = None,
16
- ) -> str:
17
- file_uuid = uuid if uuid is not None else utils.get_uuid()
18
-
19
- with (
20
- NamedTemporaryFile() as lwp_file,
21
- NamedTemporaryFile() as iwv_file,
22
- NamedTemporaryFile() as t_prof_file,
23
- NamedTemporaryFile() as abs_hum_file,
24
- tempfile.TemporaryDirectory() as temp_dir,
25
- ):
26
- coeffs = product_tools.get_read_mwrpy_coeffs(mwr_l1c_file, temp_dir)
27
-
28
- for prod, file in zip(
29
- ("2I01", "2I02", "2P01", "2P03"),
30
- (lwp_file, iwv_file, t_prof_file, abs_hum_file),
31
- strict=True,
32
- ):
33
- lev2_to_nc(prod, mwr_l1c_file, file.name, coeff_files=coeffs)
34
-
35
- with (
36
- netCDF4.Dataset(output_file, "w", format="NETCDF4_CLASSIC") as nc_output,
37
- netCDF4.Dataset(lwp_file.name, "r") as nc_lwp,
38
- netCDF4.Dataset(iwv_file.name, "r") as nc_iwv,
39
- netCDF4.Dataset(abs_hum_file.name, "r") as nc_hum,
40
- netCDF4.Dataset(t_prof_file.name, "r") as nc_t_prof,
41
- netCDF4.Dataset(mwr_l1c_file, "r") as nc_l1c,
42
- ):
43
- nc_output.createDimension("height", len(nc_t_prof.variables["height"][:]))
44
- nc_output.createDimension("time", len(nc_lwp.variables["time"][:]))
45
-
46
- for source, variables in (
47
- (nc_iwv, ("iwv",)),
48
- (nc_hum, ("absolute_humidity",)),
49
- (nc_t_prof, ("temperature", "height")),
50
- (nc_l1c, ("latitude", "longitude", "altitude")),
51
- (
52
- nc_lwp,
53
- (
54
- "time",
55
- "lwp",
56
- "lwp_random_error",
57
- "lwp_offset",
58
- "lwp_systematic_error",
59
- "azimuth_angle",
60
- ),
61
- ),
62
- ):
63
- output.copy_variables(source, nc_output, variables)
64
-
65
- output.add_standard_global_attributes(nc_output, file_uuid)
66
- output.copy_global(nc_l1c, nc_output, ("year", "month", "day", "location"))
67
- nc_output.title = f"MWR single-pointing from {nc_l1c.location}"
68
- nc_output.cloudnet_file_type = "mwr-single"
69
- nc_output.mwrpy_version = mwrpy_version
70
- output.fix_time_attributes(nc_output)
71
- output.replace_attribute_with_standard_value(
72
- nc_output,
73
- ("lwp", "iwv", "temperature", "azimuth_angle"),
74
- ("units", "long_name", "standard_name"),
75
- )
76
- nc_output.history = (
77
- f"{utils.get_time()} - MWR single-pointing product created \n"
78
- f"{nc_l1c.history}"
79
- )
80
- nc_output.source_file_uuids = nc_l1c.file_uuid
81
- nc_output.source = nc_l1c.source
82
-
83
- return file_uuid