cloudnetpy 1.95.4__tar.gz → 1.95.6__tar.gz

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.
Files changed (147) hide show
  1. {cloudnetpy-1.95.4/cloudnetpy.egg-info → cloudnetpy-1.95.6}/PKG-INFO +1 -1
  2. {cloudnetpy-1.95.4 → cloudnetpy-1.95.6}/cloudnetpy/arm.py +10 -3
  3. {cloudnetpy-1.95.4 → cloudnetpy-1.95.6}/cloudnetpy/categorize/categorize.py +11 -1
  4. {cloudnetpy-1.95.4 → cloudnetpy-1.95.6}/cloudnetpy/categorize/classify.py +3 -1
  5. {cloudnetpy-1.95.4 → cloudnetpy-1.95.6}/cloudnetpy/categorize/containers.py +2 -0
  6. {cloudnetpy-1.95.4 → cloudnetpy-1.95.6}/cloudnetpy/categorize/radar.py +10 -1
  7. {cloudnetpy-1.95.4 → cloudnetpy-1.95.6}/cloudnetpy/cli.py +18 -0
  8. {cloudnetpy-1.95.4 → cloudnetpy-1.95.6}/cloudnetpy/instruments/arm_ceilo.py +2 -0
  9. {cloudnetpy-1.95.4 → cloudnetpy-1.95.6}/cloudnetpy/instruments/kazr.py +57 -12
  10. {cloudnetpy-1.95.4 → cloudnetpy-1.95.6}/cloudnetpy/output.py +1 -0
  11. {cloudnetpy-1.95.4 → cloudnetpy-1.95.6}/cloudnetpy/plotting/plotting.py +9 -1
  12. {cloudnetpy-1.95.4 → cloudnetpy-1.95.6}/cloudnetpy/version.py +1 -1
  13. {cloudnetpy-1.95.4 → cloudnetpy-1.95.6/cloudnetpy.egg-info}/PKG-INFO +1 -1
  14. {cloudnetpy-1.95.4 → cloudnetpy-1.95.6}/LICENSE +0 -0
  15. {cloudnetpy-1.95.4 → cloudnetpy-1.95.6}/MANIFEST.in +0 -0
  16. {cloudnetpy-1.95.4 → cloudnetpy-1.95.6}/README.md +0 -0
  17. {cloudnetpy-1.95.4 → cloudnetpy-1.95.6}/cloudnetpy/__init__.py +0 -0
  18. {cloudnetpy-1.95.4 → cloudnetpy-1.95.6}/cloudnetpy/categorize/__init__.py +0 -0
  19. {cloudnetpy-1.95.4 → cloudnetpy-1.95.6}/cloudnetpy/categorize/atmos_utils.py +0 -0
  20. {cloudnetpy-1.95.4 → cloudnetpy-1.95.6}/cloudnetpy/categorize/attenuation.py +0 -0
  21. {cloudnetpy-1.95.4 → cloudnetpy-1.95.6}/cloudnetpy/categorize/attenuations/__init__.py +0 -0
  22. {cloudnetpy-1.95.4 → cloudnetpy-1.95.6}/cloudnetpy/categorize/attenuations/gas_attenuation.py +0 -0
  23. {cloudnetpy-1.95.4 → cloudnetpy-1.95.6}/cloudnetpy/categorize/attenuations/liquid_attenuation.py +0 -0
  24. {cloudnetpy-1.95.4 → cloudnetpy-1.95.6}/cloudnetpy/categorize/attenuations/melting_attenuation.py +0 -0
  25. {cloudnetpy-1.95.4 → cloudnetpy-1.95.6}/cloudnetpy/categorize/attenuations/rain_attenuation.py +0 -0
  26. {cloudnetpy-1.95.4 → cloudnetpy-1.95.6}/cloudnetpy/categorize/disdrometer.py +0 -0
  27. {cloudnetpy-1.95.4 → cloudnetpy-1.95.6}/cloudnetpy/categorize/droplet.py +0 -0
  28. {cloudnetpy-1.95.4 → cloudnetpy-1.95.6}/cloudnetpy/categorize/falling.py +0 -0
  29. {cloudnetpy-1.95.4 → cloudnetpy-1.95.6}/cloudnetpy/categorize/freezing.py +0 -0
  30. {cloudnetpy-1.95.4 → cloudnetpy-1.95.6}/cloudnetpy/categorize/insects.py +0 -0
  31. {cloudnetpy-1.95.4 → cloudnetpy-1.95.6}/cloudnetpy/categorize/lidar.py +0 -0
  32. {cloudnetpy-1.95.4 → cloudnetpy-1.95.6}/cloudnetpy/categorize/melting.py +0 -0
  33. {cloudnetpy-1.95.4 → cloudnetpy-1.95.6}/cloudnetpy/categorize/model.py +0 -0
  34. {cloudnetpy-1.95.4 → cloudnetpy-1.95.6}/cloudnetpy/categorize/mwr.py +0 -0
  35. {cloudnetpy-1.95.4 → cloudnetpy-1.95.6}/cloudnetpy/cloudnetarray.py +0 -0
  36. {cloudnetpy-1.95.4 → cloudnetpy-1.95.6}/cloudnetpy/concat_lib.py +0 -0
  37. {cloudnetpy-1.95.4 → cloudnetpy-1.95.6}/cloudnetpy/constants.py +0 -0
  38. {cloudnetpy-1.95.4 → cloudnetpy-1.95.6}/cloudnetpy/datasource.py +0 -0
  39. {cloudnetpy-1.95.4 → cloudnetpy-1.95.6}/cloudnetpy/disdronator/__init__.py +0 -0
  40. {cloudnetpy-1.95.4 → cloudnetpy-1.95.6}/cloudnetpy/disdronator/lpm.py +0 -0
  41. {cloudnetpy-1.95.4 → cloudnetpy-1.95.6}/cloudnetpy/disdronator/parsivel.py +0 -0
  42. {cloudnetpy-1.95.4 → cloudnetpy-1.95.6}/cloudnetpy/disdronator/process.py +0 -0
  43. {cloudnetpy-1.95.4 → cloudnetpy-1.95.6}/cloudnetpy/disdronator/rd80.py +0 -0
  44. {cloudnetpy-1.95.4 → cloudnetpy-1.95.6}/cloudnetpy/disdronator/utils.py +0 -0
  45. {cloudnetpy-1.95.4 → cloudnetpy-1.95.6}/cloudnetpy/exceptions.py +0 -0
  46. {cloudnetpy-1.95.4 → cloudnetpy-1.95.6}/cloudnetpy/instruments/__init__.py +0 -0
  47. {cloudnetpy-1.95.4 → cloudnetpy-1.95.6}/cloudnetpy/instruments/arm_ld.py +0 -0
  48. {cloudnetpy-1.95.4 → cloudnetpy-1.95.6}/cloudnetpy/instruments/arm_utils.py +0 -0
  49. {cloudnetpy-1.95.4 → cloudnetpy-1.95.6}/cloudnetpy/instruments/basta.py +0 -0
  50. {cloudnetpy-1.95.4 → cloudnetpy-1.95.6}/cloudnetpy/instruments/bowtie.py +0 -0
  51. {cloudnetpy-1.95.4 → cloudnetpy-1.95.6}/cloudnetpy/instruments/ceilo.py +0 -0
  52. {cloudnetpy-1.95.4 → cloudnetpy-1.95.6}/cloudnetpy/instruments/ceilometer.py +0 -0
  53. {cloudnetpy-1.95.4 → cloudnetpy-1.95.6}/cloudnetpy/instruments/cl61d.py +0 -0
  54. {cloudnetpy-1.95.4 → cloudnetpy-1.95.6}/cloudnetpy/instruments/cloudnet_instrument.py +0 -0
  55. {cloudnetpy-1.95.4 → cloudnetpy-1.95.6}/cloudnetpy/instruments/copernicus.py +0 -0
  56. {cloudnetpy-1.95.4 → cloudnetpy-1.95.6}/cloudnetpy/instruments/da10.py +0 -0
  57. {cloudnetpy-1.95.4 → cloudnetpy-1.95.6}/cloudnetpy/instruments/dealias.py +0 -0
  58. {cloudnetpy-1.95.4 → cloudnetpy-1.95.6}/cloudnetpy/instruments/disdrometer.py +0 -0
  59. {cloudnetpy-1.95.4 → cloudnetpy-1.95.6}/cloudnetpy/instruments/fd12p.py +0 -0
  60. {cloudnetpy-1.95.4 → cloudnetpy-1.95.6}/cloudnetpy/instruments/galileo.py +0 -0
  61. {cloudnetpy-1.95.4 → cloudnetpy-1.95.6}/cloudnetpy/instruments/hatpro.py +0 -0
  62. {cloudnetpy-1.95.4 → cloudnetpy-1.95.6}/cloudnetpy/instruments/instruments.py +0 -0
  63. {cloudnetpy-1.95.4 → cloudnetpy-1.95.6}/cloudnetpy/instruments/lufft.py +0 -0
  64. {cloudnetpy-1.95.4 → cloudnetpy-1.95.6}/cloudnetpy/instruments/mira.py +0 -0
  65. {cloudnetpy-1.95.4 → cloudnetpy-1.95.6}/cloudnetpy/instruments/mmcr.py +0 -0
  66. {cloudnetpy-1.95.4 → cloudnetpy-1.95.6}/cloudnetpy/instruments/mrr.py +0 -0
  67. {cloudnetpy-1.95.4 → cloudnetpy-1.95.6}/cloudnetpy/instruments/mwr3c.py +0 -0
  68. {cloudnetpy-1.95.4 → cloudnetpy-1.95.6}/cloudnetpy/instruments/mwrlos.py +0 -0
  69. {cloudnetpy-1.95.4 → cloudnetpy-1.95.6}/cloudnetpy/instruments/nc_lidar.py +0 -0
  70. {cloudnetpy-1.95.4 → cloudnetpy-1.95.6}/cloudnetpy/instruments/nc_radar.py +0 -0
  71. {cloudnetpy-1.95.4 → cloudnetpy-1.95.6}/cloudnetpy/instruments/pollyxt.py +0 -0
  72. {cloudnetpy-1.95.4 → cloudnetpy-1.95.6}/cloudnetpy/instruments/radiometrics.py +0 -0
  73. {cloudnetpy-1.95.4 → cloudnetpy-1.95.6}/cloudnetpy/instruments/rain_e_h3.py +0 -0
  74. {cloudnetpy-1.95.4 → cloudnetpy-1.95.6}/cloudnetpy/instruments/rpg.py +0 -0
  75. {cloudnetpy-1.95.4 → cloudnetpy-1.95.6}/cloudnetpy/instruments/rpg_reader.py +0 -0
  76. {cloudnetpy-1.95.4 → cloudnetpy-1.95.6}/cloudnetpy/instruments/toa5.py +0 -0
  77. {cloudnetpy-1.95.4 → cloudnetpy-1.95.6}/cloudnetpy/instruments/vaisala.py +0 -0
  78. {cloudnetpy-1.95.4 → cloudnetpy-1.95.6}/cloudnetpy/instruments/weather_radar.py +0 -0
  79. {cloudnetpy-1.95.4 → cloudnetpy-1.95.6}/cloudnetpy/instruments/weather_station.py +0 -0
  80. {cloudnetpy-1.95.4 → cloudnetpy-1.95.6}/cloudnetpy/metadata.py +0 -0
  81. {cloudnetpy-1.95.4 → cloudnetpy-1.95.6}/cloudnetpy/model_evaluation/__init__.py +0 -0
  82. {cloudnetpy-1.95.4 → cloudnetpy-1.95.6}/cloudnetpy/model_evaluation/file_handler.py +0 -0
  83. {cloudnetpy-1.95.4 → cloudnetpy-1.95.6}/cloudnetpy/model_evaluation/metadata.py +0 -0
  84. {cloudnetpy-1.95.4 → cloudnetpy-1.95.6}/cloudnetpy/model_evaluation/model_metadata.py +0 -0
  85. {cloudnetpy-1.95.4 → cloudnetpy-1.95.6}/cloudnetpy/model_evaluation/plotting/__init__.py +0 -0
  86. {cloudnetpy-1.95.4 → cloudnetpy-1.95.6}/cloudnetpy/model_evaluation/plotting/plot_meta.py +0 -0
  87. {cloudnetpy-1.95.4 → cloudnetpy-1.95.6}/cloudnetpy/model_evaluation/plotting/plot_tools.py +0 -0
  88. {cloudnetpy-1.95.4 → cloudnetpy-1.95.6}/cloudnetpy/model_evaluation/plotting/plotting.py +0 -0
  89. {cloudnetpy-1.95.4 → cloudnetpy-1.95.6}/cloudnetpy/model_evaluation/products/__init__.py +0 -0
  90. {cloudnetpy-1.95.4 → cloudnetpy-1.95.6}/cloudnetpy/model_evaluation/products/advance_methods.py +0 -0
  91. {cloudnetpy-1.95.4 → cloudnetpy-1.95.6}/cloudnetpy/model_evaluation/products/grid_methods.py +0 -0
  92. {cloudnetpy-1.95.4 → cloudnetpy-1.95.6}/cloudnetpy/model_evaluation/products/model_products.py +0 -0
  93. {cloudnetpy-1.95.4 → cloudnetpy-1.95.6}/cloudnetpy/model_evaluation/products/observation_products.py +0 -0
  94. {cloudnetpy-1.95.4 → cloudnetpy-1.95.6}/cloudnetpy/model_evaluation/products/product_resampling.py +0 -0
  95. {cloudnetpy-1.95.4 → cloudnetpy-1.95.6}/cloudnetpy/model_evaluation/products/tools.py +0 -0
  96. {cloudnetpy-1.95.4 → cloudnetpy-1.95.6}/cloudnetpy/model_evaluation/statistics/__init__.py +0 -0
  97. {cloudnetpy-1.95.4 → cloudnetpy-1.95.6}/cloudnetpy/model_evaluation/statistics/statistical_methods.py +0 -0
  98. {cloudnetpy-1.95.4 → cloudnetpy-1.95.6}/cloudnetpy/model_evaluation/tests/__init__.py +0 -0
  99. {cloudnetpy-1.95.4 → cloudnetpy-1.95.6}/cloudnetpy/model_evaluation/tests/e2e/__init__.py +0 -0
  100. {cloudnetpy-1.95.4 → cloudnetpy-1.95.6}/cloudnetpy/model_evaluation/tests/e2e/conftest.py +0 -0
  101. {cloudnetpy-1.95.4 → cloudnetpy-1.95.6}/cloudnetpy/model_evaluation/tests/e2e/process_cf/__init__.py +0 -0
  102. {cloudnetpy-1.95.4 → cloudnetpy-1.95.6}/cloudnetpy/model_evaluation/tests/e2e/process_cf/main.py +0 -0
  103. {cloudnetpy-1.95.4 → cloudnetpy-1.95.6}/cloudnetpy/model_evaluation/tests/e2e/process_cf/tests.py +0 -0
  104. {cloudnetpy-1.95.4 → cloudnetpy-1.95.6}/cloudnetpy/model_evaluation/tests/e2e/process_iwc/__init__.py +0 -0
  105. {cloudnetpy-1.95.4 → cloudnetpy-1.95.6}/cloudnetpy/model_evaluation/tests/e2e/process_iwc/main.py +0 -0
  106. {cloudnetpy-1.95.4 → cloudnetpy-1.95.6}/cloudnetpy/model_evaluation/tests/e2e/process_iwc/tests.py +0 -0
  107. {cloudnetpy-1.95.4 → cloudnetpy-1.95.6}/cloudnetpy/model_evaluation/tests/e2e/process_lwc/__init__.py +0 -0
  108. {cloudnetpy-1.95.4 → cloudnetpy-1.95.6}/cloudnetpy/model_evaluation/tests/e2e/process_lwc/main.py +0 -0
  109. {cloudnetpy-1.95.4 → cloudnetpy-1.95.6}/cloudnetpy/model_evaluation/tests/e2e/process_lwc/tests.py +0 -0
  110. {cloudnetpy-1.95.4 → cloudnetpy-1.95.6}/cloudnetpy/model_evaluation/tests/unit/__init__.py +0 -0
  111. {cloudnetpy-1.95.4 → cloudnetpy-1.95.6}/cloudnetpy/model_evaluation/tests/unit/conftest.py +0 -0
  112. {cloudnetpy-1.95.4 → cloudnetpy-1.95.6}/cloudnetpy/model_evaluation/tests/unit/test_advance_methods.py +0 -0
  113. {cloudnetpy-1.95.4 → cloudnetpy-1.95.6}/cloudnetpy/model_evaluation/tests/unit/test_grid_methods.py +0 -0
  114. {cloudnetpy-1.95.4 → cloudnetpy-1.95.6}/cloudnetpy/model_evaluation/tests/unit/test_model_products.py +0 -0
  115. {cloudnetpy-1.95.4 → cloudnetpy-1.95.6}/cloudnetpy/model_evaluation/tests/unit/test_observation_products.py +0 -0
  116. {cloudnetpy-1.95.4 → cloudnetpy-1.95.6}/cloudnetpy/model_evaluation/tests/unit/test_plot_tools.py +0 -0
  117. {cloudnetpy-1.95.4 → cloudnetpy-1.95.6}/cloudnetpy/model_evaluation/tests/unit/test_plotting.py +0 -0
  118. {cloudnetpy-1.95.4 → cloudnetpy-1.95.6}/cloudnetpy/model_evaluation/tests/unit/test_statistical_methods.py +0 -0
  119. {cloudnetpy-1.95.4 → cloudnetpy-1.95.6}/cloudnetpy/model_evaluation/tests/unit/test_tools.py +0 -0
  120. {cloudnetpy-1.95.4 → cloudnetpy-1.95.6}/cloudnetpy/model_evaluation/utils.py +0 -0
  121. {cloudnetpy-1.95.4 → cloudnetpy-1.95.6}/cloudnetpy/plotting/__init__.py +0 -0
  122. {cloudnetpy-1.95.4 → cloudnetpy-1.95.6}/cloudnetpy/plotting/plot_meta.py +0 -0
  123. {cloudnetpy-1.95.4 → cloudnetpy-1.95.6}/cloudnetpy/products/__init__.py +0 -0
  124. {cloudnetpy-1.95.4 → cloudnetpy-1.95.6}/cloudnetpy/products/classification.py +0 -0
  125. {cloudnetpy-1.95.4 → cloudnetpy-1.95.6}/cloudnetpy/products/der.py +0 -0
  126. {cloudnetpy-1.95.4 → cloudnetpy-1.95.6}/cloudnetpy/products/drizzle.py +0 -0
  127. {cloudnetpy-1.95.4 → cloudnetpy-1.95.6}/cloudnetpy/products/drizzle_error.py +0 -0
  128. {cloudnetpy-1.95.4 → cloudnetpy-1.95.6}/cloudnetpy/products/drizzle_tools.py +0 -0
  129. {cloudnetpy-1.95.4 → cloudnetpy-1.95.6}/cloudnetpy/products/epsilon_lidar.py +0 -0
  130. {cloudnetpy-1.95.4 → cloudnetpy-1.95.6}/cloudnetpy/products/epsilon_radar.py +0 -0
  131. {cloudnetpy-1.95.4 → cloudnetpy-1.95.6}/cloudnetpy/products/ier.py +0 -0
  132. {cloudnetpy-1.95.4 → cloudnetpy-1.95.6}/cloudnetpy/products/iwc.py +0 -0
  133. {cloudnetpy-1.95.4 → cloudnetpy-1.95.6}/cloudnetpy/products/iwc_weather_radar.py +0 -0
  134. {cloudnetpy-1.95.4 → cloudnetpy-1.95.6}/cloudnetpy/products/lwc.py +0 -0
  135. {cloudnetpy-1.95.4 → cloudnetpy-1.95.6}/cloudnetpy/products/mie_lu_tables.nc +0 -0
  136. {cloudnetpy-1.95.4 → cloudnetpy-1.95.6}/cloudnetpy/products/mwr_tools.py +0 -0
  137. {cloudnetpy-1.95.4 → cloudnetpy-1.95.6}/cloudnetpy/products/product_tools.py +0 -0
  138. {cloudnetpy-1.95.4 → cloudnetpy-1.95.6}/cloudnetpy/py.typed +0 -0
  139. {cloudnetpy-1.95.4 → cloudnetpy-1.95.6}/cloudnetpy/utils.py +0 -0
  140. {cloudnetpy-1.95.4 → cloudnetpy-1.95.6}/cloudnetpy.egg-info/SOURCES.txt +0 -0
  141. {cloudnetpy-1.95.4 → cloudnetpy-1.95.6}/cloudnetpy.egg-info/dependency_links.txt +0 -0
  142. {cloudnetpy-1.95.4 → cloudnetpy-1.95.6}/cloudnetpy.egg-info/entry_points.txt +0 -0
  143. {cloudnetpy-1.95.4 → cloudnetpy-1.95.6}/cloudnetpy.egg-info/requires.txt +0 -0
  144. {cloudnetpy-1.95.4 → cloudnetpy-1.95.6}/cloudnetpy.egg-info/top_level.txt +0 -0
  145. {cloudnetpy-1.95.4 → cloudnetpy-1.95.6}/docs/source/conf.py +0 -0
  146. {cloudnetpy-1.95.4 → cloudnetpy-1.95.6}/pyproject.toml +0 -0
  147. {cloudnetpy-1.95.4 → cloudnetpy-1.95.6}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cloudnetpy
