cloudnetpy 1.93.4__tar.gz → 1.93.5__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 (141) hide show
  1. {cloudnetpy-1.93.4/cloudnetpy.egg-info → cloudnetpy-1.93.5}/PKG-INFO +14 -3
  2. {cloudnetpy-1.93.4 → cloudnetpy-1.93.5}/README.md +13 -2
  3. {cloudnetpy-1.93.4 → cloudnetpy-1.93.5}/cloudnetpy/categorize/containers.py +1 -1
  4. {cloudnetpy-1.93.4 → cloudnetpy-1.93.5}/cloudnetpy/cloudnetarray.py +1 -1
  5. {cloudnetpy-1.93.4 → cloudnetpy-1.93.5}/cloudnetpy/instruments/ceilometer.py +1 -1
  6. {cloudnetpy-1.93.4 → cloudnetpy-1.93.5}/cloudnetpy/instruments/instruments.py +16 -0
  7. {cloudnetpy-1.93.4 → cloudnetpy-1.93.5}/cloudnetpy/instruments/lufft.py +2 -2
  8. {cloudnetpy-1.93.4 → cloudnetpy-1.93.5}/cloudnetpy/instruments/mira.py +81 -26
  9. cloudnetpy-1.93.5/cloudnetpy/model_evaluation/__init__.py +6 -0
  10. {cloudnetpy-1.93.4 → cloudnetpy-1.93.5}/cloudnetpy/model_evaluation/plotting/plotting.py +1 -2
  11. {cloudnetpy-1.93.4 → cloudnetpy-1.93.5}/cloudnetpy/model_evaluation/products/product_resampling.py +1 -2
  12. {cloudnetpy-1.93.4 → cloudnetpy-1.93.5}/cloudnetpy/model_evaluation/tests/unit/test_tools.py +3 -3
  13. {cloudnetpy-1.93.4 → cloudnetpy-1.93.5}/cloudnetpy/plotting/plotting.py +1 -1
  14. {cloudnetpy-1.93.4 → cloudnetpy-1.93.5}/cloudnetpy/products/lwc.py +1 -1
  15. {cloudnetpy-1.93.4 → cloudnetpy-1.93.5}/cloudnetpy/utils.py +1 -1
  16. {cloudnetpy-1.93.4 → cloudnetpy-1.93.5}/cloudnetpy/version.py +1 -1
  17. {cloudnetpy-1.93.4 → cloudnetpy-1.93.5/cloudnetpy.egg-info}/PKG-INFO +14 -3
  18. cloudnetpy-1.93.4/cloudnetpy/model_evaluation/tests/unit/__init__.py +0 -0
  19. {cloudnetpy-1.93.4 → cloudnetpy-1.93.5}/LICENSE +0 -0
  20. {cloudnetpy-1.93.4 → cloudnetpy-1.93.5}/MANIFEST.in +0 -0
  21. {cloudnetpy-1.93.4 → cloudnetpy-1.93.5}/cloudnetpy/__init__.py +0 -0
  22. {cloudnetpy-1.93.4 → cloudnetpy-1.93.5}/cloudnetpy/categorize/__init__.py +0 -0
  23. {cloudnetpy-1.93.4 → cloudnetpy-1.93.5}/cloudnetpy/categorize/atmos_utils.py +0 -0
  24. {cloudnetpy-1.93.4 → cloudnetpy-1.93.5}/cloudnetpy/categorize/attenuation.py +0 -0
  25. {cloudnetpy-1.93.4 → cloudnetpy-1.93.5}/cloudnetpy/categorize/attenuations/__init__.py +0 -0
  26. {cloudnetpy-1.93.4 → cloudnetpy-1.93.5}/cloudnetpy/categorize/attenuations/gas_attenuation.py +0 -0
  27. {cloudnetpy-1.93.4 → cloudnetpy-1.93.5}/cloudnetpy/categorize/attenuations/liquid_attenuation.py +0 -0
  28. {cloudnetpy-1.93.4 → cloudnetpy-1.93.5}/cloudnetpy/categorize/attenuations/melting_attenuation.py +0 -0
  29. {cloudnetpy-1.93.4 → cloudnetpy-1.93.5}/cloudnetpy/categorize/attenuations/rain_attenuation.py +0 -0
  30. {cloudnetpy-1.93.4 → cloudnetpy-1.93.5}/cloudnetpy/categorize/categorize.py +0 -0
  31. {cloudnetpy-1.93.4 → cloudnetpy-1.93.5}/cloudnetpy/categorize/classify.py +0 -0
  32. {cloudnetpy-1.93.4 → cloudnetpy-1.93.5}/cloudnetpy/categorize/disdrometer.py +0 -0
  33. {cloudnetpy-1.93.4 → cloudnetpy-1.93.5}/cloudnetpy/categorize/droplet.py +0 -0
  34. {cloudnetpy-1.93.4 → cloudnetpy-1.93.5}/cloudnetpy/categorize/falling.py +0 -0
  35. {cloudnetpy-1.93.4 → cloudnetpy-1.93.5}/cloudnetpy/categorize/freezing.py +0 -0
  36. {cloudnetpy-1.93.4 → cloudnetpy-1.93.5}/cloudnetpy/categorize/insects.py +0 -0
  37. {cloudnetpy-1.93.4 → cloudnetpy-1.93.5}/cloudnetpy/categorize/lidar.py +0 -0
  38. {cloudnetpy-1.93.4 → cloudnetpy-1.93.5}/cloudnetpy/categorize/melting.py +0 -0
  39. {cloudnetpy-1.93.4 → cloudnetpy-1.93.5}/cloudnetpy/categorize/model.py +0 -0
  40. {cloudnetpy-1.93.4 → cloudnetpy-1.93.5}/cloudnetpy/categorize/mwr.py +0 -0
  41. {cloudnetpy-1.93.4 → cloudnetpy-1.93.5}/cloudnetpy/categorize/radar.py +0 -0
  42. {cloudnetpy-1.93.4 → cloudnetpy-1.93.5}/cloudnetpy/cli.py +0 -0
  43. {cloudnetpy-1.93.4 → cloudnetpy-1.93.5}/cloudnetpy/concat_lib.py +0 -0
  44. {cloudnetpy-1.93.4 → cloudnetpy-1.93.5}/cloudnetpy/constants.py +0 -0
  45. {cloudnetpy-1.93.4 → cloudnetpy-1.93.5}/cloudnetpy/datasource.py +0 -0
  46. {cloudnetpy-1.93.4 → cloudnetpy-1.93.5}/cloudnetpy/disdronator/__init__.py +0 -0
  47. {cloudnetpy-1.93.4 → cloudnetpy-1.93.5}/cloudnetpy/disdronator/lpm.py +0 -0
  48. {cloudnetpy-1.93.4 → cloudnetpy-1.93.5}/cloudnetpy/disdronator/parsivel.py +0 -0
  49. {cloudnetpy-1.93.4 → cloudnetpy-1.93.5}/cloudnetpy/disdronator/rd80.py +0 -0
  50. {cloudnetpy-1.93.4 → cloudnetpy-1.93.5}/cloudnetpy/disdronator/utils.py +0 -0
  51. {cloudnetpy-1.93.4 → cloudnetpy-1.93.5}/cloudnetpy/exceptions.py +0 -0
  52. {cloudnetpy-1.93.4 → cloudnetpy-1.93.5}/cloudnetpy/instruments/__init__.py +0 -0
  53. {cloudnetpy-1.93.4 → cloudnetpy-1.93.5}/cloudnetpy/instruments/basta.py +0 -0
  54. {cloudnetpy-1.93.4 → cloudnetpy-1.93.5}/cloudnetpy/instruments/bowtie.py +0 -0
  55. {cloudnetpy-1.93.4 → cloudnetpy-1.93.5}/cloudnetpy/instruments/ceilo.py +0 -0
  56. {cloudnetpy-1.93.4 → cloudnetpy-1.93.5}/cloudnetpy/instruments/cl61d.py +0 -0
  57. {cloudnetpy-1.93.4 → cloudnetpy-1.93.5}/cloudnetpy/instruments/cloudnet_instrument.py +0 -0
  58. {cloudnetpy-1.93.4 → cloudnetpy-1.93.5}/cloudnetpy/instruments/copernicus.py +0 -0
  59. {cloudnetpy-1.93.4 → cloudnetpy-1.93.5}/cloudnetpy/instruments/da10.py +0 -0
  60. {cloudnetpy-1.93.4 → cloudnetpy-1.93.5}/cloudnetpy/instruments/disdrometer/__init__.py +0 -0
  61. {cloudnetpy-1.93.4 → cloudnetpy-1.93.5}/cloudnetpy/instruments/disdrometer/common.py +0 -0
  62. {cloudnetpy-1.93.4 → cloudnetpy-1.93.5}/cloudnetpy/instruments/disdrometer/parsivel.py +0 -0
  63. {cloudnetpy-1.93.4 → cloudnetpy-1.93.5}/cloudnetpy/instruments/disdrometer/rd80.py +0 -0
  64. {cloudnetpy-1.93.4 → cloudnetpy-1.93.5}/cloudnetpy/instruments/disdrometer/thies.py +0 -0
  65. {cloudnetpy-1.93.4 → cloudnetpy-1.93.5}/cloudnetpy/instruments/fd12p.py +0 -0
  66. {cloudnetpy-1.93.4 → cloudnetpy-1.93.5}/cloudnetpy/instruments/galileo.py +0 -0
  67. {cloudnetpy-1.93.4 → cloudnetpy-1.93.5}/cloudnetpy/instruments/hatpro.py +0 -0
  68. {cloudnetpy-1.93.4 → cloudnetpy-1.93.5}/cloudnetpy/instruments/mrr.py +0 -0
  69. {cloudnetpy-1.93.4 → cloudnetpy-1.93.5}/cloudnetpy/instruments/nc_lidar.py +0 -0
  70. {cloudnetpy-1.93.4 → cloudnetpy-1.93.5}/cloudnetpy/instruments/nc_radar.py +0 -0
  71. {cloudnetpy-1.93.4 → cloudnetpy-1.93.5}/cloudnetpy/instruments/pollyxt.py +0 -0
  72. {cloudnetpy-1.93.4 → cloudnetpy-1.93.5}/cloudnetpy/instruments/radiometrics.py +0 -0
  73. {cloudnetpy-1.93.4 → cloudnetpy-1.93.5}/cloudnetpy/instruments/rain_e_h3.py +0 -0
  74. {cloudnetpy-1.93.4 → cloudnetpy-1.93.5}/cloudnetpy/instruments/rpg.py +0 -0
  75. {cloudnetpy-1.93.4 → cloudnetpy-1.93.5}/cloudnetpy/instruments/rpg_reader.py +0 -0
  76. {cloudnetpy-1.93.4 → cloudnetpy-1.93.5}/cloudnetpy/instruments/toa5.py +0 -0
  77. {cloudnetpy-1.93.4 → cloudnetpy-1.93.5}/cloudnetpy/instruments/vaisala.py +0 -0
  78. {cloudnetpy-1.93.4 → cloudnetpy-1.93.5}/cloudnetpy/instruments/weather_radar.py +0 -0
  79. {cloudnetpy-1.93.4 → cloudnetpy-1.93.5}/cloudnetpy/instruments/weather_station.py +0 -0
  80. {cloudnetpy-1.93.4 → cloudnetpy-1.93.5}/cloudnetpy/metadata.py +0 -0
  81. {cloudnetpy-1.93.4 → cloudnetpy-1.93.5}/cloudnetpy/model_evaluation/file_handler.py +0 -0
  82. {cloudnetpy-1.93.4 → cloudnetpy-1.93.5}/cloudnetpy/model_evaluation/metadata.py +0 -0
  83. {cloudnetpy-1.93.4 → cloudnetpy-1.93.5}/cloudnetpy/model_evaluation/model_metadata.py +0 -0
  84. {cloudnetpy-1.93.4/cloudnetpy/model_evaluation → cloudnetpy-1.93.5/cloudnetpy/model_evaluation/plotting}/__init__.py +0 -0
  85. {cloudnetpy-1.93.4 → cloudnetpy-1.93.5}/cloudnetpy/model_evaluation/plotting/plot_meta.py +0 -0
  86. {cloudnetpy-1.93.4 → cloudnetpy-1.93.5}/cloudnetpy/model_evaluation/plotting/plot_tools.py +0 -0
  87. {cloudnetpy-1.93.4/cloudnetpy/model_evaluation/plotting → cloudnetpy-1.93.5/cloudnetpy/model_evaluation/products}/__init__.py +0 -0
  88. {cloudnetpy-1.93.4 → cloudnetpy-1.93.5}/cloudnetpy/model_evaluation/products/advance_methods.py +0 -0
  89. {cloudnetpy-1.93.4 → cloudnetpy-1.93.5}/cloudnetpy/model_evaluation/products/grid_methods.py +0 -0
  90. {cloudnetpy-1.93.4 → cloudnetpy-1.93.5}/cloudnetpy/model_evaluation/products/model_products.py +0 -0
  91. {cloudnetpy-1.93.4 → cloudnetpy-1.93.5}/cloudnetpy/model_evaluation/products/observation_products.py +0 -0
  92. {cloudnetpy-1.93.4 → cloudnetpy-1.93.5}/cloudnetpy/model_evaluation/products/tools.py +0 -0
  93. {cloudnetpy-1.93.4/cloudnetpy/model_evaluation/products → cloudnetpy-1.93.5/cloudnetpy/model_evaluation/statistics}/__init__.py +0 -0
  94. {cloudnetpy-1.93.4 → cloudnetpy-1.93.5}/cloudnetpy/model_evaluation/statistics/statistical_methods.py +0 -0
  95. {cloudnetpy-1.93.4/cloudnetpy/model_evaluation/statistics → cloudnetpy-1.93.5/cloudnetpy/model_evaluation/tests}/__init__.py +0 -0
  96. {cloudnetpy-1.93.4/cloudnetpy/model_evaluation/tests → cloudnetpy-1.93.5/cloudnetpy/model_evaluation/tests/e2e}/__init__.py +0 -0
  97. {cloudnetpy-1.93.4 → cloudnetpy-1.93.5}/cloudnetpy/model_evaluation/tests/e2e/conftest.py +0 -0
  98. {cloudnetpy-1.93.4/cloudnetpy/model_evaluation/tests/e2e → cloudnetpy-1.93.5/cloudnetpy/model_evaluation/tests/e2e/process_cf}/__init__.py +0 -0
  99. {cloudnetpy-1.93.4 → cloudnetpy-1.93.5}/cloudnetpy/model_evaluation/tests/e2e/process_cf/main.py +0 -0
  100. {cloudnetpy-1.93.4 → cloudnetpy-1.93.5}/cloudnetpy/model_evaluation/tests/e2e/process_cf/tests.py +0 -0
  101. {cloudnetpy-1.93.4/cloudnetpy/model_evaluation/tests/e2e/process_cf → cloudnetpy-1.93.5/cloudnetpy/model_evaluation/tests/e2e/process_iwc}/__init__.py +0 -0
  102. {cloudnetpy-1.93.4 → cloudnetpy-1.93.5}/cloudnetpy/model_evaluation/tests/e2e/process_iwc/main.py +0 -0
  103. {cloudnetpy-1.93.4 → cloudnetpy-1.93.5}/cloudnetpy/model_evaluation/tests/e2e/process_iwc/tests.py +0 -0
  104. {cloudnetpy-1.93.4/cloudnetpy/model_evaluation/tests/e2e/process_iwc → cloudnetpy-1.93.5/cloudnetpy/model_evaluation/tests/e2e/process_lwc}/__init__.py +0 -0
  105. {cloudnetpy-1.93.4 → cloudnetpy-1.93.5}/cloudnetpy/model_evaluation/tests/e2e/process_lwc/main.py +0 -0
  106. {cloudnetpy-1.93.4 → cloudnetpy-1.93.5}/cloudnetpy/model_evaluation/tests/e2e/process_lwc/tests.py +0 -0
  107. {cloudnetpy-1.93.4/cloudnetpy/model_evaluation/tests/e2e/process_lwc → cloudnetpy-1.93.5/cloudnetpy/model_evaluation/tests/unit}/__init__.py +0 -0
  108. {cloudnetpy-1.93.4 → cloudnetpy-1.93.5}/cloudnetpy/model_evaluation/tests/unit/conftest.py +0 -0
  109. {cloudnetpy-1.93.4 → cloudnetpy-1.93.5}/cloudnetpy/model_evaluation/tests/unit/test_advance_methods.py +0 -0
  110. {cloudnetpy-1.93.4 → cloudnetpy-1.93.5}/cloudnetpy/model_evaluation/tests/unit/test_grid_methods.py +0 -0
  111. {cloudnetpy-1.93.4 → cloudnetpy-1.93.5}/cloudnetpy/model_evaluation/tests/unit/test_model_products.py +0 -0
  112. {cloudnetpy-1.93.4 → cloudnetpy-1.93.5}/cloudnetpy/model_evaluation/tests/unit/test_observation_products.py +0 -0
  113. {cloudnetpy-1.93.4 → cloudnetpy-1.93.5}/cloudnetpy/model_evaluation/tests/unit/test_plot_tools.py +0 -0
  114. {cloudnetpy-1.93.4 → cloudnetpy-1.93.5}/cloudnetpy/model_evaluation/tests/unit/test_plotting.py +0 -0
  115. {cloudnetpy-1.93.4 → cloudnetpy-1.93.5}/cloudnetpy/model_evaluation/tests/unit/test_statistical_methods.py +0 -0
  116. {cloudnetpy-1.93.4 → cloudnetpy-1.93.5}/cloudnetpy/model_evaluation/utils.py +0 -0
  117. {cloudnetpy-1.93.4 → cloudnetpy-1.93.5}/cloudnetpy/output.py +0 -0
  118. {cloudnetpy-1.93.4 → cloudnetpy-1.93.5}/cloudnetpy/plotting/__init__.py +0 -0
  119. {cloudnetpy-1.93.4 → cloudnetpy-1.93.5}/cloudnetpy/plotting/plot_meta.py +0 -0
  120. {cloudnetpy-1.93.4 → cloudnetpy-1.93.5}/cloudnetpy/products/__init__.py +0 -0
  121. {cloudnetpy-1.93.4 → cloudnetpy-1.93.5}/cloudnetpy/products/classification.py +0 -0
  122. {cloudnetpy-1.93.4 → cloudnetpy-1.93.5}/cloudnetpy/products/der.py +0 -0
  123. {cloudnetpy-1.93.4 → cloudnetpy-1.93.5}/cloudnetpy/products/drizzle.py +0 -0
  124. {cloudnetpy-1.93.4 → cloudnetpy-1.93.5}/cloudnetpy/products/drizzle_error.py +0 -0
  125. {cloudnetpy-1.93.4 → cloudnetpy-1.93.5}/cloudnetpy/products/drizzle_tools.py +0 -0
  126. {cloudnetpy-1.93.4 → cloudnetpy-1.93.5}/cloudnetpy/products/epsilon_lidar.py +0 -0
  127. {cloudnetpy-1.93.4 → cloudnetpy-1.93.5}/cloudnetpy/products/epsilon_radar.py +0 -0
  128. {cloudnetpy-1.93.4 → cloudnetpy-1.93.5}/cloudnetpy/products/ier.py +0 -0
  129. {cloudnetpy-1.93.4 → cloudnetpy-1.93.5}/cloudnetpy/products/iwc.py +0 -0
  130. {cloudnetpy-1.93.4 → cloudnetpy-1.93.5}/cloudnetpy/products/mie_lu_tables.nc +0 -0
  131. {cloudnetpy-1.93.4 → cloudnetpy-1.93.5}/cloudnetpy/products/mwr_tools.py +0 -0
  132. {cloudnetpy-1.93.4 → cloudnetpy-1.93.5}/cloudnetpy/products/product_tools.py +0 -0
  133. {cloudnetpy-1.93.4 → cloudnetpy-1.93.5}/cloudnetpy/py.typed +0 -0
  134. {cloudnetpy-1.93.4 → cloudnetpy-1.93.5}/cloudnetpy.egg-info/SOURCES.txt +0 -0
  135. {cloudnetpy-1.93.4 → cloudnetpy-1.93.5}/cloudnetpy.egg-info/dependency_links.txt +0 -0
  136. {cloudnetpy-1.93.4 → cloudnetpy-1.93.5}/cloudnetpy.egg-info/entry_points.txt +0 -0
  137. {cloudnetpy-1.93.4 → cloudnetpy-1.93.5}/cloudnetpy.egg-info/requires.txt +0 -0
  138. {cloudnetpy-1.93.4 → cloudnetpy-1.93.5}/cloudnetpy.egg-info/top_level.txt +0 -0
  139. {cloudnetpy-1.93.4 → cloudnetpy-1.93.5}/docs/source/conf.py +0 -0
  140. {cloudnetpy-1.93.4 → cloudnetpy-1.93.5}/pyproject.toml +0 -0
  141. {cloudnetpy-1.93.4 → cloudnetpy-1.93.5}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cloudnetpy
