cloudnetpy 1.96.0__tar.gz → 1.96.2__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 (149) hide show
  1. {cloudnetpy-1.96.0/cloudnetpy.egg-info → cloudnetpy-1.96.2}/PKG-INFO +3 -3
  2. {cloudnetpy-1.96.0 → cloudnetpy-1.96.2}/cloudnetpy/categorize/attenuations/__init__.py +2 -2
  3. {cloudnetpy-1.96.0 → cloudnetpy-1.96.2}/cloudnetpy/categorize/classify.py +1 -1
  4. {cloudnetpy-1.96.0 → cloudnetpy-1.96.2}/cloudnetpy/categorize/containers.py +2 -1
  5. {cloudnetpy-1.96.0 → cloudnetpy-1.96.2}/cloudnetpy/categorize/falling.py +1 -1
  6. {cloudnetpy-1.96.0 → cloudnetpy-1.96.2}/cloudnetpy/categorize/freezing.py +1 -1
  7. {cloudnetpy-1.96.0 → cloudnetpy-1.96.2}/cloudnetpy/categorize/melting.py +1 -1
  8. {cloudnetpy-1.96.0 → cloudnetpy-1.96.2}/cloudnetpy/categorize/radar.py +3 -6
  9. {cloudnetpy-1.96.0 → cloudnetpy-1.96.2}/cloudnetpy/constants.py +16 -16
  10. {cloudnetpy-1.96.0 → cloudnetpy-1.96.2}/cloudnetpy/disdronator/lpm.py +13 -2
  11. {cloudnetpy-1.96.0 → cloudnetpy-1.96.2}/cloudnetpy/disdronator/parsivel.py +6 -2
  12. {cloudnetpy-1.96.0 → cloudnetpy-1.96.2}/cloudnetpy/disdronator/process.py +12 -9
  13. {cloudnetpy-1.96.0 → cloudnetpy-1.96.2}/cloudnetpy/disdronator/rd80.py +10 -1
  14. cloudnetpy-1.96.2/cloudnetpy/disdronator/utils.py +69 -0
  15. {cloudnetpy-1.96.0 → cloudnetpy-1.96.2}/cloudnetpy/instruments/disdrometer.py +3 -3
  16. {cloudnetpy-1.96.0 → cloudnetpy-1.96.2}/cloudnetpy/instruments/fd12p.py +3 -4
  17. {cloudnetpy-1.96.0 → cloudnetpy-1.96.2}/cloudnetpy/instruments/hatpro.py +2 -2
  18. {cloudnetpy-1.96.0 → cloudnetpy-1.96.2}/cloudnetpy/instruments/mmcr.py +136 -3
  19. {cloudnetpy-1.96.0 → cloudnetpy-1.96.2}/cloudnetpy/instruments/mwr3c.py +1 -1
  20. {cloudnetpy-1.96.0 → cloudnetpy-1.96.2}/cloudnetpy/instruments/mwrlos.py +1 -1
  21. {cloudnetpy-1.96.0 → cloudnetpy-1.96.2}/cloudnetpy/instruments/radiometrics.py +6 -5
  22. {cloudnetpy-1.96.0 → cloudnetpy-1.96.2}/cloudnetpy/instruments/rain_e_h3.py +3 -4
  23. {cloudnetpy-1.96.0 → cloudnetpy-1.96.2}/cloudnetpy/instruments/weather_station.py +12 -6
  24. {cloudnetpy-1.96.0 → cloudnetpy-1.96.2}/cloudnetpy/model_evaluation/plotting/plotting.py +2 -1
  25. {cloudnetpy-1.96.0 → cloudnetpy-1.96.2}/cloudnetpy/model_evaluation/products/advance_methods.py +2 -1
  26. {cloudnetpy-1.96.0 → cloudnetpy-1.96.2}/cloudnetpy/model_evaluation/products/model_products.py +1 -1
  27. {cloudnetpy-1.96.0 → cloudnetpy-1.96.2}/cloudnetpy/model_evaluation/tests/unit/test_model_products.py +1 -1
  28. {cloudnetpy-1.96.0 → cloudnetpy-1.96.2}/cloudnetpy/plotting/plotting.py +11 -10
  29. {cloudnetpy-1.96.0 → cloudnetpy-1.96.2}/cloudnetpy/products/cod.py +1 -4
  30. {cloudnetpy-1.96.0 → cloudnetpy-1.96.2}/cloudnetpy/products/der.py +6 -4
  31. {cloudnetpy-1.96.0 → cloudnetpy-1.96.2}/cloudnetpy/products/drizzle.py +2 -3
  32. {cloudnetpy-1.96.0 → cloudnetpy-1.96.2}/cloudnetpy/products/drizzle_error.py +3 -5
  33. {cloudnetpy-1.96.0 → cloudnetpy-1.96.2}/cloudnetpy/products/epsilon_lidar.py +2 -3
  34. {cloudnetpy-1.96.0 → cloudnetpy-1.96.2}/cloudnetpy/products/iwc_weather_radar.py +3 -2
  35. {cloudnetpy-1.96.0 → cloudnetpy-1.96.2}/cloudnetpy/products/mwr_tools.py +17 -3
  36. {cloudnetpy-1.96.0 → cloudnetpy-1.96.2}/cloudnetpy/utils.py +2 -1
  37. {cloudnetpy-1.96.0 → cloudnetpy-1.96.2}/cloudnetpy/version.py +1 -1
  38. {cloudnetpy-1.96.0 → cloudnetpy-1.96.2/cloudnetpy.egg-info}/PKG-INFO +3 -3
  39. {cloudnetpy-1.96.0 → cloudnetpy-1.96.2}/cloudnetpy.egg-info/requires.txt +2 -2
  40. {cloudnetpy-1.96.0 → cloudnetpy-1.96.2}/pyproject.toml +2 -2
  41. cloudnetpy-1.96.0/cloudnetpy/disdronator/utils.py +0 -38
  42. {cloudnetpy-1.96.0 → cloudnetpy-1.96.2}/LICENSE +0 -0
  43. {cloudnetpy-1.96.0 → cloudnetpy-1.96.2}/MANIFEST.in +0 -0
  44. {cloudnetpy-1.96.0 → cloudnetpy-1.96.2}/README.md +0 -0
  45. {cloudnetpy-1.96.0 → cloudnetpy-1.96.2}/cloudnetpy/__init__.py +0 -0
  46. {cloudnetpy-1.96.0 → cloudnetpy-1.96.2}/cloudnetpy/arm.py +0 -0
  47. {cloudnetpy-1.96.0 → cloudnetpy-1.96.2}/cloudnetpy/categorize/__init__.py +0 -0
  48. {cloudnetpy-1.96.0 → cloudnetpy-1.96.2}/cloudnetpy/categorize/atmos_utils.py +0 -0
  49. {cloudnetpy-1.96.0 → cloudnetpy-1.96.2}/cloudnetpy/categorize/attenuation.py +0 -0
  50. {cloudnetpy-1.96.0 → cloudnetpy-1.96.2}/cloudnetpy/categorize/attenuations/gas_attenuation.py +0 -0
  51. {cloudnetpy-1.96.0 → cloudnetpy-1.96.2}/cloudnetpy/categorize/attenuations/liquid_attenuation.py +0 -0
  52. {cloudnetpy-1.96.0 → cloudnetpy-1.96.2}/cloudnetpy/categorize/attenuations/melting_attenuation.py +0 -0
  53. {cloudnetpy-1.96.0 → cloudnetpy-1.96.2}/cloudnetpy/categorize/attenuations/rain_attenuation.py +0 -0
  54. {cloudnetpy-1.96.0 → cloudnetpy-1.96.2}/cloudnetpy/categorize/categorize.py +0 -0
  55. {cloudnetpy-1.96.0 → cloudnetpy-1.96.2}/cloudnetpy/categorize/disdrometer.py +0 -0
  56. {cloudnetpy-1.96.0 → cloudnetpy-1.96.2}/cloudnetpy/categorize/droplet.py +0 -0
  57. {cloudnetpy-1.96.0 → cloudnetpy-1.96.2}/cloudnetpy/categorize/insects.py +0 -0
  58. {cloudnetpy-1.96.0 → cloudnetpy-1.96.2}/cloudnetpy/categorize/lidar.py +0 -0
  59. {cloudnetpy-1.96.0 → cloudnetpy-1.96.2}/cloudnetpy/categorize/model.py +0 -0
  60. {cloudnetpy-1.96.0 → cloudnetpy-1.96.2}/cloudnetpy/categorize/mwr.py +0 -0
  61. {cloudnetpy-1.96.0 → cloudnetpy-1.96.2}/cloudnetpy/cli.py +0 -0
  62. {cloudnetpy-1.96.0 → cloudnetpy-1.96.2}/cloudnetpy/cloudnetarray.py +0 -0
  63. {cloudnetpy-1.96.0 → cloudnetpy-1.96.2}/cloudnetpy/concat_lib.py +0 -0
  64. {cloudnetpy-1.96.0 → cloudnetpy-1.96.2}/cloudnetpy/datasource.py +0 -0
  65. {cloudnetpy-1.96.0 → cloudnetpy-1.96.2}/cloudnetpy/disdronator/__init__.py +0 -0
  66. {cloudnetpy-1.96.0 → cloudnetpy-1.96.2}/cloudnetpy/exceptions.py +0 -0
  67. {cloudnetpy-1.96.0 → cloudnetpy-1.96.2}/cloudnetpy/instruments/__init__.py +0 -0
  68. {cloudnetpy-1.96.0 → cloudnetpy-1.96.2}/cloudnetpy/instruments/arm_ceilo.py +0 -0
  69. {cloudnetpy-1.96.0 → cloudnetpy-1.96.2}/cloudnetpy/instruments/arm_ld.py +0 -0
  70. {cloudnetpy-1.96.0 → cloudnetpy-1.96.2}/cloudnetpy/instruments/arm_utils.py +0 -0
  71. {cloudnetpy-1.96.0 → cloudnetpy-1.96.2}/cloudnetpy/instruments/basta.py +0 -0
  72. {cloudnetpy-1.96.0 → cloudnetpy-1.96.2}/cloudnetpy/instruments/bowtie.py +0 -0
  73. {cloudnetpy-1.96.0 → cloudnetpy-1.96.2}/cloudnetpy/instruments/ceilo.py +0 -0
  74. {cloudnetpy-1.96.0 → cloudnetpy-1.96.2}/cloudnetpy/instruments/ceilometer.py +0 -0
  75. {cloudnetpy-1.96.0 → cloudnetpy-1.96.2}/cloudnetpy/instruments/cl61d.py +0 -0
  76. {cloudnetpy-1.96.0 → cloudnetpy-1.96.2}/cloudnetpy/instruments/cloudnet_instrument.py +0 -0
  77. {cloudnetpy-1.96.0 → cloudnetpy-1.96.2}/cloudnetpy/instruments/copernicus.py +0 -0
  78. {cloudnetpy-1.96.0 → cloudnetpy-1.96.2}/cloudnetpy/instruments/da10.py +0 -0
  79. {cloudnetpy-1.96.0 → cloudnetpy-1.96.2}/cloudnetpy/instruments/dealias.py +0 -0
  80. {cloudnetpy-1.96.0 → cloudnetpy-1.96.2}/cloudnetpy/instruments/galileo.py +0 -0
  81. {cloudnetpy-1.96.0 → cloudnetpy-1.96.2}/cloudnetpy/instruments/instruments.py +0 -0
  82. {cloudnetpy-1.96.0 → cloudnetpy-1.96.2}/cloudnetpy/instruments/kazr.py +0 -0
  83. {cloudnetpy-1.96.0 → cloudnetpy-1.96.2}/cloudnetpy/instruments/lufft.py +0 -0
  84. {cloudnetpy-1.96.0 → cloudnetpy-1.96.2}/cloudnetpy/instruments/mira.py +0 -0
  85. {cloudnetpy-1.96.0 → cloudnetpy-1.96.2}/cloudnetpy/instruments/mrr.py +0 -0
  86. {cloudnetpy-1.96.0 → cloudnetpy-1.96.2}/cloudnetpy/instruments/nc_lidar.py +0 -0
  87. {cloudnetpy-1.96.0 → cloudnetpy-1.96.2}/cloudnetpy/instruments/nc_radar.py +0 -0
  88. {cloudnetpy-1.96.0 → cloudnetpy-1.96.2}/cloudnetpy/instruments/pollyxt.py +0 -0
  89. {cloudnetpy-1.96.0 → cloudnetpy-1.96.2}/cloudnetpy/instruments/rpg.py +0 -0
  90. {cloudnetpy-1.96.0 → cloudnetpy-1.96.2}/cloudnetpy/instruments/rpg_reader.py +0 -0
  91. {cloudnetpy-1.96.0 → cloudnetpy-1.96.2}/cloudnetpy/instruments/toa5.py +0 -0
  92. {cloudnetpy-1.96.0 → cloudnetpy-1.96.2}/cloudnetpy/instruments/vaisala.py +0 -0
  93. {cloudnetpy-1.96.0 → cloudnetpy-1.96.2}/cloudnetpy/instruments/weather_radar.py +0 -0
  94. {cloudnetpy-1.96.0 → cloudnetpy-1.96.2}/cloudnetpy/metadata.py +0 -0
  95. {cloudnetpy-1.96.0 → cloudnetpy-1.96.2}/cloudnetpy/model_evaluation/__init__.py +0 -0
  96. {cloudnetpy-1.96.0 → cloudnetpy-1.96.2}/cloudnetpy/model_evaluation/file_handler.py +0 -0
  97. {cloudnetpy-1.96.0 → cloudnetpy-1.96.2}/cloudnetpy/model_evaluation/metadata.py +0 -0
  98. {cloudnetpy-1.96.0 → cloudnetpy-1.96.2}/cloudnetpy/model_evaluation/model_metadata.py +0 -0
  99. {cloudnetpy-1.96.0 → cloudnetpy-1.96.2}/cloudnetpy/model_evaluation/plotting/__init__.py +0 -0
  100. {cloudnetpy-1.96.0 → cloudnetpy-1.96.2}/cloudnetpy/model_evaluation/plotting/plot_meta.py +0 -0
  101. {cloudnetpy-1.96.0 → cloudnetpy-1.96.2}/cloudnetpy/model_evaluation/plotting/plot_tools.py +0 -0
  102. {cloudnetpy-1.96.0 → cloudnetpy-1.96.2}/cloudnetpy/model_evaluation/products/__init__.py +0 -0
  103. {cloudnetpy-1.96.0 → cloudnetpy-1.96.2}/cloudnetpy/model_evaluation/products/grid_methods.py +0 -0
  104. {cloudnetpy-1.96.0 → cloudnetpy-1.96.2}/cloudnetpy/model_evaluation/products/observation_products.py +0 -0
  105. {cloudnetpy-1.96.0 → cloudnetpy-1.96.2}/cloudnetpy/model_evaluation/products/product_resampling.py +0 -0
  106. {cloudnetpy-1.96.0 → cloudnetpy-1.96.2}/cloudnetpy/model_evaluation/products/tools.py +0 -0
  107. {cloudnetpy-1.96.0 → cloudnetpy-1.96.2}/cloudnetpy/model_evaluation/statistics/__init__.py +0 -0
  108. {cloudnetpy-1.96.0 → cloudnetpy-1.96.2}/cloudnetpy/model_evaluation/statistics/statistical_methods.py +0 -0
  109. {cloudnetpy-1.96.0 → cloudnetpy-1.96.2}/cloudnetpy/model_evaluation/tests/__init__.py +0 -0
  110. {cloudnetpy-1.96.0 → cloudnetpy-1.96.2}/cloudnetpy/model_evaluation/tests/e2e/__init__.py +0 -0
  111. {cloudnetpy-1.96.0 → cloudnetpy-1.96.2}/cloudnetpy/model_evaluation/tests/e2e/conftest.py +0 -0
  112. {cloudnetpy-1.96.0 → cloudnetpy-1.96.2}/cloudnetpy/model_evaluation/tests/e2e/process_cf/__init__.py +0 -0
  113. {cloudnetpy-1.96.0 → cloudnetpy-1.96.2}/cloudnetpy/model_evaluation/tests/e2e/process_cf/main.py +0 -0
  114. {cloudnetpy-1.96.0 → cloudnetpy-1.96.2}/cloudnetpy/model_evaluation/tests/e2e/process_cf/tests.py +0 -0
  115. {cloudnetpy-1.96.0 → cloudnetpy-1.96.2}/cloudnetpy/model_evaluation/tests/e2e/process_iwc/__init__.py +0 -0
  116. {cloudnetpy-1.96.0 → cloudnetpy-1.96.2}/cloudnetpy/model_evaluation/tests/e2e/process_iwc/main.py +0 -0
  117. {cloudnetpy-1.96.0 → cloudnetpy-1.96.2}/cloudnetpy/model_evaluation/tests/e2e/process_iwc/tests.py +0 -0
  118. {cloudnetpy-1.96.0 → cloudnetpy-1.96.2}/cloudnetpy/model_evaluation/tests/e2e/process_lwc/__init__.py +0 -0
  119. {cloudnetpy-1.96.0 → cloudnetpy-1.96.2}/cloudnetpy/model_evaluation/tests/e2e/process_lwc/main.py +0 -0
  120. {cloudnetpy-1.96.0 → cloudnetpy-1.96.2}/cloudnetpy/model_evaluation/tests/e2e/process_lwc/tests.py +0 -0
  121. {cloudnetpy-1.96.0 → cloudnetpy-1.96.2}/cloudnetpy/model_evaluation/tests/unit/__init__.py +0 -0
  122. {cloudnetpy-1.96.0 → cloudnetpy-1.96.2}/cloudnetpy/model_evaluation/tests/unit/conftest.py +0 -0
  123. {cloudnetpy-1.96.0 → cloudnetpy-1.96.2}/cloudnetpy/model_evaluation/tests/unit/test_advance_methods.py +0 -0
  124. {cloudnetpy-1.96.0 → cloudnetpy-1.96.2}/cloudnetpy/model_evaluation/tests/unit/test_grid_methods.py +0 -0
  125. {cloudnetpy-1.96.0 → cloudnetpy-1.96.2}/cloudnetpy/model_evaluation/tests/unit/test_observation_products.py +0 -0
  126. {cloudnetpy-1.96.0 → cloudnetpy-1.96.2}/cloudnetpy/model_evaluation/tests/unit/test_plot_tools.py +0 -0
  127. {cloudnetpy-1.96.0 → cloudnetpy-1.96.2}/cloudnetpy/model_evaluation/tests/unit/test_plotting.py +0 -0
  128. {cloudnetpy-1.96.0 → cloudnetpy-1.96.2}/cloudnetpy/model_evaluation/tests/unit/test_statistical_methods.py +0 -0
  129. {cloudnetpy-1.96.0 → cloudnetpy-1.96.2}/cloudnetpy/model_evaluation/tests/unit/test_tools.py +0 -0
  130. {cloudnetpy-1.96.0 → cloudnetpy-1.96.2}/cloudnetpy/model_evaluation/utils.py +0 -0
  131. {cloudnetpy-1.96.0 → cloudnetpy-1.96.2}/cloudnetpy/output.py +0 -0
  132. {cloudnetpy-1.96.0 → cloudnetpy-1.96.2}/cloudnetpy/plotting/__init__.py +0 -0
  133. {cloudnetpy-1.96.0 → cloudnetpy-1.96.2}/cloudnetpy/plotting/plot_meta.py +0 -0
  134. {cloudnetpy-1.96.0 → cloudnetpy-1.96.2}/cloudnetpy/products/__init__.py +0 -0
  135. {cloudnetpy-1.96.0 → cloudnetpy-1.96.2}/cloudnetpy/products/classification.py +0 -0
  136. {cloudnetpy-1.96.0 → cloudnetpy-1.96.2}/cloudnetpy/products/drizzle_tools.py +0 -0
  137. {cloudnetpy-1.96.0 → cloudnetpy-1.96.2}/cloudnetpy/products/epsilon_radar.py +0 -0
  138. {cloudnetpy-1.96.0 → cloudnetpy-1.96.2}/cloudnetpy/products/ier.py +0 -0
  139. {cloudnetpy-1.96.0 → cloudnetpy-1.96.2}/cloudnetpy/products/iwc.py +0 -0
  140. {cloudnetpy-1.96.0 → cloudnetpy-1.96.2}/cloudnetpy/products/lwc.py +0 -0
  141. {cloudnetpy-1.96.0 → cloudnetpy-1.96.2}/cloudnetpy/products/mie_lu_tables.nc +0 -0
  142. {cloudnetpy-1.96.0 → cloudnetpy-1.96.2}/cloudnetpy/products/product_tools.py +0 -0
  143. {cloudnetpy-1.96.0 → cloudnetpy-1.96.2}/cloudnetpy/py.typed +0 -0
  144. {cloudnetpy-1.96.0 → cloudnetpy-1.96.2}/cloudnetpy.egg-info/SOURCES.txt +0 -0
  145. {cloudnetpy-1.96.0 → cloudnetpy-1.96.2}/cloudnetpy.egg-info/dependency_links.txt +0 -0
  146. {cloudnetpy-1.96.0 → cloudnetpy-1.96.2}/cloudnetpy.egg-info/entry_points.txt +0 -0
  147. {cloudnetpy-1.96.0 → cloudnetpy-1.96.2}/cloudnetpy.egg-info/top_level.txt +0 -0
  148. {cloudnetpy-1.96.0 → cloudnetpy-1.96.2}/docs/source/conf.py +0 -0
  149. {cloudnetpy-1.96.0 → cloudnetpy-1.96.2}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cloudnetpy
