cloudnetpy 1.96.2__tar.gz → 1.96.3__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 (148) hide show
  1. {cloudnetpy-1.96.2/cloudnetpy.egg-info → cloudnetpy-1.96.3}/PKG-INFO +1 -1
  2. {cloudnetpy-1.96.2 → cloudnetpy-1.96.3}/cloudnetpy/categorize/insects.py +24 -2
  3. {cloudnetpy-1.96.2 → cloudnetpy-1.96.3}/cloudnetpy/categorize/melting.py +41 -5
  4. {cloudnetpy-1.96.2 → cloudnetpy-1.96.3}/cloudnetpy/cli.py +8 -2
  5. {cloudnetpy-1.96.2 → cloudnetpy-1.96.3}/cloudnetpy/version.py +1 -1
  6. {cloudnetpy-1.96.2 → cloudnetpy-1.96.3/cloudnetpy.egg-info}/PKG-INFO +1 -1
  7. {cloudnetpy-1.96.2 → cloudnetpy-1.96.3}/LICENSE +0 -0
  8. {cloudnetpy-1.96.2 → cloudnetpy-1.96.3}/MANIFEST.in +0 -0
  9. {cloudnetpy-1.96.2 → cloudnetpy-1.96.3}/README.md +0 -0
  10. {cloudnetpy-1.96.2 → cloudnetpy-1.96.3}/cloudnetpy/__init__.py +0 -0
  11. {cloudnetpy-1.96.2 → cloudnetpy-1.96.3}/cloudnetpy/arm.py +0 -0
  12. {cloudnetpy-1.96.2 → cloudnetpy-1.96.3}/cloudnetpy/categorize/__init__.py +0 -0
  13. {cloudnetpy-1.96.2 → cloudnetpy-1.96.3}/cloudnetpy/categorize/atmos_utils.py +0 -0
  14. {cloudnetpy-1.96.2 → cloudnetpy-1.96.3}/cloudnetpy/categorize/attenuation.py +0 -0
  15. {cloudnetpy-1.96.2 → cloudnetpy-1.96.3}/cloudnetpy/categorize/attenuations/__init__.py +0 -0
  16. {cloudnetpy-1.96.2 → cloudnetpy-1.96.3}/cloudnetpy/categorize/attenuations/gas_attenuation.py +0 -0
  17. {cloudnetpy-1.96.2 → cloudnetpy-1.96.3}/cloudnetpy/categorize/attenuations/liquid_attenuation.py +0 -0
  18. {cloudnetpy-1.96.2 → cloudnetpy-1.96.3}/cloudnetpy/categorize/attenuations/melting_attenuation.py +0 -0
  19. {cloudnetpy-1.96.2 → cloudnetpy-1.96.3}/cloudnetpy/categorize/attenuations/rain_attenuation.py +0 -0
  20. {cloudnetpy-1.96.2 → cloudnetpy-1.96.3}/cloudnetpy/categorize/categorize.py +0 -0
  21. {cloudnetpy-1.96.2 → cloudnetpy-1.96.3}/cloudnetpy/categorize/classify.py +0 -0
  22. {cloudnetpy-1.96.2 → cloudnetpy-1.96.3}/cloudnetpy/categorize/containers.py +0 -0
  23. {cloudnetpy-1.96.2 → cloudnetpy-1.96.3}/cloudnetpy/categorize/disdrometer.py +0 -0
  24. {cloudnetpy-1.96.2 → cloudnetpy-1.96.3}/cloudnetpy/categorize/droplet.py +0 -0
  25. {cloudnetpy-1.96.2 → cloudnetpy-1.96.3}/cloudnetpy/categorize/falling.py +0 -0
  26. {cloudnetpy-1.96.2 → cloudnetpy-1.96.3}/cloudnetpy/categorize/freezing.py +0 -0
  27. {cloudnetpy-1.96.2 → cloudnetpy-1.96.3}/cloudnetpy/categorize/lidar.py +0 -0
  28. {cloudnetpy-1.96.2 → cloudnetpy-1.96.3}/cloudnetpy/categorize/model.py +0 -0
  29. {cloudnetpy-1.96.2 → cloudnetpy-1.96.3}/cloudnetpy/categorize/mwr.py +0 -0
  30. {cloudnetpy-1.96.2 → cloudnetpy-1.96.3}/cloudnetpy/categorize/radar.py +0 -0
  31. {cloudnetpy-1.96.2 → cloudnetpy-1.96.3}/cloudnetpy/cloudnetarray.py +0 -0
  32. {cloudnetpy-1.96.2 → cloudnetpy-1.96.3}/cloudnetpy/concat_lib.py +0 -0
  33. {cloudnetpy-1.96.2 → cloudnetpy-1.96.3}/cloudnetpy/constants.py +0 -0
  34. {cloudnetpy-1.96.2 → cloudnetpy-1.96.3}/cloudnetpy/datasource.py +0 -0
  35. {cloudnetpy-1.96.2 → cloudnetpy-1.96.3}/cloudnetpy/disdronator/__init__.py +0 -0
  36. {cloudnetpy-1.96.2 → cloudnetpy-1.96.3}/cloudnetpy/disdronator/lpm.py +0 -0
  37. {cloudnetpy-1.96.2 → cloudnetpy-1.96.3}/cloudnetpy/disdronator/parsivel.py +0 -0
  38. {cloudnetpy-1.96.2 → cloudnetpy-1.96.3}/cloudnetpy/disdronator/process.py +0 -0
  39. {cloudnetpy-1.96.2 → cloudnetpy-1.96.3}/cloudnetpy/disdronator/rd80.py +0 -0
  40. {cloudnetpy-1.96.2 → cloudnetpy-1.96.3}/cloudnetpy/disdronator/utils.py +0 -0
  41. {cloudnetpy-1.96.2 → cloudnetpy-1.96.3}/cloudnetpy/exceptions.py +0 -0
  42. {cloudnetpy-1.96.2 → cloudnetpy-1.96.3}/cloudnetpy/instruments/__init__.py +0 -0
  43. {cloudnetpy-1.96.2 → cloudnetpy-1.96.3}/cloudnetpy/instruments/arm_ceilo.py +0 -0
  44. {cloudnetpy-1.96.2 → cloudnetpy-1.96.3}/cloudnetpy/instruments/arm_ld.py +0 -0
  45. {cloudnetpy-1.96.2 → cloudnetpy-1.96.3}/cloudnetpy/instruments/arm_utils.py +0 -0
  46. {cloudnetpy-1.96.2 → cloudnetpy-1.96.3}/cloudnetpy/instruments/basta.py +0 -0
  47. {cloudnetpy-1.96.2 → cloudnetpy-1.96.3}/cloudnetpy/instruments/bowtie.py +0 -0
  48. {cloudnetpy-1.96.2 → cloudnetpy-1.96.3}/cloudnetpy/instruments/ceilo.py +0 -0
  49. {cloudnetpy-1.96.2 → cloudnetpy-1.96.3}/cloudnetpy/instruments/ceilometer.py +0 -0
  50. {cloudnetpy-1.96.2 → cloudnetpy-1.96.3}/cloudnetpy/instruments/cl61d.py +0 -0
  51. {cloudnetpy-1.96.2 → cloudnetpy-1.96.3}/cloudnetpy/instruments/cloudnet_instrument.py +0 -0
  52. {cloudnetpy-1.96.2 → cloudnetpy-1.96.3}/cloudnetpy/instruments/copernicus.py +0 -0
  53. {cloudnetpy-1.96.2 → cloudnetpy-1.96.3}/cloudnetpy/instruments/da10.py +0 -0
  54. {cloudnetpy-1.96.2 → cloudnetpy-1.96.3}/cloudnetpy/instruments/dealias.py +0 -0
  55. {cloudnetpy-1.96.2 → cloudnetpy-1.96.3}/cloudnetpy/instruments/disdrometer.py +0 -0
  56. {cloudnetpy-1.96.2 → cloudnetpy-1.96.3}/cloudnetpy/instruments/fd12p.py +0 -0
  57. {cloudnetpy-1.96.2 → cloudnetpy-1.96.3}/cloudnetpy/instruments/galileo.py +0 -0
  58. {cloudnetpy-1.96.2 → cloudnetpy-1.96.3}/cloudnetpy/instruments/hatpro.py +0 -0
  59. {cloudnetpy-1.96.2 → cloudnetpy-1.96.3}/cloudnetpy/instruments/instruments.py +0 -0
  60. {cloudnetpy-1.96.2 → cloudnetpy-1.96.3}/cloudnetpy/instruments/kazr.py +0 -0
  61. {cloudnetpy-1.96.2 → cloudnetpy-1.96.3}/cloudnetpy/instruments/lufft.py +0 -0
  62. {cloudnetpy-1.96.2 → cloudnetpy-1.96.3}/cloudnetpy/instruments/mira.py +0 -0
  63. {cloudnetpy-1.96.2 → cloudnetpy-1.96.3}/cloudnetpy/instruments/mmcr.py +0 -0
  64. {cloudnetpy-1.96.2 → cloudnetpy-1.96.3}/cloudnetpy/instruments/mrr.py +0 -0
  65. {cloudnetpy-1.96.2 → cloudnetpy-1.96.3}/cloudnetpy/instruments/mwr3c.py +0 -0
  66. {cloudnetpy-1.96.2 → cloudnetpy-1.96.3}/cloudnetpy/instruments/mwrlos.py +0 -0
  67. {cloudnetpy-1.96.2 → cloudnetpy-1.96.3}/cloudnetpy/instruments/nc_lidar.py +0 -0
  68. {cloudnetpy-1.96.2 → cloudnetpy-1.96.3}/cloudnetpy/instruments/nc_radar.py +0 -0
  69. {cloudnetpy-1.96.2 → cloudnetpy-1.96.3}/cloudnetpy/instruments/pollyxt.py +0 -0
  70. {cloudnetpy-1.96.2 → cloudnetpy-1.96.3}/cloudnetpy/instruments/radiometrics.py +0 -0
  71. {cloudnetpy-1.96.2 → cloudnetpy-1.96.3}/cloudnetpy/instruments/rain_e_h3.py +0 -0
  72. {cloudnetpy-1.96.2 → cloudnetpy-1.96.3}/cloudnetpy/instruments/rpg.py +0 -0
  73. {cloudnetpy-1.96.2 → cloudnetpy-1.96.3}/cloudnetpy/instruments/rpg_reader.py +0 -0
  74. {cloudnetpy-1.96.2 → cloudnetpy-1.96.3}/cloudnetpy/instruments/toa5.py +0 -0
  75. {cloudnetpy-1.96.2 → cloudnetpy-1.96.3}/cloudnetpy/instruments/vaisala.py +0 -0
  76. {cloudnetpy-1.96.2 → cloudnetpy-1.96.3}/cloudnetpy/instruments/weather_radar.py +0 -0
  77. {cloudnetpy-1.96.2 → cloudnetpy-1.96.3}/cloudnetpy/instruments/weather_station.py +0 -0
  78. {cloudnetpy-1.96.2 → cloudnetpy-1.96.3}/cloudnetpy/metadata.py +0 -0
  79. {cloudnetpy-1.96.2 → cloudnetpy-1.96.3}/cloudnetpy/model_evaluation/__init__.py +0 -0
  80. {cloudnetpy-1.96.2 → cloudnetpy-1.96.3}/cloudnetpy/model_evaluation/file_handler.py +0 -0
  81. {cloudnetpy-1.96.2 → cloudnetpy-1.96.3}/cloudnetpy/model_evaluation/metadata.py +0 -0
  82. {cloudnetpy-1.96.2 → cloudnetpy-1.96.3}/cloudnetpy/model_evaluation/model_metadata.py +0 -0
  83. {cloudnetpy-1.96.2 → cloudnetpy-1.96.3}/cloudnetpy/model_evaluation/plotting/__init__.py +0 -0
  84. {cloudnetpy-1.96.2 → cloudnetpy-1.96.3}/cloudnetpy/model_evaluation/plotting/plot_meta.py +0 -0
  85. {cloudnetpy-1.96.2 → cloudnetpy-1.96.3}/cloudnetpy/model_evaluation/plotting/plot_tools.py +0 -0
  86. {cloudnetpy-1.96.2 → cloudnetpy-1.96.3}/cloudnetpy/model_evaluation/plotting/plotting.py +0 -0
  87. {cloudnetpy-1.96.2 → cloudnetpy-1.96.3}/cloudnetpy/model_evaluation/products/__init__.py +0 -0
  88. {cloudnetpy-1.96.2 → cloudnetpy-1.96.3}/cloudnetpy/model_evaluation/products/advance_methods.py +0 -0
  89. {cloudnetpy-1.96.2 → cloudnetpy-1.96.3}/cloudnetpy/model_evaluation/products/grid_methods.py +0 -0
  90. {cloudnetpy-1.96.2 → cloudnetpy-1.96.3}/cloudnetpy/model_evaluation/products/model_products.py +0 -0
  91. {cloudnetpy-1.96.2 → cloudnetpy-1.96.3}/cloudnetpy/model_evaluation/products/observation_products.py +0 -0
  92. {cloudnetpy-1.96.2 → cloudnetpy-1.96.3}/cloudnetpy/model_evaluation/products/product_resampling.py +0 -0
  93. {cloudnetpy-1.96.2 → cloudnetpy-1.96.3}/cloudnetpy/model_evaluation/products/tools.py +0 -0
  94. {cloudnetpy-1.96.2 → cloudnetpy-1.96.3}/cloudnetpy/model_evaluation/statistics/__init__.py +0 -0
  95. {cloudnetpy-1.96.2 → cloudnetpy-1.96.3}/cloudnetpy/model_evaluation/statistics/statistical_methods.py +0 -0
  96. {cloudnetpy-1.96.2 → cloudnetpy-1.96.3}/cloudnetpy/model_evaluation/tests/__init__.py +0 -0
  97. {cloudnetpy-1.96.2 → cloudnetpy-1.96.3}/cloudnetpy/model_evaluation/tests/e2e/__init__.py +0 -0
  98. {cloudnetpy-1.96.2 → cloudnetpy-1.96.3}/cloudnetpy/model_evaluation/tests/e2e/conftest.py +0 -0
  99. {cloudnetpy-1.96.2 → cloudnetpy-1.96.3}/cloudnetpy/model_evaluation/tests/e2e/process_cf/__init__.py +0 -0
  100. {cloudnetpy-1.96.2 → cloudnetpy-1.96.3}/cloudnetpy/model_evaluation/tests/e2e/process_cf/main.py +0 -0
  101. {cloudnetpy-1.96.2 → cloudnetpy-1.96.3}/cloudnetpy/model_evaluation/tests/e2e/process_cf/tests.py +0 -0
  102. {cloudnetpy-1.96.2 → cloudnetpy-1.96.3}/cloudnetpy/model_evaluation/tests/e2e/process_iwc/__init__.py +0 -0
  103. {cloudnetpy-1.96.2 → cloudnetpy-1.96.3}/cloudnetpy/model_evaluation/tests/e2e/process_iwc/main.py +0 -0
  104. {cloudnetpy-1.96.2 → cloudnetpy-1.96.3}/cloudnetpy/model_evaluation/tests/e2e/process_iwc/tests.py +0 -0
  105. {cloudnetpy-1.96.2 → cloudnetpy-1.96.3}/cloudnetpy/model_evaluation/tests/e2e/process_lwc/__init__.py +0 -0
  106. {cloudnetpy-1.96.2 → cloudnetpy-1.96.3}/cloudnetpy/model_evaluation/tests/e2e/process_lwc/main.py +0 -0
  107. {cloudnetpy-1.96.2 → cloudnetpy-1.96.3}/cloudnetpy/model_evaluation/tests/e2e/process_lwc/tests.py +0 -0
  108. {cloudnetpy-1.96.2 → cloudnetpy-1.96.3}/cloudnetpy/model_evaluation/tests/unit/__init__.py +0 -0
  109. {cloudnetpy-1.96.2 → cloudnetpy-1.96.3}/cloudnetpy/model_evaluation/tests/unit/conftest.py +0 -0
  110. {cloudnetpy-1.96.2 → cloudnetpy-1.96.3}/cloudnetpy/model_evaluation/tests/unit/test_advance_methods.py +0 -0
  111. {cloudnetpy-1.96.2 → cloudnetpy-1.96.3}/cloudnetpy/model_evaluation/tests/unit/test_grid_methods.py +0 -0
  112. {cloudnetpy-1.96.2 → cloudnetpy-1.96.3}/cloudnetpy/model_evaluation/tests/unit/test_model_products.py +0 -0
  113. {cloudnetpy-1.96.2 → cloudnetpy-1.96.3}/cloudnetpy/model_evaluation/tests/unit/test_observation_products.py +0 -0
  114. {cloudnetpy-1.96.2 → cloudnetpy-1.96.3}/cloudnetpy/model_evaluation/tests/unit/test_plot_tools.py +0 -0
  115. {cloudnetpy-1.96.2 → cloudnetpy-1.96.3}/cloudnetpy/model_evaluation/tests/unit/test_plotting.py +0 -0
  116. {cloudnetpy-1.96.2 → cloudnetpy-1.96.3}/cloudnetpy/model_evaluation/tests/unit/test_statistical_methods.py +0 -0
  117. {cloudnetpy-1.96.2 → cloudnetpy-1.96.3}/cloudnetpy/model_evaluation/tests/unit/test_tools.py +0 -0
  118. {cloudnetpy-1.96.2 → cloudnetpy-1.96.3}/cloudnetpy/model_evaluation/utils.py +0 -0
  119. {cloudnetpy-1.96.2 → cloudnetpy-1.96.3}/cloudnetpy/output.py +0 -0
  120. {cloudnetpy-1.96.2 → cloudnetpy-1.96.3}/cloudnetpy/plotting/__init__.py +0 -0
  121. {cloudnetpy-1.96.2 → cloudnetpy-1.96.3}/cloudnetpy/plotting/plot_meta.py +0 -0
  122. {cloudnetpy-1.96.2 → cloudnetpy-1.96.3}/cloudnetpy/plotting/plotting.py +0 -0
  123. {cloudnetpy-1.96.2 → cloudnetpy-1.96.3}/cloudnetpy/products/__init__.py +0 -0
  124. {cloudnetpy-1.96.2 → cloudnetpy-1.96.3}/cloudnetpy/products/classification.py +0 -0
  125. {cloudnetpy-1.96.2 → cloudnetpy-1.96.3}/cloudnetpy/products/cod.py +0 -0
  126. {cloudnetpy-1.96.2 → cloudnetpy-1.96.3}/cloudnetpy/products/der.py +0 -0
  127. {cloudnetpy-1.96.2 → cloudnetpy-1.96.3}/cloudnetpy/products/drizzle.py +0 -0
  128. {cloudnetpy-1.96.2 → cloudnetpy-1.96.3}/cloudnetpy/products/drizzle_error.py +0 -0
  129. {cloudnetpy-1.96.2 → cloudnetpy-1.96.3}/cloudnetpy/products/drizzle_tools.py +0 -0
  130. {cloudnetpy-1.96.2 → cloudnetpy-1.96.3}/cloudnetpy/products/epsilon_lidar.py +0 -0
  131. {cloudnetpy-1.96.2 → cloudnetpy-1.96.3}/cloudnetpy/products/epsilon_radar.py +0 -0
  132. {cloudnetpy-1.96.2 → cloudnetpy-1.96.3}/cloudnetpy/products/ier.py +0 -0
  133. {cloudnetpy-1.96.2 → cloudnetpy-1.96.3}/cloudnetpy/products/iwc.py +0 -0
  134. {cloudnetpy-1.96.2 → cloudnetpy-1.96.3}/cloudnetpy/products/iwc_weather_radar.py +0 -0
  135. {cloudnetpy-1.96.2 → cloudnetpy-1.96.3}/cloudnetpy/products/lwc.py +0 -0
  136. {cloudnetpy-1.96.2 → cloudnetpy-1.96.3}/cloudnetpy/products/mie_lu_tables.nc +0 -0
  137. {cloudnetpy-1.96.2 → cloudnetpy-1.96.3}/cloudnetpy/products/mwr_tools.py +0 -0
  138. {cloudnetpy-1.96.2 → cloudnetpy-1.96.3}/cloudnetpy/products/product_tools.py +0 -0
  139. {cloudnetpy-1.96.2 → cloudnetpy-1.96.3}/cloudnetpy/py.typed +0 -0
  140. {cloudnetpy-1.96.2 → cloudnetpy-1.96.3}/cloudnetpy/utils.py +0 -0
  141. {cloudnetpy-1.96.2 → cloudnetpy-1.96.3}/cloudnetpy.egg-info/SOURCES.txt +0 -0
  142. {cloudnetpy-1.96.2 → cloudnetpy-1.96.3}/cloudnetpy.egg-info/dependency_links.txt +0 -0
  143. {cloudnetpy-1.96.2 → cloudnetpy-1.96.3}/cloudnetpy.egg-info/entry_points.txt +0 -0
  144. {cloudnetpy-1.96.2 → cloudnetpy-1.96.3}/cloudnetpy.egg-info/requires.txt +0 -0
  145. {cloudnetpy-1.96.2 → cloudnetpy-1.96.3}/cloudnetpy.egg-info/top_level.txt +0 -0
  146. {cloudnetpy-1.96.2 → cloudnetpy-1.96.3}/docs/source/conf.py +0 -0
  147. {cloudnetpy-1.96.2 → cloudnetpy-1.96.3}/pyproject.toml +0 -0
  148. {cloudnetpy-1.96.2 → cloudnetpy-1.96.3}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cloudnetpy