3
- Version: 1.95.4
3
+ Version: 1.95.6
4
4
  Summary: Python package for Cloudnet processing
5
5
  Author: Simo Tukiainen
6
6
  License: MIT License
@@ -61,15 +61,22 @@ class ArmInstrument(NamedTuple):
61
61
 
62
62
 
63
63
  # In order of preference within each product; the first with files is used.
64
+ # Raw moments are preferred over ARM corrected products for consistency. The
65
+ # b1-level KAZR moments are identical to the a1-level ones except for the
66
+ # reflectivity calibration applied by ARM.
64
67
  ARM_INSTRUMENTS: Final = (
68
+ # KAZR2 calibrated moments (2020 onwards, hourly files, months of delay)
69
+ ArmInstrument("radar", "kazr", "kazrcfrgeqc.b1", kazr2nc, multi_file=True),
70
+ # KAZR2 calibrated moments at ENA
71
+ ArmInstrument("radar", "kazr", "kazr2cfrgeqc.b1", kazr2nc, multi_file=True),
65
72
  # KAZR2 (approx. 2019 onwards, hourly files)
66
73
  ArmInstrument("radar", "kazr", "kazrcfrge.a1", kazr2nc, multi_file=True),
67
74
  # KAZR2 at ENA (Dec 2019 onwards, hourly files)
68
75
  ArmInstrument("radar", "kazr", "kazr2cfrge.a1", kazr2nc, multi_file=True),
69
- # KAZR corrected moments (approx. 2011-2019)
70
- ArmInstrument("radar", "kazr", "kazrcorge.c1", kazr2nc, multi_file=True),
71
- # KAZR moments (approx. 2011-2019, e.g. mobile facilities)
76
+ # KAZR moments (approx. 2011-2019, daily files)
72
77
  ArmInstrument("radar", "kazr", "kazrge.a1", kazr2nc, multi_file=True),
78
+ # KAZR corrected moments (approx. 2011-2012), fallback if raw missing
79
+ ArmInstrument("radar", "kazr", "kazrcorge.c1", kazr2nc, multi_file=True),
73
80
  # MMCR (before 2011)
74
81
  ArmInstrument("radar", "mmcr", "mmcrmom.b1", mmcr2nc, multi_file=False),
75
82
  ArmInstrument("lidar", "cl31", "ceil.b1", armceilo2nc, multi_file=False),
@@ -212,6 +212,10 @@ def generate_categorize(
212
212
  attributes = output.add_time_attribute(CATEGORIZE_ATTRIBUTES, date)
213
213
  attributes = output.add_time_attribute(attributes, date, "model_time")
214
214
  attributes = output.add_source_attribute(attributes, data)
215
+ if "Z_offset" in cloudnet_arrays:
216
+ attributes["Z"] = attributes["Z"]._replace(
217
+ ancillary_variables=f"{attributes['Z'].ancillary_variables} Z_offset"
218
+ )
215
219
  output.update_attributes(cloudnet_arrays, attributes)
216
220
  _save_cat(output_file, data, cloudnet_arrays, uuid)
217
221
  return uuid
@@ -336,7 +340,7 @@ COMMENTS = {
336
340
  "and possibly liquid water, rain and melting layer (see quality_bits\n"
337
341
  "variable). Calibration convention: in the absence of attenuation, a cloud\n"
338
342
  "at 273 K containing one million 100-micron droplets per cubic metre will\n"
339
- "have\n a reflectivity of 0 dBZ at all frequencies."
343
+ "have a reflectivity of 0 dBZ at all frequencies."
340
344
  ),
341
345
  "bias": (
342
346
  "This variable is an estimate of the one-standard-deviation\ncalibration error."
@@ -439,6 +443,12 @@ CATEGORIZE_ATTRIBUTES = {
439
443
  "nyquist_velocity": COMMON_ATTRIBUTES["nyquist_velocity"]._replace(
440
444
  dimensions=("time", "height")
441
445
  ),
446
+ "Z_offset": MetaData(
447
+ long_name="Radar reflectivity calibration offset",
448
+ units="dBZ",
449
+ comment="Calibration offset applied to the reflectivity in the radar file.",
450
+ dimensions=None,
451
+ ),
442
452
  # Lidar variables
443
453
  "beta": MetaData(
444
454
  long_name="Attenuated backscatter coefficient",
@@ -62,7 +62,9 @@ def classify_measurements(data: Observations) -> ClassificationResult:
62
62
 
63
63
  bits.melting = melting.find_melting_layer(obs)
64
64
  bits.freezing = freezing.find_freezing_region(obs, bits.melting)
65
- liquid_from_lidar = droplet.find_liquid(obs)
65
+ # Vaisala CL51/CL61 have reliable near-range data, so allow lower liquid peaks
66
+ is_cl = any(model in obs.lidar_type.lower() for model in ("cl51", "cl61"))
67
+ liquid_from_lidar = droplet.find_liquid(obs, min_alt=70 if is_cl else 100)
66
68
  if obs.lv0_files is not None and len(obs.lv0_files) > 0:
67
69
  if "rpg-fmcw-94" not in obs.radar_type.lower():
68
70
  msg = "VoodooNet is only implemented for RPG-FMCW-94 radar."
@@ -56,6 +56,7 @@ class ClassData:
56
56
  height (ndarray): 1D height vector (m).
57
57
  model_type (str): Model identifier.
58
58
  radar_type (str): Radar identifier.
59
+ lidar_type (str): Lidar identifier.
59
60
  is_rain (ndarray): 2D boolean array denoting rain.
60
61
  is_clutter (ndarray): 2D boolean array denoting clutter.
61
62
  altitude: site altitude.
@@ -76,6 +77,7 @@ class ClassData:
76
77
  self.tw = data.model.data["Tw"][:]
77
78
  self.model_type = data.model.source_type
78
79
  self.beta = data.lidar.data["beta"][:]
80
+ self.lidar_type = data.lidar.source
79
81
  self.lwp = (
80
82
  data.mwr.data["lwp"][:]
81
83
  if data.mwr is not None
@@ -341,10 +341,19 @@ class Radar(DataSource):
341
341
  def _init_data(self) -> None:
342
342
  self.append_data(self.getvar("Zh"), "Z", units="dBZ")
343
343
  self.append_data(self.getvar("v"), "v_sigma")
344
- for key in ("v", "ldr", "width", "sldr", "rainfall_rate", "nyquist_velocity"):
344
+ for key in (
345
+ "v",
346
+ "ldr",
347
+ "width",
348
+ "sldr",
349
+ "rainfall_rate",
350
+ "nyquist_velocity",
351
+ ):
345
352
  if key in self.dataset.variables:
346
353
  data = self.dataset.variables[key]
347
354
  self.append_data(data, key)
355
+ if "Zh_offset" in self.dataset.variables:
356
+ self.append_data(self.dataset.variables["Zh_offset"], "Z_offset")
348
357
 
349
358
  def _rebin_velocity(
350
359
  self,
@@ -437,6 +437,8 @@ def _process_instrument_product(
437
437
  input_files = input_folder
438
438
  case ("mrr", _id):
439
439
  fun = instruments.mrr2nc
440
+ case ("weather-radar", _id):
441
+ fun = instruments.wr2nc
440
442
  case ("weather-station", _id):
441
443
  fun = instruments.ws2nc
442
444
  case (invalid_product_id, invalid_instrument_id):
@@ -770,6 +772,10 @@ def _plot(
770
772
  options = PlotParameters()
771
773
  if args.max_y is not None:
772
774
  options.max_y = args.max_y
775
+ if args.start_time is not None:
776
+ options.start_time = args.start_time
777
+ if args.stop_time is not None:
778
+ options.stop_time = args.stop_time
773
779
  try:
774
780
  generate_figure(
775
781
  filepath,
@@ -949,6 +955,18 @@ def main() -> None:
949
955
  help="Maximum y-axis value (km) in 2D time/height plots (default: 12)",
950
956
  default=None,
951
957
  )
958
+ parser.add_argument(
959
+ "--start-time",
960
+ type=float,
961
+ help="Start time in fractional hours since midnight UTC (default: 0)",
962
+ default=None,
963
+ )
964
+ parser.add_argument(
965
+ "--stop-time",
966
+ type=float,
967
+ help="Stop time in fractional hours since midnight UTC (default: 24)",
968
+ default=None,
969
+ )
952
970
  parser.add_argument(
953
971
  "-o",
954
972
  "--options",
@@ -112,6 +112,8 @@ class ArmCeilo(Ceilometer):
112
112
  self.data["time"] = np.array(nc["time"][:])
113
113
  calibration_factor = float(self.site_meta.get("calibration_factor", 1))
114
114
  backscatter = ma.masked_invalid(nc["backscatter"][:])
115
+ # Missing profiles are filled with int32 min without _FillValue
116
+ backscatter = ma.masked_less(backscatter, -1e6)
115
117
  self.data["beta_raw"] = backscatter * BACKSCATTER_SCALE * calibration_factor
116
118
  self.data["calibration_factor"] = calibration_factor
117
119
  self.data["zenith_angle"] = float(ma.median(nc["tilt_angle"][:]))
@@ -12,6 +12,7 @@ from uuid import UUID
12
12
 
13
13
  import netCDF4
14
14
  import numpy as np
15
+ import numpy.typing as npt
15
16
  from numpy import ma
16
17
 
17
18
  from cloudnetpy import output, utils
@@ -27,7 +28,7 @@ from cloudnetpy.instruments.dealias import (
27
28
  )
28
29
  from cloudnetpy.instruments.instruments import KAZR
29
30
  from cloudnetpy.instruments.nc_radar import estimate_snr_limit
30
- from cloudnetpy.metadata import COMMON_ATTRIBUTES
31
+ from cloudnetpy.metadata import COMMON_ATTRIBUTES, MetaData
31
32
 
32
33
  # KAZR2 CF/Radial format (e.g. sgpkazrcfrgeC1.a1, hourly files)
33
34
  KEYMAP_CFR = {
@@ -67,15 +68,18 @@ def kazr2nc(
67
68
  ) -> UUID:
68
69
  """Converts ARM KAZR cloud radar data into Cloudnet Level 1b netCDF file.
69
70
 
70
- Supports the KAZR2 CF/Radial moments (`kazrcfrge.a1`, hourly files), the
71
- ARM corrected moments (`kazrcorge.c1`, daily files) and the original KAZR
72
- moments (`kazrge.a1`, daily files). With the corrected moments, noise is
73
- screened using the ARM significant detection mask and LDR is calculated
74
- from the cross- and co-polar reflectivities. LDR is screened using the
75
- cross-polar SNR and removed completely if the cross-polar channel is found
76
- unreliable. Stationary clutter layers (zero velocity and spectral width)
77
- are removed. Velocities of the non-corrected formats are dealiased using
78
- velocity continuity.
71
+ Supports the KAZR2 CF/Radial moments (`kazrcfrge.a1` and the calibrated
72
+ `kazrcfrgeqc.b1`, hourly files), the ARM corrected moments (`kazrcorge.c1`,
73
+ daily files) and the original KAZR moments (`kazrge.a1`, daily files). The
74
+ reflectivity calibration offset applied by ARM in the calibrated files is
75
+ kept and recorded in `Zh_offset`. Uncalibrated files are calibrated with
76
+ `Zh_offset` from `site_meta` if given. With the corrected moments, noise is
77
+ screened using the ARM significant detection mask and
78
+ LDR is calculated from the cross- and co-polar reflectivities. LDR is
79
+ screened using the cross-polar SNR and removed completely if the
80
+ cross-polar channel is found unreliable. Stationary clutter layers (zero
81
+ velocity and spectral width) are removed. Velocities of the non-corrected
82
+ formats are dealiased using velocity continuity.
79
83
 
80
84
  Args:
81
85
  raw_files: Input file, a sequence of files, or a folder containing the
@@ -83,9 +87,11 @@ def kazr2nc(
83
87
  output_file: Output filename.
84
88
  site_meta: Dictionary containing information about the site. Required key
85
89
  value pair is `name`. Optional are `latitude`, `longitude` and
86
- `altitude` (taken from the raw file if missing) and `snr_limit`
90
+ `altitude` (taken from the raw file if missing), `snr_limit`
87
91
  (fixed SNR threshold in dB; by default the threshold is estimated
88
- from the noise in the top range gates).
92
+ from the noise in the top range gates) and `Zh_offset` (reflectivity
93
+ calibration offset in dB, used only if the file is not calibrated
94
+ by ARM).
89
95
  uuid: Set specific UUID for the file.
90
96
  date: Expected date as YYYY-MM-DD of all profiles in the file.
91
97
 
@@ -107,6 +113,7 @@ def kazr2nc(
107
113
  snr_limit = site_meta.get("snr_limit")
108
114
  kazr = Kazr(_get_files(raw_files), site_meta, date)
109
115
  kazr.read_files()
116
+ kazr.calibrate_reflectivity()
110
117
  kazr.sort_timestamps()
111
118
  kazr.remove_duplicate_timestamps()
112
119
  kazr.calc_ldr()
@@ -152,6 +159,7 @@ class Kazr(CloudnetInstrument):
152
159
  self.dealiased = False
153
160
  self.ldr_floor: float | None = None
154
161
  self.corrected = False # ARM corrected (dealiased) moments
162
+ self.offset_applied: float | None = None # Calibration offset by ARM
155
163
  self._raw: dict[str, list] = {}
156
164
 
157
165
  def read_files(self) -> None:
@@ -171,6 +179,20 @@ class Kazr(CloudnetInstrument):
171
179
  self.data[key] = CloudnetArray(ma.concatenate(arrays), key)
172
180
  self._screen_date()
173
181
 
182
+ def calibrate_reflectivity(self) -> None:
183
+ """Applies `Zh_offset` from site_meta unless already calibrated by ARM."""
184
+ zh_offset = self.site_meta.get("Zh_offset")
185
+ if self.offset_applied is not None:
186
+ if zh_offset is not None:
187
+ logging.info("File calibrated by ARM, ignoring Zh_offset")
188
+ zh_offset = self.offset_applied
189
+ elif zh_offset is None:
190
+ zh_offset = 0.0
191
+ else:
192
+ zh_offset = float(zh_offset)
193
+ self.data["Zh"].data[:] += zh_offset
194
+ self.append_data(np.array(zh_offset, dtype=np.float32), "Zh_offset")
195
+
174
196
  def screen_noise(self, snr_limit: float | None = None) -> None:
175
197
  """Masks noise using ARM detection mask if available, otherwise SNR.
176
198
 
@@ -339,6 +361,10 @@ class Kazr(CloudnetInstrument):
339
361
  else:
340
362
  msg = "Unknown KAZR file format"
341
363
  raise RadarDataError(msg)
364
+ zh_key = next(k for k, v in self.keymap.items() if v == "Zh")
365
+ bias = getattr(nc[zh_key], "applied_bias_correction", None)
366
+ if bias is not None:
367
+ self.offset_applied = _parse_bias(bias)
342
368
  self.serial_number = getattr(nc, "serial_number", None) or None
343
369
  self.append_data(np.array(nc["range"][:], dtype=float), "range")
344
370
  self.append_data(0.0, "zenith_angle")
@@ -508,6 +534,25 @@ def _get_files(raw_files: str | PathLike | Sequence[str | PathLike]) -> list[Pat
508
534
 
509
535
  ATTRIBUTES = {
510
536
  "correction_bits": CORRECTION_BITS_ATTRIBUTES,
537
+ "Zh_offset": MetaData(
538
+ long_name="Radar reflectivity calibration offset",
539
+ units="dBZ",
540
+ comment=(
541
+ "Calibration offset applied to the reflectivity, either by ARM "
542
+ "in the calibrated (b1) files or by Cloudnet in the other files."
543
+ ),
544
+ dimensions=None,
545
+ ),
511
546
  "zenith_angle": COMMON_ATTRIBUTES["zenith_angle"]._replace(dimensions=None),
512
547
  "nyquist_velocity": COMMON_ATTRIBUTES["nyquist_velocity"]._replace(dimensions=None),
513
548
  }
549
+
550
+
551
+ def _parse_bias(bias: npt.ArrayLike) -> float | None:
552
+ """Parses ARM reflectivity bias attribute, which may be an empty array."""
553
+ values = np.atleast_1d(np.asarray(bias, dtype=float))
554
+ if len(values) == 0:
555
+ return None
556
+ if len(np.unique(values)) > 1:
557
+ logging.warning("Multiple bias corrections %s, using the first one", values)
558
+ return round(float(values[0]), 2)
@@ -401,6 +401,7 @@ def add_source_attribute(attributes: dict, data: Observations) -> dict:
401
401
  "radar_frequency",
402
402
  "nyquist_velocity",
403
403
  "rainfall_rate",
404
+ "Z_offset",
404
405
  ),
405
406
  "lidar": ("beta", "lidar_wavelength"),
406
407
  "mwr": ("lwp",),
@@ -54,6 +54,8 @@ class PlotParameters:
54
54
  plotted variable.
55
55
  minor_ticks: Whether to display minor ticks on the x-axis.
56
56
  plot_above_ground: Whether to plot above ground instead of above mean sea level.
57
+ start_time: Start time in fractional hours for time-axis limits.
58
+ stop_time: Stop time in fractional hours for time-axis limits.
57
59
 
58
60
  """
59
61
 
@@ -70,6 +72,8 @@ class PlotParameters:
70
72
  raise_on_empty: bool = False
71
73
  minor_ticks: bool = True
72
74
  plot_above_ground: bool = True
75
+ start_time: float | None = None
76
+ stop_time: float | None = None
73
77
 
74
78
 
75
79
  class Dimensions:
@@ -337,7 +341,11 @@ class SubPlot:
337
341
  if self.options.minor_ticks:
338
342
  self.ax.xaxis.set_minor_locator(AutoMinorLocator(4))
339
343
  self.ax.tick_params(which="minor", length=2.5)
340
- self.ax.set_xlim(0, 24)
344
+ start_time = (
345
+ self.options.start_time if self.options.start_time is not None else 0
346
+ )
347
+ stop_time = self.options.stop_time if self.options.stop_time is not None else 24
348
+ self.ax.set_xlim(start_time, stop_time)
341
349
 
342
350
  def set_yax(
343
351
  self,
@@ -1,4 +1,4 @@
1
1
  MAJOR = 1
2
2
  MINOR = 95
3
- PATCH = 4
3
+ PATCH = 6
4
4
  __version__ = f"{MAJOR}.{MINOR}.{PATCH}"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cloudnetpy
3
- Version: 1.95.4
3
+ Version: 1.95.6
4
4
  Summary: Python package for Cloudnet processing
5
5
  Author: Simo Tukiainen
6
6
  License: MIT License
File without changes
File without changes
File without changes
File without changes
File without changes