3
- Version: 1.96.0
3
+ Version: 1.96.2
4
4
  Summary: Python package for Cloudnet processing
5
5
  Author: Simo Tukiainen
6
6
  License: MIT License
@@ -38,12 +38,12 @@ Classifier: Topic :: Scientific/Engineering :: Atmospheric Science
38
38
  Requires-Python: >=3.10
39
39
  Description-Content-Type: text/markdown
40
40
  License-File: LICENSE
41
- Requires-Dist: atmoslib>=2.0.0
41
+ Requires-Dist: atmoslib>=2.4.2
42
42
  Requires-Dist: ceilopyter>=0.2.0
43
43
  Requires-Dist: cloudnet-api-client
44
44
  Requires-Dist: doppy>=0.5.0
45
45
  Requires-Dist: matplotlib
46
- Requires-Dist: mwrpy>=1.3.5
46
+ Requires-Dist: mwrpy>=1.7.0
47
47
  Requires-Dist: netCDF4
48
48
  Requires-Dist: requests
49
49
  Requires-Dist: rpgpy>=0.14.5
@@ -31,7 +31,7 @@ def calc_two_way_attenuation(
31
31
  """Calculates two-way attenuation (dB) for given specific attenuation
32
32
  (dB km-1) and height above ground level (m).
33
33
  """
34
- path_lengths = path_lengths_from_ground(height_agl) * con.M_TO_KM # km
34
+ path_lengths = path_lengths_from_ground(height_agl) * con.M_TO_KM
35
35
  one_way_attenuation = specific_attenuation * path_lengths
36
36
  accumulated_attenuation = ma.cumsum(one_way_attenuation, axis=1)
37
- return accumulated_attenuation * con.TWO_WAY
37
+ return accumulated_attenuation * 2 # two way
@@ -1,5 +1,6 @@
1
1
  import numpy as np
2
2
  import numpy.typing as npt
3
+ from atmoslib.constants import T0
3
4
  from numpy import ma
4
5
  from scipy import ndimage
5
6
 
@@ -18,7 +19,6 @@ from cloudnetpy.categorize.containers import (
18
19
  ClassificationResult,
19
20
  Observations,
20
21
  )
21
- from cloudnetpy.constants import T0
22
22
  from cloudnetpy.products.product_tools import CategoryBits, QualityBits
23
23
 
24
24
 
@@ -4,10 +4,11 @@ from os import PathLike
4
4
 
5
5
  import numpy as np
6
6
  import numpy.typing as npt
7
+ from atmoslib.constants import T0
7
8
  from numpy import ma
8
9
 
9
10
  from cloudnetpy import utils
10
- from cloudnetpy.constants import MM_H_TO_M_S, T0
11
+ from cloudnetpy.constants import MM_H_TO_M_S
11
12
  from cloudnetpy.products.product_tools import CategoryBits
12
13
 
13
14
  from .disdrometer import Disdrometer
@@ -2,11 +2,11 @@
2
2
 
3
3
  import numpy as np
4
4
  import numpy.typing as npt
5
+ from atmoslib.constants import T0
5
6
  from numpy import ma
6
7
 
7
8
  from cloudnetpy.categorize import atmos_utils
8
9
  from cloudnetpy.categorize.containers import ClassData
9
- from cloudnetpy.constants import T0
10
10
 
11
11
 
12
12
  def find_falling_hydrometeors(
@@ -4,12 +4,12 @@ import logging
4
4
 
5
5
  import numpy as np
6
6
  import numpy.typing as npt
7
+ from atmoslib.constants import T0
7
8
  from numpy import ma
8
9
  from scipy.interpolate import interp1d
9
10
 
10
11
  from cloudnetpy import utils
11
12
  from cloudnetpy.categorize.containers import ClassData
12
- from cloudnetpy.constants import T0
13
13
 
14
14
 
15
15
  def find_freezing_region(obs: ClassData, melting_layer: npt.NDArray) -> npt.NDArray:
@@ -2,13 +2,13 @@
2
2
 
3
3
  import numpy as np
4
4
  import numpy.typing as npt
5
+ from atmoslib.constants import T0
5
6
  from numpy import ma
6
7
  from scipy.ndimage import gaussian_filter
7
8
 
8
9
  from cloudnetpy import utils
9
10
  from cloudnetpy.categorize import droplet
10
11
  from cloudnetpy.categorize.containers import ClassData
11
- from cloudnetpy.constants import T0
12
12
 
13
13
 
14
14
  def find_melting_layer(obs: ClassData, *, smooth: bool = True) -> npt.NDArray:
@@ -7,11 +7,10 @@ from os import PathLike
7
7
  import numpy as np
8
8
  import numpy.typing as npt
9
9
  from numpy import ma
10
- from scipy import constants
11
10
 
12
11
  from cloudnetpy import utils
13
12
  from cloudnetpy.categorize.attenuations import RadarAttenuation
14
- from cloudnetpy.constants import GHZ_TO_HZ, SEC_IN_HOUR, SPEED_OF_LIGHT
13
+ from cloudnetpy.constants import GHZ_TO_HZ, LN_TO_DB, SEC_IN_HOUR, SPEED_OF_LIGHT
15
14
  from cloudnetpy.datasource import DataSource
16
15
 
17
16
 
@@ -265,8 +264,7 @@ class Radar(DataSource):
265
264
  """
266
265
  noise_threshold = 3
267
266
  n_pulses = _number_of_independent_pulses()
268
- ln_to_log10 = 10 / np.log(10)
269
- z_precision = ma.divide(ln_to_log10, np.sqrt(n_pulses)) * (
267
+ z_precision = ma.divide(LN_TO_DB, np.sqrt(n_pulses)) * (
270
268
  1 + (utils.db2lin(z_power_min - z_power) / noise_threshold)
271
269
  )
272
270
 
@@ -439,8 +437,7 @@ class Radar(DataSource):
439
437
 
440
438
 
441
439
  def _prf_to_folding_velocity(prf: npt.NDArray, radar_frequency: float) -> npt.NDArray:
442
- ghz_to_hz = 1e9
443
440
  if len(prf) != 1:
444
441
  msg = "Unable to determine folding velocity"
445
442
  raise RuntimeError(msg)
446
- return prf[0] * constants.c / (4 * radar_frequency * ghz_to_hz)
443
+ return prf[0] * SPEED_OF_LIGHT / (4 * radar_frequency * GHZ_TO_HZ)
@@ -1,24 +1,21 @@
1
1
  """Constants used in Cloudnet processing."""
2
2
 
3
+ import math
3
4
  from typing import Final
4
5
 
5
- # Triple point of water
6
- T0: Final = 273.16
6
+ T_FREEZING: Final = 273.15
7
+ """Freezing point of water at standard pressure (K), i.e. 0 degrees Celsius"""
7
8
 
8
- # Ratio of the molecular weight of water vapor to dry air
9
- MW_RATIO: Final = 0.62198
10
-
11
- # Specific gas constant for dry air (J kg-1 K-1)
12
- RS: Final = 287.058
13
-
14
- # ice density kg m-3
15
9
  RHO_ICE: Final = 917
10
+ """Ice density (kg m-3)"""
11
+
12
+ RHO_WATER: Final = 1000
13
+ """Liquid water density (kg m-3)"""
16
14
 
17
- # Standard atmospheric pressure at sea level Pa
18
- P0: Final = 1013_25
15
+ SPEED_OF_LIGHT: Final = 299_792_458
16
+ """Speed of light in vacuum (m s-1)"""
19
17
 
20
- # other
21
- SPEED_OF_LIGHT: Final = 3.0e8
18
+ # Unit conversions
22
19
  SEC_IN_MINUTE: Final = 60
23
20
  SEC_IN_HOUR: Final = 3600
24
21
  SEC_IN_DAY: Final = 86400
@@ -35,7 +32,10 @@ MM_H_TO_M_S: Final = 1 / M_S_TO_MM_H
35
32
  GHZ_TO_HZ: Final = 1e9
36
33
  HZ_TO_GHZ: Final = 1e-9
37
34
  HPA_TO_PA: Final = 100
38
- PA_TO_HPA: Final = 1 / HPA_TO_PA
39
35
  KM_H_TO_M_S: Final = 1000 / SEC_IN_HOUR
40
- TWO_WAY: Final = 2
41
- G: Final = 9.80665
36
+
37
+ CM_TO_KG_M2: Final = 10
38
+ """Liquid water equivalent cm to kg m-2"""
39
+
40
+ LN_TO_DB: Final = 10 / math.log(10)
41
+ """Natural logarithm of a power ratio to decibels"""
@@ -1,4 +1,5 @@
1
1
  import datetime
2
+ import logging
2
3
  from collections import defaultdict
3
4
  from os import PathLike
4
5
  from typing import TypeAlias
@@ -109,9 +110,18 @@ def read_lpm(filename: str | PathLike) -> tuple[npt.NDArray, dict[int, npt.NDArr
109
110
 
110
111
 
111
112
  def read_lpm_l1(
112
- time: npt.NDArray, l0: dict[int, npt.NDArray], au: int | None = None
113
+ time: npt.NDArray,
114
+ l0: dict[int, npt.NDArray],
115
+ au: int | None = None,
116
+ altitude: float | None = None,
113
117
  ) -> DisdroL1:
114
- area_nom = 4600 * 1000 / au if au is not None else 4560
118
+ if au is None:
119
+ area_nom = 4560.0
120
+ logging.warning(
121
+ "No AU parameter given, assuming nominal sampling area: %d mm2", area_nom
122
+ )
123
+ else:
124
+ area_nom = 4600.0 * 1000.0 / au
115
125
  area_eff = area_nom * (1 - D / (2 * LASER_WIDTH))
116
126
  data_raw = np.stack([l0[i] for i in range(81, 521)], axis=1).reshape(
117
127
  (len(time), len(D), len(V))
@@ -128,6 +138,7 @@ def read_lpm_l1(
128
138
  area_nom=area_nom,
129
139
  area_eff=area_eff,
130
140
  data_raw=data_raw,
141
+ altitude=altitude,
131
142
  )
132
143
 
133
144
 
@@ -9,6 +9,7 @@ import netCDF4
9
9
  import numpy as np
10
10
  import numpy.typing as npt
11
11
 
12
+ from cloudnetpy.constants import M_S_TO_MM_H
12
13
  from cloudnetpy.disdronator.process import DisdroL1
13
14
  from cloudnetpy.disdronator.utils import convert_to_numpy
14
15
 
@@ -434,7 +435,7 @@ def _read_parsivel2nc(filename: str | PathLike) -> ParsivelOutput:
434
435
  time = cftime.num2pydate(nc["time"][:], units=nc["time"].units)
435
436
  data = {num: nc[key][:] for key, num in PARSIVEL2NC_KEYS.items()}
436
437
  # The data logger converts mm/h to m/s, so we need to revert this.
437
- data[1] *= 3600 * 1000
438
+ data[1] *= M_S_TO_MM_H
438
439
  # The data logger attempts to convert temperature from °C to K, but this
439
440
  # is incorrectly done only for the first value.
440
441
  data[12][0] -= 273
@@ -522,7 +523,9 @@ def read_parsivel(
522
523
  return np.array(time), convert_to_numpy(data, {}, INT_KEYS, FLOAT_KEYS)
523
524
 
524
525
 
525
- def read_parsivel_l1(time: npt.NDArray, l0: dict[int, npt.NDArray]) -> DisdroL1:
526
+ def read_parsivel_l1(
527
+ time: npt.NDArray, l0: dict[int, npt.NDArray], altitude: float | None = None
528
+ ) -> DisdroL1:
526
529
  if 93 not in l0:
527
530
  msg = "No raw data"
528
531
  raise ValueError(msg)
@@ -544,6 +547,7 @@ def read_parsivel_l1(time: npt.NDArray, l0: dict[int, npt.NDArray]) -> DisdroL1:
544
547
  area_nom=AREA_NOM,
545
548
  area_eff=AREA_EFF,
546
549
  data_raw=data_raw,
550
+ altitude=altitude,
547
551
  )
548
552
 
549
553
 
@@ -4,6 +4,7 @@ import numpy as np
4
4
  import numpy.typing as npt
5
5
  from numpy import ma
6
6
 
7
+ from cloudnetpy import constants
7
8
  from cloudnetpy.disdronator.utils import make_rain_mask
8
9
 
9
10
 
@@ -20,6 +21,7 @@ class DisdroL1:
20
21
  area_nom: float
21
22
  area_eff: npt.NDArray | None
22
23
  data_raw: npt.NDArray
24
+ altitude: float | None
23
25
 
24
26
 
25
27
  @dataclass
@@ -43,6 +45,7 @@ class DisdroL2:
43
45
  radar_refl: npt.NDArray
44
46
  energy_flux: npt.NDArray
45
47
  visibility: npt.NDArray
48
+ altitude: float | None
46
49
 
47
50
 
48
51
  def process_l2(l1: DisdroL1) -> DisdroL2:
@@ -61,10 +64,9 @@ def process_l2(l1: DisdroL1) -> DisdroL2:
61
64
  area_mm2 = (
62
65
  l1.area_eff if l1.area_eff is not None else np.repeat(l1.area_nom, n_diameter)
63
66
  )
64
- area_m2 = area_mm2 * 1e-6
65
- diameter_m = l1.diameter / 1000
66
- interval_h = interval / 3600
67
- rho_w = 1e-6 # kg mm-3
67
+ area_m2 = area_mm2 * constants.MM2_TO_M2
68
+ diameter_m = l1.diameter * constants.MM_TO_M
69
+ interval_h = interval / constants.SEC_IN_HOUR
68
70
 
69
71
  if spec.ndim == 2:
70
72
  number_concentration = spec / (
@@ -79,10 +81,10 @@ def process_l2(l1: DisdroL1) -> DisdroL2:
79
81
  energy_flux = (
80
82
  np.pi
81
83
  / 12
82
- * rho_w
84
+ * constants.RHO_WATER
83
85
  * np.sum(
84
86
  spec
85
- * l1.diameter**3
87
+ * diameter_m**3
86
88
  * l1.velocity**2
87
89
  / (area_m2 * interval_h[:, np.newaxis]),
88
90
  axis=1,
@@ -112,7 +114,7 @@ def process_l2(l1: DisdroL1) -> DisdroL2:
112
114
  fall_velocity = ma.divide(
113
115
  np.sum(l1.velocity * spec, axis=2), np.sum(spec, axis=2)
114
116
  )
115
- is_rain = make_rain_mask(l1.diameter, l1.velocity)
117
+ is_rain = make_rain_mask(l1.diameter, l1.velocity, altitude=l1.altitude)
116
118
  spec_rain = np.copy(spec)
117
119
  spec_rain[:, ~is_rain] = 0
118
120
  rain_amount = (
@@ -136,10 +138,10 @@ def process_l2(l1: DisdroL1) -> DisdroL2:
136
138
  energy_flux = (
137
139
  np.pi
138
140
  / 12
139
- * rho_w
141
+ * constants.RHO_WATER
140
142
  * np.sum(
141
143
  spec_rain
142
- * l1.diameter[:, np.newaxis] ** 3
144
+ * diameter_m[:, np.newaxis] ** 3
143
145
  * l1.velocity**2
144
146
  / (area_m2[:, np.newaxis] * interval_h[:, np.newaxis, np.newaxis]),
145
147
  axis=(1, 2),
@@ -190,4 +192,5 @@ def process_l2(l1: DisdroL1) -> DisdroL2:
190
192
  radar_refl=radar_refl_db,
191
193
  energy_flux=energy_flux,
192
194
  visibility=visibility,
195
+ altitude=l1.altitude,
193
196
  )
@@ -1,4 +1,5 @@
1
1
  import datetime
2
+ import logging
2
3
  from os import PathLike
3
4
 
4
5
  import numpy as np
@@ -35,7 +36,14 @@ def read_rd80(filename: str | PathLike) -> tuple[npt.NDArray, dict[str, npt.NDAr
35
36
  return np.array(time), convert_to_numpy(data)
36
37
 
37
38
 
38
- def read_rd80_l1(time: npt.NDArray, l0: dict[str, npt.NDArray]) -> DisdroL1:
39
+ def read_rd80_l1(
40
+ time: npt.NDArray, l0: dict[str, npt.NDArray], altitude: float | None = None
41
+ ) -> DisdroL1:
42
+ if altitude is not None:
43
+ logging.warning(
44
+ "Altitude given but the correction for non-sea-level "
45
+ "conditions is not implemented for RD-80."
46
+ )
39
47
  return DisdroL1(
40
48
  diameter=D,
41
49
  diameter_spread=D_SPREAD,
@@ -48,6 +56,7 @@ def read_rd80_l1(time: npt.NDArray, l0: dict[str, npt.NDArray]) -> DisdroL1:
48
56
  area_nom=AREA_NOM,
49
57
  area_eff=None,
50
58
  data_raw=l0["n"],
59
+ altitude=altitude,
51
60
  )
52
61
 
53
62
 
@@ -0,0 +1,69 @@
1
+ import logging
2
+ from collections.abc import Container
3
+
4
+ import numpy as np
5
+ import numpy.typing as npt
6
+ from atmoslib import isa_air_density
7
+ from atmoslib.constants import RHO_STD
8
+ from numpy import ma
9
+
10
+
11
+ def convert_to_numpy(
12
+ data: dict,
13
+ fill_values: dict | None = None,
14
+ int_keys: Container | None = None,
15
+ float_keys: Container | None = None,
16
+ ) -> dict:
17
+ output = {}
18
+ for key, value in data.items():
19
+ arr = np.array(value)
20
+ if fill_values is not None and key in fill_values:
21
+ arr = ma.masked_where(arr == fill_values[key], arr)
22
+ if int_keys is not None and key in int_keys:
23
+ new_arr = arr.astype(np.int32)
24
+ if not np.all(arr == new_arr):
25
+ msg = "Cannot convert non-integer float to integer"
26
+ raise ValueError(msg)
27
+ arr = new_arr
28
+ elif float_keys is not None and key in float_keys:
29
+ arr = arr.astype(np.float32)
30
+ output[key] = arr
31
+ return output
32
+
33
+
34
+ def make_rain_mask(
35
+ diameter: npt.NDArray[np.floating],
36
+ velocity: npt.NDArray[np.floating],
37
+ threshold: float = 0.5,
38
+ altitude: float | None = None,
39
+ ) -> npt.NDArray[np.bool]:
40
+ """Make mask for rain bins based on theoretical diameter-velocity relation.
41
+
42
+ Args:
43
+ diameter: Diameter (mm)
44
+ velocity: Velocity (m s-1)
45
+ threshold: Maximum error to theoretical relation (1)
46
+ altitude: Site altitude for optional altitude correction (m)
47
+
48
+ References:
49
+ Atlas, D., Srivastava, R. C., & Sekhon, R. S. (1973). Doppler Radar
50
+ Characteristics of Precipitation at Vertical Incidence. Reviews of
51
+ Geophysics and Space Physics, 11(1), 1-35.
52
+ https://doi.org/10.1029/RG011i001p00001
53
+
54
+ Beard, K. V. (1985). Simple Altitude Adjustments to Raindrop Velocities
55
+ for Doppler Radar Analysis. Journal of Atmospheric and Oceanic
56
+ Technology, 2(4), 468-471.
57
+ https://doi.org/10.1175/1520-0426(1985)002%3C0468:SAATRV%3E2.0.CO;2
58
+ """
59
+ v = 9.65 - 10.3 * np.exp(-0.6 * diameter) # Eq. 24, Atlas et al. (1973)
60
+ if altitude is None:
61
+ logging.warning(
62
+ "No altitude given, no correction applied for non-sea-level conditions."
63
+ )
64
+ else:
65
+ rho = isa_air_density(altitude)
66
+ m = 0.375 + 0.025 * diameter # Eq. 3, Beard (1985)
67
+ v = (RHO_STD / rho) ** m * v # Eq. 1, Beard (1985)
68
+ e = np.abs((velocity - v[:, np.newaxis]) / v[:, np.newaxis])
69
+ return e < threshold
@@ -71,7 +71,7 @@ def parsivel2nc(
71
71
  field_separator=field_separator,
72
72
  decimal_separator=decimal_separator,
73
73
  ),
74
- read_parsivel_l1,
74
+ functools.partial(read_parsivel_l1, altitude=site_meta.get("altitude")),
75
75
  ATTRIBUTES,
76
76
  disdrometer_file,
77
77
  output_file,
@@ -117,7 +117,7 @@ def thies2nc(
117
117
  return _process_disdrometer(
118
118
  Thies,
119
119
  read_lpm,
120
- functools.partial(read_lpm_l1, au=au),
120
+ functools.partial(read_lpm_l1, au=au, altitude=site_meta.get("altitude")),
121
121
  ATTRIBUTES,
122
122
  disdrometer_file,
123
123
  output_file,
@@ -160,7 +160,7 @@ def rd802nc(
160
160
  return _process_disdrometer(
161
161
  Rd80,
162
162
  read_rd80,
163
- read_rd80_l1,
163
+ functools.partial(read_rd80_l1, altitude=site_meta.get("altitude")),
164
164
  RD80_ATTRIBUTES,
165
165
  input_file,
166
166
  output_file,
@@ -9,6 +9,7 @@ import numpy as np
9
9
  from numpy import ma
10
10
 
11
11
  from cloudnetpy import output
12
+ from cloudnetpy.constants import MM_H_TO_M_S, MM_TO_M
12
13
  from cloudnetpy.exceptions import ValidTimeStampError
13
14
  from cloudnetpy.instruments import instruments
14
15
  from cloudnetpy.instruments.cloudnet_instrument import CSVFile
@@ -122,11 +123,9 @@ class FD12P(CSVFile):
122
123
 
123
124
  def convert_units(self) -> None:
124
125
  precipitation_rate = self.data["precipitation_rate"][:]
125
- self.data["precipitation_rate"].data = (
126
- precipitation_rate / 3600 / 1000
127
- ) # mm/h -> m/s
126
+ self.data["precipitation_rate"].data = precipitation_rate * MM_H_TO_M_S
128
127
  for key in ("precipitation_amount", "snowfall_amount"):
129
- self.data[key].data = self.data[key][:] / 1000 # mm -> m
128
+ self.data[key].data = self.data[key][:] * MM_TO_M
130
129
 
131
130
  def screen_all_masked(self) -> None:
132
131
  is_valid = np.ones_like(self.data["time"][:], dtype=np.bool_)
@@ -69,8 +69,8 @@ def hatpro2l1c(
69
69
 
70
70
  try:
71
71
  hatpro_raw = lev1_to_nc(
72
- "1C01",
73
- str(mwr_dir),
72
+ data_type="1C01",
73
+ path_to_files=str(mwr_dir),
74
74
  instrument_type=instrument_type,
75
75
  output_file=str(output_file),
76
76
  lidar_path=lidar_file,