3
- Version: 1.96.2
3
+ Version: 1.96.3
4
4
  Summary: Python package for Cloudnet processing
5
5
  Author: Simo Tukiainen
6
6
  License: MIT License
@@ -58,7 +58,9 @@ def _insect_probability(obs: ClassData) -> tuple[npt.NDArray, npt.NDArray]:
58
58
  prob_from_ldr = _calc_prob_from_ldr(prob)
59
59
  prob_from_others = _calc_prob_from_all(prob)
60
60
  prob_from_others = _adjust_for_radar(obs, prob, prob_from_others)
61
- prob_combined = _fill_missing_pixels(prob_from_ldr, prob_from_others)
61
+ prob_from_others = _adjust_for_lidar(obs, prob_from_others)
62
+ is_ldr = ~ma.getmaskarray(obs.ldr) if hasattr(obs, "ldr") else None
63
+ prob_combined = _fill_missing_pixels(prob_from_ldr, prob_from_others, is_ldr)
62
64
  return prob_combined, prob_from_others
63
65
 
64
66
 
@@ -147,11 +149,31 @@ def _adjust_for_radar(
147
149
  return prob_from_others
148
150
 
149
151
 
152
+ def _adjust_for_lidar(
153
+ obs: ClassData,
154
+ prob_from_others: npt.NDArray,
155
+ weight: float = 0.8,
156
+ ) -> npt.NDArray:
157
+ """Reduces probability above the lidar signal, where liquid may be hidden."""
158
+ is_beta = ~ma.getmaskarray(obs.beta)
159
+ n_gates = is_beta.shape[1]
160
+ top = n_gates - np.argmax(is_beta[:, ::-1], axis=1)
161
+ top[~is_beta.any(axis=1)] = 0
162
+ above_lidar = np.arange(n_gates)[np.newaxis, :] >= top[:, np.newaxis]
163
+ prob_from_others[above_lidar] *= weight
164
+ return prob_from_others
165
+
166
+
150
167
  def _fill_missing_pixels(
151
168
  prob_from_ldr: npt.NDArray,
152
169
  prob_from_others: npt.NDArray,
170
+ is_ldr: npt.NDArray | None = None,
153
171
  ) -> npt.NDArray:
154
- return np.maximum(prob_from_ldr, prob_from_others)
172
+ """Combines probabilities trusting measured ldr over other parameters."""
173
+ prob = np.maximum(prob_from_ldr, prob_from_others)
174
+ if is_ldr is not None:
175
+ prob[is_ldr] = prob_from_ldr[is_ldr]
176
+ return prob
155
177
 
156
178
 
157
179
  def _screen_insects(
@@ -10,6 +10,10 @@ from cloudnetpy import utils
10
10
  from cloudnetpy.categorize import droplet
11
11
  from cloudnetpy.categorize.containers import ClassData
12
12
 
13
+ MIN_LAPSE_RATE = 0.004 # K m-1
14
+ MIN_LDR_COVERAGE = 0.5
15
+ T0_TOLERANCE = 1 # K
16
+
13
17
 
14
18
  def find_melting_layer(obs: ClassData, *, smooth: bool = True) -> npt.NDArray:
15
19
  """Finds melting layer from model temperature, ldr, and velocity.
@@ -27,11 +31,15 @@ def find_melting_layer(obs: ClassData, *, smooth: bool = True) -> npt.NDArray:
27
31
  The peak in *ldr* is the primary parameter we analyze. If
28
32
  *ldr* has a proper peak, and *v* < -1 m/s in the base, melting layer
29
33
  has been found. If *ldr* is missing we only analyze the behaviour
30
- of *v*, which is always present, to detect the melting layer.
34
+ of *v*, which is always present, to detect the melting layer. If *ldr*
35
+ covers the profile but shows no peak, there is no melting layer.
31
36
 
32
37
  Model temperature is used to limit the melting layer search to a certain
33
38
  temperature range around 0 C. For ECMWF the range is -4..+3, and for
34
- the rest -8..+6.
39
+ the rest -8..+6. Model temperature must also reach -1 C in the profile,
40
+ and the search is limited in altitude above the highest 0 C level,
41
+ because in temperature inversions the temperature range alone may
42
+ span several kilometers.
35
43
 
36
44
  Notes:
37
45
  This melting layer detection method is novel and needs to be validated.
@@ -63,7 +71,7 @@ def find_melting_layer(obs: ClassData, *, smooth: bool = True) -> npt.NDArray:
63
71
  t_range = _find_model_temperature_range(obs.model_type)
64
72
 
65
73
  for ind, t_prof in enumerate(obs.tw):
66
- temp_indices = _get_temp_indices(t_prof, t_range)
74
+ temp_indices = _get_temp_indices(t_prof, t_range, obs.height)
67
75
  if len(temp_indices) <= 1:
68
76
  continue
69
77
  z_prof = obs.z[ind, temp_indices]
@@ -90,6 +98,8 @@ def find_melting_layer(obs: ClassData, *, smooth: bool = True) -> npt.NDArray:
90
98
  z_prof,
91
99
  )
92
100
  except (ValueError, IndexError, AssertionError):
101
+ if _has_ldr_coverage(ldr_prof, v_prof):
102
+ continue
93
103
  height = obs.height[temp_indices]
94
104
  if hasattr(obs, "width"):
95
105
  width_prof = obs.width[ind, temp_indices]
@@ -104,6 +114,16 @@ def find_melting_layer(obs: ClassData, *, smooth: bool = True) -> npt.NDArray:
104
114
  return melting_layer
105
115
 
106
116
 
117
+ def _has_ldr_coverage(ldr_prof: npt.NDArray | None, v_prof: npt.NDArray) -> bool:
118
+ """Checks if ldr covers enough of the profile to rule out melting layer."""
119
+ if ldr_prof is None:
120
+ return False
121
+ is_v = ~ma.getmaskarray(v_prof)
122
+ is_ldr = ~ma.getmaskarray(ldr_prof)
123
+ n_ldr = np.count_nonzero(is_ldr & is_v)
124
+ return bool(n_ldr >= MIN_LDR_COVERAGE * np.count_nonzero(is_v))
125
+
126
+
107
127
  def _find_melting_layer_from_ldr(
108
128
  ldr_prof: npt.NDArray,
109
129
  ldr_dprof: npt.NDArray,
@@ -166,12 +186,28 @@ def _basetop(dprof: npt.NDArray, pind: int) -> tuple[int, int]:
166
186
  return base, top
167
187
 
168
188
 
169
- def _get_temp_indices(t_prof: npt.NDArray, t_range: tuple) -> npt.NDArray:
189
+ def _get_temp_indices(
190
+ t_prof: npt.NDArray, t_range: tuple, height: npt.NDArray | None = None
191
+ ) -> npt.NDArray:
170
192
  """Finds indices of temperature profile covering the given range."""
171
- ind = np.where((t_prof > min(t_range) + T0) & (t_prof < max(t_range) + T0))[0]
193
+ in_range = (t_prof > min(t_range) + T0) & (t_prof < max(t_range) + T0)
194
+ if height is not None:
195
+ in_range &= height <= _find_max_height(t_prof, t_range, height)
196
+ ind = np.where(in_range)[0]
172
197
  return np.array([]) if len(ind) == 0 else np.arange(np.min(ind), np.max(ind) + 1)
173
198
 
174
199
 
200
+ def _find_max_height(t_prof: npt.NDArray, t_range: tuple, height: npt.NDArray) -> float:
201
+ """Finds maximum melting layer height assuming realistic lapse rate."""
202
+ warm = np.where(t_prof >= T0)[0]
203
+ if len(warm) == 0:
204
+ # Model may be slightly too cold when melting layer is near the ground
205
+ warm = np.where(t_prof >= T0 - T0_TOLERANCE)[0]
206
+ if len(warm) == 0:
207
+ return -np.inf
208
+ return height[warm[-1]] - min(t_range) / MIN_LAPSE_RATE
209
+
210
+
175
211
  def _find_model_temperature_range(model_type: str) -> tuple[float, float]:
176
212
  """Returns temperature range around 0C for given model type."""
177
213
  if model_type == "gdas1":
@@ -928,9 +928,11 @@ def main() -> None:
928
928
  )
929
929
  parser.add_argument(
930
930
  "--show",
931
- help="Show plotted image",
931
+ nargs="?",
932
+ const=True,
932
933
  default=False,
933
- action=argparse.BooleanOptionalAction,
934
+ metavar="VARIABLES",
935
+ help="Show plotted image, optionally only given variables (comma-separated)",
934
936
  )
935
937
  parser.add_argument(
936
938
  "--dl",
@@ -980,6 +982,10 @@ def main() -> None:
980
982
  default=None,
981
983
  )
982
984
  args = parser.parse_args()
985
+ if isinstance(args.show, str):
986
+ if args.variables is None:
987
+ args.variables = args.show
988
+ args.show = True
983
989
 
984
990
  logger = logging.getLogger()
985
991
  logger.setLevel(logging.INFO)
@@ -1,4 +1,4 @@
1
1
  MAJOR = 1
2
2
  MINOR = 96
3
- PATCH = 2
3
+ PATCH = 3
4
4
  __version__ = f"{MAJOR}.{MINOR}.{PATCH}"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cloudnetpy
3
- Version: 1.96.2
3
+ Version: 1.96.3
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