3
- Version: 1.93.4
3
+ Version: 1.93.5
4
4
  Summary: Python package for Cloudnet processing
5
5
  Author: Simo Tukiainen
6
6
  License: MIT License
@@ -106,12 +106,23 @@ python3 -m pip install .
106
106
 
107
107
  ### Verification
108
108
 
109
- To verify the installation:
109
+ Verify the installation by running `cloudnetpy --help`.
110
+
111
+ ## Command-line usage
112
+
113
+ CloudnetPy ships with a `cloudnetpy` console script that fetches data from the
114
+ [Cloudnet data portal](https://cloudnet.fmi.fi), runs the requested processing
115
+ steps, and writes netCDF files (and optionally plots) to disk:
110
116
 
111
117
  ```sh
112
- cloudnetpy --help
118
+ cloudnetpy --site munich --date 2023-07-29 --products radar --show
119
+ cloudnetpy --site kenttarova --date 2025-07-29 --products classification --show
120
+ cloudnetpy -s kenttarova -d 2025-05-28 -p l3-cf -m harmonie-fmi-6-11 --show
113
121
  ```
114
122
 
123
+ See the [command-line usage documentation](https://actris-cloudnet.github.io/cloudnetpy/cli.html)
124
+ for instrument selection, different products, plotting, and all options.
125
+
115
126
  ## Citing
116
127
 
117
128
  If you wish to acknowledge CloudnetPy in your publication, please cite:
@@ -41,12 +41,23 @@ python3 -m pip install .
41
41
 
42
42
  ### Verification
43
43
 
44
- To verify the installation:
44
+ Verify the installation by running `cloudnetpy --help`.
45
+
46
+ ## Command-line usage
47
+
48
+ CloudnetPy ships with a `cloudnetpy` console script that fetches data from the
49
+ [Cloudnet data portal](https://cloudnet.fmi.fi), runs the requested processing
50
+ steps, and writes netCDF files (and optionally plots) to disk:
45
51
 
46
52
  ```sh
47
- cloudnetpy --help
53
+ cloudnetpy --site munich --date 2023-07-29 --products radar --show
54
+ cloudnetpy --site kenttarova --date 2025-07-29 --products classification --show
55
+ cloudnetpy -s kenttarova -d 2025-05-28 -p l3-cf -m harmonie-fmi-6-11 --show
48
56
  ```
49
57
 
58
+ See the [command-line usage documentation](https://actris-cloudnet.github.io/cloudnetpy/cli.html)
59
+ for instrument selection, different products, plotting, and all options.
60
+
50
61
  ## Citing
51
62
 
52
63
  If you wish to acknowledge CloudnetPy in your publication, please cite:
@@ -163,6 +163,6 @@ def _find_clutter(
163
163
  """
164
164
  is_clutter = np.zeros(v.shape, dtype=bool)
165
165
  filled = False
166
- tiny_velocity = (np.abs(v[:, :n_gates]) < v_lim).filled(filled)
166
+ tiny_velocity = ma.less(ma.abs(v[:, :n_gates]), v_lim).filled(filled)
167
167
  is_clutter[:, :n_gates] = tiny_velocity * utils.transpose(~is_rain)
168
168
  return is_clutter
@@ -111,7 +111,7 @@ class CloudnetArray:
111
111
 
112
112
  def _filter(self, fun: Callable[[npt.NDArray], npt.NDArray]) -> None:
113
113
  if not isinstance(self.data, ma.MaskedArray):
114
- self.data = ma.masked_array(self.data)
114
+ self.data = ma.array(self.data)
115
115
  is_data = (~self.data.mask).astype(int)
116
116
  is_data_filtered = fun(is_data)
117
117
  self.data[is_data_filtered == 0] = ma.masked
@@ -273,7 +273,7 @@ class NoisyData:
273
273
  ind = self._get_altitude_ind()
274
274
  snr[:, ind] *= snr_scale_factor
275
275
  if ma.isMaskedArray(array) is False:
276
- array = ma.masked_array(array)
276
+ array = ma.array(array)
277
277
  if keep_negative is True:
278
278
  array[np.abs(snr) < snr_limit] = ma.masked
279
279
  else:
@@ -91,6 +91,22 @@ MIRA35 = Instrument(
91
91
  frequency=35.5,
92
92
  )
93
93
 
94
+ MIRA35S = Instrument(
95
+ manufacturer="METEK",
96
+ domain="radar",
97
+ category="cloud radar",
98
+ model="MIRA-35S",
99
+ frequency=35.5,
100
+ )
101
+
102
+ MIRA35C = Instrument(
103
+ manufacturer="METEK",
104
+ domain="radar",
105
+ category="cloud radar",
106
+ model="MIRA-35C",
107
+ frequency=35.5,
108
+ )
109
+
94
110
  COPERNICUS = Instrument(
95
111
  manufacturer="RAL Space",
96
112
  domain="radar",
@@ -43,7 +43,7 @@ class LufftCeilo(NcLidar):
43
43
  logging.warning("Using default calibration factor")
44
44
  calibration_factor = 3e-12
45
45
  beta_raw = self._getvar("beta_raw", "beta_att")
46
- beta_raw = ma.masked_array(beta_raw)
46
+ beta_raw = ma.array(beta_raw)
47
47
  old_version = self._get_old_software_version()
48
48
  if old_version is not None:
49
49
  self.is_old_version = True
@@ -53,7 +53,7 @@ class LufftCeilo(NcLidar):
53
53
  )
54
54
  data_std = self._getvar("stddev")
55
55
  normalised_apd = self._get_nn()
56
- beta_raw *= utils.transpose(ma.masked_array(data_std / normalised_apd))
56
+ beta_raw *= utils.transpose(ma.array(data_std / normalised_apd))
57
57
  beta_raw *= self.data["range"] ** 2
58
58
  beta_raw *= calibration_factor
59
59
  self.data["calibration_factor"] = float(calibration_factor)
@@ -14,7 +14,9 @@ import numpy as np
14
14
  from numpy import ma
15
15
 
16
16
  from cloudnetpy import concat_lib, output, utils
17
- from cloudnetpy.instruments.instruments import MIRA10, MIRA35
17
+ from cloudnetpy.cloudnetarray import CloudnetArray
18
+ from cloudnetpy.constants import HZ_TO_GHZ
19
+ from cloudnetpy.instruments.instruments import MIRA10, MIRA35, MIRA35C, MIRA35S
18
20
  from cloudnetpy.instruments.nc_radar import NcRadar
19
21
  from cloudnetpy.metadata import MetaData
20
22
 
@@ -26,7 +28,7 @@ def mira2nc(
26
28
  uuid: str | UUID | None = None,
27
29
  date: str | datetime.date | None = None,
28
30
  ) -> UUID:
29
- """Converts METEK MIRA-35 cloud radar data into Cloudnet Level 1b netCDF file.
31
+ """Converts METEK MIRA cloud radar data into Cloudnet Level 1b netCDF file.
30
32
 
31
33
  This function converts raw MIRA file(s) into a much smaller file that
32
34
  contains only the relevant data and can be used in further processing
@@ -38,8 +40,9 @@ def mira2nc(
38
40
  ``.znc`` files from one day, or a list of files. ``.znc`` files take
39
41
  precedence because they are the newer filetype.
40
42
  output_file: Output filename.
41
- site_meta: Dictionary containing information about the site. Required key
42
- value pair is `name`.
43
+ site_meta: Dictionary containing information about the site. Required
44
+ key-value pair is `name`. Optional `model` takes `mira-35` (default),
45
+ `mira-35s`, `mira-35c`, or `mira-10`.
43
46
  uuid: Set specific UUID for the file.
44
47
  date: Expected date as YYYY-MM-DD of all profiles in the file.
45
48
 
@@ -96,7 +99,8 @@ def mira2nc(
96
99
  mira.mask_bad_angles()
97
100
  mira.add_time_and_range()
98
101
  mira.add_site_geolocation()
99
- mira.add_radar_specific_variables()
102
+ mira.add_radar_frequency()
103
+ mira.broadcast_nyquist_velocity()
100
104
  valid_indices = mira.add_zenith_and_azimuth_angles(
101
105
  elevation_threshold=1.1,
102
106
  elevation_diff_threshold=1e-6,
@@ -114,7 +118,7 @@ def mira2nc(
114
118
 
115
119
 
116
120
  class Mira(NcRadar):
117
- """Class for MIRA-35 raw radar data. Child of NcRadar().
121
+ """Class for MIRA raw radar data. Child of NcRadar().
118
122
 
119
123
  Args:
120
124
  full_path: Filename of a daily MIRA .mmclx NetCDF file.
@@ -127,14 +131,44 @@ class Mira(NcRadar):
127
131
  def __init__(self, full_path: str | PathLike, site_meta: dict) -> None:
128
132
  super().__init__(full_path, site_meta)
129
133
  self.date = self._init_mira_date()
134
+ self.hrd = self._read_hrd()
130
135
  if "model" not in site_meta or site_meta["model"] == "mira-35":
131
136
  self.instrument = MIRA35
137
+ elif site_meta["model"] == "mira-35s":
138
+ self.instrument = MIRA35S
139
+ elif site_meta["model"] == "mira-35c":
140
+ self.instrument = MIRA35C
132
141
  elif site_meta["model"] == "mira-10":
133
142
  self.instrument = MIRA10
134
143
  else:
135
144
  msg = f"Invalid model: {site_meta['model']}"
136
145
  raise ValueError(msg)
137
146
 
147
+ def _read_hrd(self) -> dict[str, str]:
148
+ lines = self.dataset.hrd.split("\n")
149
+ output = {}
150
+ for line in lines:
151
+ if ":" not in line:
152
+ continue
153
+ key, value = line.split(":", maxsplit=1)
154
+ output[key] = value.strip()
155
+ return output
156
+
157
+ def add_radar_frequency(self) -> None:
158
+ # XMT should always be present. In newer files, there's also
159
+ # LO_frequency variable which doesn't match XMT exactly and sometimes
160
+ # contains only zeros.
161
+ key = "radar_frequency"
162
+ frequency = float(self.hrd["XMT"]) * HZ_TO_GHZ
163
+ self.data[key] = CloudnetArray(frequency, key)
164
+
165
+ def broadcast_nyquist_velocity(self) -> None:
166
+ # Scalar in original file, 1d array in concatenated file.
167
+ key = "nyquist_velocity"
168
+ nv = self.data[key].data
169
+ if len(nv.shape) == 1:
170
+ self.data[key].data = ma.getdata(nv)[:, np.newaxis]
171
+
138
172
  def screen_by_date(self, expected_date: datetime.date) -> None:
139
173
  """Screens incorrect time stamps."""
140
174
  time_stamps = self.getvar("time")
@@ -152,17 +186,36 @@ class Mira(NcRadar):
152
186
  return utils.seconds2date(float(time_stamps[0]), self.epoch).date()
153
187
 
154
188
  def screen_low_power(self) -> None:
155
- """Screen times with average transmit power close to zero."""
189
+ """Screen times with low average transmit power (tpow).
190
+
191
+ The expected average power depends on the specific model:
192
+
193
+ - MIRA-35 / 35S: average power should be between 30 and 60 W according
194
+ to the data sheet. Based on a random sample, tpow values range from 15
195
+ to 25 W.
196
+ - MIRA-35C: average power should be around 3 W according to the data
197
+ sheet. Based on a random sample, tpow values range from 1.5 to 2 W.
198
+ - MIRA-10: average power is up to 40 W (website) or 50 W (data sheet).
199
+
200
+ Please note that the raw tpow values cannot always be trusted:
201
+
202
+ - Files with SN:fzk and without FZK100 field in 'hrd' global attribute
203
+ should be multiplied by 100.
204
+ - It looks like tpow could contain the peak power instead of the average
205
+ power. As of now, this has only be seen in Munich MIRA-10, but because
206
+ this is the only MIRA-10 in Cloudnet, let's leave it as it is.
207
+
208
+ Example case:
209
+
210
+ - Limassol 2024-10-20: https://hdl.handle.net/21.12132/1.159fe518fe5b403d
211
+ """
156
212
  if "tpow" not in self.data:
157
213
  logging.warning("Variable tpow is missing")
158
214
  return
159
215
  self._correct_fzk_tpow()
160
216
  tpow = self.data["tpow"][:]
161
- # Threshold for abnormally low power e.g. Limassol 2024-10-20. Average
162
- # power should 30 to 60 W according to MIRA-35 data sheet. Based on a
163
- # random sample, typical range is 15 to 25 W. In Lampedusa, the power is
164
- # constantly as low as 1.9 W.
165
- is_low = tpow < 1
217
+ low_threshold = 0.5 if self.instrument == MIRA35C else 5
218
+ is_low = tpow < low_threshold
166
219
  n_removed = np.count_nonzero(is_low)
167
220
  if n_removed > 0:
168
221
  logging.warning(
@@ -171,21 +224,17 @@ class Mira(NcRadar):
171
224
  self.screen_time_indices(~is_low)
172
225
 
173
226
  def _correct_fzk_tpow(self) -> None:
174
- """Corrects tpow for old FZK-serial instruments missing the FZK100 fix.
227
+ """Corrects tpow for old instruments missing the FZK100 fix.
228
+
229
+ In old MIRA-35 files with 'SN:fzk', tpow was reported 100x too small
230
+ (e.g. Schneefernerhaus 2012-01-01). The tpow was corrected in a firmware
231
+ update as indicated by 'FZK100: 1.00000' in the 'hrd' global
232
+ attribute (e.g. Schneefernerhaus 2018-01-01).
175
233
 
176
- Some MIRA-35 instruments with serial number 'fzk' had a firmware bug
177
- where tpow was reported 100x too small. Files produced after the
178
- firmware fix contain 'FZK100' in the 'hrd' global attribute. Files
179
- without this field need tpow multiplied by 100.
234
+ Please note that this doesn't affect all old MIRA-35 instruments (e.g.
235
+ 'SN:dwd', Lindenberg 2007-01-01).
180
236
  """
181
- hrd = getattr(self.dataset, "hrd", "")
182
- if "FZK100" in hrd:
183
- return
184
- sn_lines = [line for line in hrd.split("\n") if line.strip().startswith("SN:")]
185
- if not sn_lines:
186
- return
187
- sn = sn_lines[0].split(":", 1)[1].strip()
188
- if sn != "fzk":
237
+ if self.hrd["SN"] != "fzk" or "FZK100" in self.hrd:
189
238
  return
190
239
  logging.info("Correcting tpow by factor 100 for old FZK instrument firmware")
191
240
  self.data["tpow"].data[:] *= 100
@@ -197,6 +246,11 @@ class Mira(NcRadar):
197
246
  """
198
247
  if "ldr" not in self.data:
199
248
  return
249
+ # Delete LDR if polarization is off. The LDR variable exists but
250
+ # contains no data. At least Munich MIRA-10 doesn't have polarization.
251
+ if self.hrd["POL"] == "0":
252
+ del self.data["ldr"]
253
+ return
200
254
  ldr = self.data["ldr"][:]
201
255
  if ma.mean(ldr) > 0:
202
256
  logging.warning(
@@ -314,6 +368,7 @@ def _get_keymap(filetype: str) -> dict[str, str]:
314
368
  ("nave", "nave"),
315
369
  ("prf", "prf"),
316
370
  ("rg0", "rg0"),
371
+ ("NyquistVelocity", "nyquist_velocity"),
317
372
  ("tpow", "tpow"),
318
373
  ],
319
374
  ),
@@ -331,7 +386,7 @@ def _get_keymap(filetype: str) -> dict[str, str]:
331
386
  ("nave", "nave"),
332
387
  ("prf", "prf"),
333
388
  ("rg0", "rg0"),
334
- ("NyquistVelocity", "NyquistVelocity"), # variable in some mmclx files
389
+ ("NyquistVelocity", "nyquist_velocity"),
335
390
  ("tpow", "tpow"),
336
391
  ]
337
392
  ),
@@ -0,0 +1,6 @@
1
+ from cloudnetpy.model_evaluation.plotting.plotting import generate_L3_day_plots
2
+ from cloudnetpy.model_evaluation.products.product_resampling import (
3
+ process_L3_day_product,
4
+ )
5
+
6
+ __all__ = ["generate_L3_day_plots", "process_L3_day_product"]
@@ -103,8 +103,7 @@ def generate_L3_day_plots(
103
103
  separated from standard timegrid to their own figures.
104
104
 
105
105
  Examples:
106
- >>> from cloudnetpy.model_evaluation.plotting.plotting
107
- import generate_L3_day_plots
106
+ >>> from cloudnetpy.model_evaluation import generate_L3_day_plots
108
107
  >>> l3_day_file = 'cf_ecmwf.nc'
109
108
  >>> product = 'cf'
110
109
  >>> generate_L3_day_plots(l3_day_file, product)
@@ -55,8 +55,7 @@ def process_L3_day_product(
55
55
  FileExistsError: Output file exists and overwrite is False.
56
56
 
57
57
  Examples:
58
- >>> from cloudnetpy.model_evaluation.products.product_resampling import \
59
- process_L3_day_product
58
+ >>> from cloudnetpy.model_evaluation import process_L3_day_product
60
59
  >>> process_L3_day_product('ecmwf', 'cf', 'ecmwf.nc',
61
60
  ... 'categorize.nc', 'l3-cf.nc')
62
61
  """
@@ -37,7 +37,7 @@ def test_calculate_advection_time_hour(model_file) -> None:
37
37
  expected = resolution * 1000 / wind / 60**2
38
38
  expected[expected > 1 / sampling] = 1 / sampling
39
39
  expected = np.asarray([[timedelta(hours=float(t)) for t in tt] for tt in expected])
40
- result = tools.calculate_advection_time(resolution, ma.masked_array(wind), sampling)
40
+ result = tools.calculate_advection_time(resolution, ma.array(wind), sampling)
41
41
  assert result.all() == expected.all()
42
42
 
43
43
 
@@ -49,14 +49,14 @@ def test_calculate_advection_time_10min(model_file) -> None:
49
49
  expected = resolution * 1000 / wind / 60**2
50
50
  expected[expected > 1 / sampling] = 1 / sampling
51
51
  expected = np.asarray([[timedelta(hours=float(t)) for t in tt] for tt in expected])
52
- result = tools.calculate_advection_time(resolution, ma.masked_array(wind), sampling)
52
+ result = tools.calculate_advection_time(resolution, ma.array(wind), sampling)
53
53
  assert result.all() == expected.all()
54
54
 
55
55
 
56
56
  def test_calculate_advection_time_fractional_resolution() -> None:
57
57
  # A sub-kilometre / fractional resolution must not be truncated to int.
58
58
  resolution = 0.5
59
- wind = ma.masked_array([[2.0]])
59
+ wind = ma.array([[2.0]])
60
60
  sampling = 6
61
61
  result = tools.calculate_advection_time(resolution, wind, sampling)
62
62
  expected = timedelta(hours=resolution * 1000 / 2.0 / 60**2)
@@ -671,7 +671,7 @@ class Plot2D(Plot):
671
671
  if "rain_detected" not in figure_data.file.variables:
672
672
  return
673
673
  rain = figure_data.file.variables["rain_detected"][:]
674
- is_rain: ma.MaskedArray = ma.masked_array(np.zeros_like(rain), mask=(rain == 0))
674
+ is_rain: ma.MaskedArray = ma.array(np.zeros_like(rain), mask=(rain == 0))
675
675
  if is_rain.mask.all():
676
676
  return
677
677
  self._ax.plot(
@@ -344,7 +344,7 @@ class LwcError:
344
344
 
345
345
  def _calc_lwc_gradient(self) -> npt.NDArray:
346
346
  if not isinstance(self.lwc, ma.MaskedArray):
347
- self.lwc = ma.masked_array(self.lwc)
347
+ self.lwc = ma.array(self.lwc)
348
348
  gradient_elements = np.gradient(self.lwc.filled(0))
349
349
  return utils.l2norm(*gradient_elements)
350
350
 
@@ -146,7 +146,7 @@ def rebin_2d(
146
146
  stat_fn = REBIN_STAT_FN[statistic]
147
147
 
148
148
  shape = array.shape if keepdim else (n_bins, array.shape[1])
149
- result: ma.MaskedArray = ma.masked_array(np.ones(shape, dtype="float32"), mask=True)
149
+ result: ma.MaskedArray = ma.array(np.ones(shape, dtype="float32"), mask=True)
150
150
 
151
151
  for bin_ind in range(n_bins):
152
152
  if counts[bin_ind] < n_min:
@@ -1,4 +1,4 @@
1
1
  MAJOR = 1
2
2
  MINOR = 93
3
- PATCH = 4
3
+ PATCH = 5
4
4
  __version__ = f"{MAJOR}.{MINOR}.{PATCH}"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cloudnetpy
3
- Version: 1.93.4
3
+ Version: 1.93.5
4
4
  Summary: Python package for Cloudnet processing
5
5
  Author: Simo Tukiainen
6
6
  License: MIT License
@@ -106,12 +106,23 @@ python3 -m pip install .
106
106
 
107
107
  ### Verification
108
108
 
109
- To verify the installation:
109
+ Verify the installation by running `cloudnetpy --help`.
110
+
111
+ ## Command-line usage
112
+
113
+ CloudnetPy ships with a `cloudnetpy` console script that fetches data from the
114
+ [Cloudnet data portal](https://cloudnet.fmi.fi), runs the requested processing
115
+ steps, and writes netCDF files (and optionally plots) to disk:
110
116
 
111
117
  ```sh
112
- cloudnetpy --help
118
+ cloudnetpy --site munich --date 2023-07-29 --products radar --show
119
+ cloudnetpy --site kenttarova --date 2025-07-29 --products classification --show
120
+ cloudnetpy -s kenttarova -d 2025-05-28 -p l3-cf -m harmonie-fmi-6-11 --show
113
121
  ```
114
122
 
123
+ See the [command-line usage documentation](https://actris-cloudnet.github.io/cloudnetpy/cli.html)
124
+ for instrument selection, different products, plotting, and all options.
125
+
115
126
  ## Citing
116
127
 
117
128
  If you wish to acknowledge CloudnetPy in your publication, please cite:
File without changes
File without changes
File without changes
File without changes