cloudnetpy 1.96.6__tar.gz → 1.96.7__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.6/cloudnetpy.egg-info → cloudnetpy-1.96.7}/PKG-INFO +3 -4
  2. {cloudnetpy-1.96.6 → cloudnetpy-1.96.7}/cloudnetpy/categorize/categorize.py +1 -2
  3. {cloudnetpy-1.96.6 → cloudnetpy-1.96.7}/cloudnetpy/cli.py +1 -1
  4. {cloudnetpy-1.96.6 → cloudnetpy-1.96.7}/cloudnetpy/concat_lib.py +1 -2
  5. {cloudnetpy-1.96.6 → cloudnetpy-1.96.7}/cloudnetpy/datasource.py +1 -1
  6. {cloudnetpy-1.96.6 → cloudnetpy-1.96.7}/cloudnetpy/instruments/ceilo.py +5 -0
  7. {cloudnetpy-1.96.6 → cloudnetpy-1.96.7}/cloudnetpy/instruments/ceilometer.py +7 -1
  8. {cloudnetpy-1.96.6 → cloudnetpy-1.96.7}/cloudnetpy/instruments/hatpro.py +1 -1
  9. {cloudnetpy-1.96.6 → cloudnetpy-1.96.7}/cloudnetpy/instruments/kazr.py +2 -4
  10. cloudnetpy-1.96.7/cloudnetpy/instruments/lufft.py +79 -0
  11. {cloudnetpy-1.96.6 → cloudnetpy-1.96.7}/cloudnetpy/instruments/mira.py +1 -1
  12. {cloudnetpy-1.96.6 → cloudnetpy-1.96.7}/cloudnetpy/instruments/mrr.py +1 -1
  13. {cloudnetpy-1.96.6 → cloudnetpy-1.96.7}/cloudnetpy/instruments/weather_station.py +5 -5
  14. {cloudnetpy-1.96.6 → cloudnetpy-1.96.7}/cloudnetpy/model_evaluation/products/observation_products.py +2 -2
  15. {cloudnetpy-1.96.6 → cloudnetpy-1.96.7}/cloudnetpy/output.py +1 -1
  16. {cloudnetpy-1.96.6 → cloudnetpy-1.96.7}/cloudnetpy/plotting/plotting.py +2 -2
  17. {cloudnetpy-1.96.6 → cloudnetpy-1.96.7}/cloudnetpy/utils.py +5 -7
  18. {cloudnetpy-1.96.6 → cloudnetpy-1.96.7}/cloudnetpy/version.py +1 -1
  19. {cloudnetpy-1.96.6 → cloudnetpy-1.96.7/cloudnetpy.egg-info}/PKG-INFO +3 -4
  20. {cloudnetpy-1.96.6 → cloudnetpy-1.96.7}/cloudnetpy.egg-info/requires.txt +1 -2
  21. {cloudnetpy-1.96.6 → cloudnetpy-1.96.7}/pyproject.toml +2 -3
  22. cloudnetpy-1.96.6/cloudnetpy/instruments/lufft.py +0 -113
  23. {cloudnetpy-1.96.6 → cloudnetpy-1.96.7}/LICENSE +0 -0
  24. {cloudnetpy-1.96.6 → cloudnetpy-1.96.7}/MANIFEST.in +0 -0
  25. {cloudnetpy-1.96.6 → cloudnetpy-1.96.7}/README.md +0 -0
  26. {cloudnetpy-1.96.6 → cloudnetpy-1.96.7}/cloudnetpy/__init__.py +0 -0
  27. {cloudnetpy-1.96.6 → cloudnetpy-1.96.7}/cloudnetpy/arm.py +0 -0
  28. {cloudnetpy-1.96.6 → cloudnetpy-1.96.7}/cloudnetpy/categorize/__init__.py +0 -0
  29. {cloudnetpy-1.96.6 → cloudnetpy-1.96.7}/cloudnetpy/categorize/atmos_utils.py +0 -0
  30. {cloudnetpy-1.96.6 → cloudnetpy-1.96.7}/cloudnetpy/categorize/attenuation.py +0 -0
  31. {cloudnetpy-1.96.6 → cloudnetpy-1.96.7}/cloudnetpy/categorize/attenuations/__init__.py +0 -0
  32. {cloudnetpy-1.96.6 → cloudnetpy-1.96.7}/cloudnetpy/categorize/attenuations/gas_attenuation.py +0 -0
  33. {cloudnetpy-1.96.6 → cloudnetpy-1.96.7}/cloudnetpy/categorize/attenuations/liquid_attenuation.py +0 -0
  34. {cloudnetpy-1.96.6 → cloudnetpy-1.96.7}/cloudnetpy/categorize/attenuations/melting_attenuation.py +0 -0
  35. {cloudnetpy-1.96.6 → cloudnetpy-1.96.7}/cloudnetpy/categorize/attenuations/rain_attenuation.py +0 -0
  36. {cloudnetpy-1.96.6 → cloudnetpy-1.96.7}/cloudnetpy/categorize/classify.py +0 -0
  37. {cloudnetpy-1.96.6 → cloudnetpy-1.96.7}/cloudnetpy/categorize/containers.py +0 -0
  38. {cloudnetpy-1.96.6 → cloudnetpy-1.96.7}/cloudnetpy/categorize/disdrometer.py +0 -0
  39. {cloudnetpy-1.96.6 → cloudnetpy-1.96.7}/cloudnetpy/categorize/droplet.py +0 -0
  40. {cloudnetpy-1.96.6 → cloudnetpy-1.96.7}/cloudnetpy/categorize/falling.py +0 -0
  41. {cloudnetpy-1.96.6 → cloudnetpy-1.96.7}/cloudnetpy/categorize/freezing.py +0 -0
  42. {cloudnetpy-1.96.6 → cloudnetpy-1.96.7}/cloudnetpy/categorize/insects.py +0 -0
  43. {cloudnetpy-1.96.6 → cloudnetpy-1.96.7}/cloudnetpy/categorize/lidar.py +0 -0
  44. {cloudnetpy-1.96.6 → cloudnetpy-1.96.7}/cloudnetpy/categorize/melting.py +0 -0
  45. {cloudnetpy-1.96.6 → cloudnetpy-1.96.7}/cloudnetpy/categorize/model.py +0 -0
  46. {cloudnetpy-1.96.6 → cloudnetpy-1.96.7}/cloudnetpy/categorize/mwr.py +0 -0
  47. {cloudnetpy-1.96.6 → cloudnetpy-1.96.7}/cloudnetpy/categorize/radar.py +0 -0
  48. {cloudnetpy-1.96.6 → cloudnetpy-1.96.7}/cloudnetpy/cloudnetarray.py +0 -0
  49. {cloudnetpy-1.96.6 → cloudnetpy-1.96.7}/cloudnetpy/constants.py +0 -0
  50. {cloudnetpy-1.96.6 → cloudnetpy-1.96.7}/cloudnetpy/disdronator/__init__.py +0 -0
  51. {cloudnetpy-1.96.6 → cloudnetpy-1.96.7}/cloudnetpy/disdronator/lpm.py +0 -0
  52. {cloudnetpy-1.96.6 → cloudnetpy-1.96.7}/cloudnetpy/disdronator/parsivel.py +0 -0
  53. {cloudnetpy-1.96.6 → cloudnetpy-1.96.7}/cloudnetpy/disdronator/process.py +0 -0
  54. {cloudnetpy-1.96.6 → cloudnetpy-1.96.7}/cloudnetpy/disdronator/rd80.py +0 -0
  55. {cloudnetpy-1.96.6 → cloudnetpy-1.96.7}/cloudnetpy/disdronator/utils.py +0 -0
  56. {cloudnetpy-1.96.6 → cloudnetpy-1.96.7}/cloudnetpy/exceptions.py +0 -0
  57. {cloudnetpy-1.96.6 → cloudnetpy-1.96.7}/cloudnetpy/instruments/__init__.py +0 -0
  58. {cloudnetpy-1.96.6 → cloudnetpy-1.96.7}/cloudnetpy/instruments/arm_ceilo.py +0 -0
  59. {cloudnetpy-1.96.6 → cloudnetpy-1.96.7}/cloudnetpy/instruments/arm_ld.py +0 -0
  60. {cloudnetpy-1.96.6 → cloudnetpy-1.96.7}/cloudnetpy/instruments/arm_utils.py +0 -0
  61. {cloudnetpy-1.96.6 → cloudnetpy-1.96.7}/cloudnetpy/instruments/basta.py +0 -0
  62. {cloudnetpy-1.96.6 → cloudnetpy-1.96.7}/cloudnetpy/instruments/bowtie.py +0 -0
  63. {cloudnetpy-1.96.6 → cloudnetpy-1.96.7}/cloudnetpy/instruments/cl61d.py +0 -0
  64. {cloudnetpy-1.96.6 → cloudnetpy-1.96.7}/cloudnetpy/instruments/cloudnet_instrument.py +0 -0
  65. {cloudnetpy-1.96.6 → cloudnetpy-1.96.7}/cloudnetpy/instruments/copernicus.py +0 -0
  66. {cloudnetpy-1.96.6 → cloudnetpy-1.96.7}/cloudnetpy/instruments/da10.py +0 -0
  67. {cloudnetpy-1.96.6 → cloudnetpy-1.96.7}/cloudnetpy/instruments/dealias.py +0 -0
  68. {cloudnetpy-1.96.6 → cloudnetpy-1.96.7}/cloudnetpy/instruments/disdrometer.py +0 -0
  69. {cloudnetpy-1.96.6 → cloudnetpy-1.96.7}/cloudnetpy/instruments/fd12p.py +0 -0
  70. {cloudnetpy-1.96.6 → cloudnetpy-1.96.7}/cloudnetpy/instruments/galileo.py +0 -0
  71. {cloudnetpy-1.96.6 → cloudnetpy-1.96.7}/cloudnetpy/instruments/instruments.py +0 -0
  72. {cloudnetpy-1.96.6 → cloudnetpy-1.96.7}/cloudnetpy/instruments/mmcr.py +0 -0
  73. {cloudnetpy-1.96.6 → cloudnetpy-1.96.7}/cloudnetpy/instruments/mwr3c.py +0 -0
  74. {cloudnetpy-1.96.6 → cloudnetpy-1.96.7}/cloudnetpy/instruments/mwrlos.py +0 -0
  75. {cloudnetpy-1.96.6 → cloudnetpy-1.96.7}/cloudnetpy/instruments/nc_lidar.py +0 -0
  76. {cloudnetpy-1.96.6 → cloudnetpy-1.96.7}/cloudnetpy/instruments/nc_radar.py +0 -0
  77. {cloudnetpy-1.96.6 → cloudnetpy-1.96.7}/cloudnetpy/instruments/pollyxt.py +0 -0
  78. {cloudnetpy-1.96.6 → cloudnetpy-1.96.7}/cloudnetpy/instruments/radiometrics.py +0 -0
  79. {cloudnetpy-1.96.6 → cloudnetpy-1.96.7}/cloudnetpy/instruments/rain_e_h3.py +0 -0
  80. {cloudnetpy-1.96.6 → cloudnetpy-1.96.7}/cloudnetpy/instruments/rpg.py +0 -0
  81. {cloudnetpy-1.96.6 → cloudnetpy-1.96.7}/cloudnetpy/instruments/rpg_reader.py +0 -0
  82. {cloudnetpy-1.96.6 → cloudnetpy-1.96.7}/cloudnetpy/instruments/toa5.py +0 -0
  83. {cloudnetpy-1.96.6 → cloudnetpy-1.96.7}/cloudnetpy/instruments/vaisala.py +0 -0
  84. {cloudnetpy-1.96.6 → cloudnetpy-1.96.7}/cloudnetpy/instruments/weather_radar.py +0 -0
  85. {cloudnetpy-1.96.6 → cloudnetpy-1.96.7}/cloudnetpy/metadata.py +0 -0
  86. {cloudnetpy-1.96.6 → cloudnetpy-1.96.7}/cloudnetpy/model_evaluation/__init__.py +0 -0
  87. {cloudnetpy-1.96.6 → cloudnetpy-1.96.7}/cloudnetpy/model_evaluation/file_handler.py +0 -0
  88. {cloudnetpy-1.96.6 → cloudnetpy-1.96.7}/cloudnetpy/model_evaluation/metadata.py +0 -0
  89. {cloudnetpy-1.96.6 → cloudnetpy-1.96.7}/cloudnetpy/model_evaluation/model_metadata.py +0 -0
  90. {cloudnetpy-1.96.6 → cloudnetpy-1.96.7}/cloudnetpy/model_evaluation/plotting/__init__.py +0 -0
  91. {cloudnetpy-1.96.6 → cloudnetpy-1.96.7}/cloudnetpy/model_evaluation/plotting/plot_meta.py +0 -0
  92. {cloudnetpy-1.96.6 → cloudnetpy-1.96.7}/cloudnetpy/model_evaluation/plotting/plot_tools.py +0 -0
  93. {cloudnetpy-1.96.6 → cloudnetpy-1.96.7}/cloudnetpy/model_evaluation/plotting/plotting.py +0 -0
  94. {cloudnetpy-1.96.6 → cloudnetpy-1.96.7}/cloudnetpy/model_evaluation/products/__init__.py +0 -0
  95. {cloudnetpy-1.96.6 → cloudnetpy-1.96.7}/cloudnetpy/model_evaluation/products/advance_methods.py +0 -0
  96. {cloudnetpy-1.96.6 → cloudnetpy-1.96.7}/cloudnetpy/model_evaluation/products/grid_methods.py +0 -0
  97. {cloudnetpy-1.96.6 → cloudnetpy-1.96.7}/cloudnetpy/model_evaluation/products/model_products.py +0 -0
  98. {cloudnetpy-1.96.6 → cloudnetpy-1.96.7}/cloudnetpy/model_evaluation/products/product_resampling.py +0 -0
  99. {cloudnetpy-1.96.6 → cloudnetpy-1.96.7}/cloudnetpy/model_evaluation/products/tools.py +0 -0
  100. {cloudnetpy-1.96.6 → cloudnetpy-1.96.7}/cloudnetpy/model_evaluation/statistics/__init__.py +0 -0
  101. {cloudnetpy-1.96.6 → cloudnetpy-1.96.7}/cloudnetpy/model_evaluation/statistics/statistical_methods.py +0 -0
  102. {cloudnetpy-1.96.6 → cloudnetpy-1.96.7}/cloudnetpy/model_evaluation/tests/__init__.py +0 -0
  103. {cloudnetpy-1.96.6 → cloudnetpy-1.96.7}/cloudnetpy/model_evaluation/tests/e2e/__init__.py +0 -0
  104. {cloudnetpy-1.96.6 → cloudnetpy-1.96.7}/cloudnetpy/model_evaluation/tests/e2e/conftest.py +0 -0
  105. {cloudnetpy-1.96.6 → cloudnetpy-1.96.7}/cloudnetpy/model_evaluation/tests/e2e/process_cf/__init__.py +0 -0
  106. {cloudnetpy-1.96.6 → cloudnetpy-1.96.7}/cloudnetpy/model_evaluation/tests/e2e/process_cf/main.py +0 -0
  107. {cloudnetpy-1.96.6 → cloudnetpy-1.96.7}/cloudnetpy/model_evaluation/tests/e2e/process_cf/tests.py +0 -0
  108. {cloudnetpy-1.96.6 → cloudnetpy-1.96.7}/cloudnetpy/model_evaluation/tests/e2e/process_iwc/__init__.py +0 -0
  109. {cloudnetpy-1.96.6 → cloudnetpy-1.96.7}/cloudnetpy/model_evaluation/tests/e2e/process_iwc/main.py +0 -0
  110. {cloudnetpy-1.96.6 → cloudnetpy-1.96.7}/cloudnetpy/model_evaluation/tests/e2e/process_iwc/tests.py +0 -0
  111. {cloudnetpy-1.96.6 → cloudnetpy-1.96.7}/cloudnetpy/model_evaluation/tests/e2e/process_lwc/__init__.py +0 -0
  112. {cloudnetpy-1.96.6 → cloudnetpy-1.96.7}/cloudnetpy/model_evaluation/tests/e2e/process_lwc/main.py +0 -0
  113. {cloudnetpy-1.96.6 → cloudnetpy-1.96.7}/cloudnetpy/model_evaluation/tests/e2e/process_lwc/tests.py +0 -0
  114. {cloudnetpy-1.96.6 → cloudnetpy-1.96.7}/cloudnetpy/model_evaluation/tests/unit/__init__.py +0 -0
  115. {cloudnetpy-1.96.6 → cloudnetpy-1.96.7}/cloudnetpy/model_evaluation/tests/unit/conftest.py +0 -0
  116. {cloudnetpy-1.96.6 → cloudnetpy-1.96.7}/cloudnetpy/model_evaluation/tests/unit/test_advance_methods.py +0 -0
  117. {cloudnetpy-1.96.6 → cloudnetpy-1.96.7}/cloudnetpy/model_evaluation/tests/unit/test_grid_methods.py +0 -0
  118. {cloudnetpy-1.96.6 → cloudnetpy-1.96.7}/cloudnetpy/model_evaluation/tests/unit/test_model_products.py +0 -0
  119. {cloudnetpy-1.96.6 → cloudnetpy-1.96.7}/cloudnetpy/model_evaluation/tests/unit/test_observation_products.py +0 -0
  120. {cloudnetpy-1.96.6 → cloudnetpy-1.96.7}/cloudnetpy/model_evaluation/tests/unit/test_plot_tools.py +0 -0
  121. {cloudnetpy-1.96.6 → cloudnetpy-1.96.7}/cloudnetpy/model_evaluation/tests/unit/test_plotting.py +0 -0
  122. {cloudnetpy-1.96.6 → cloudnetpy-1.96.7}/cloudnetpy/model_evaluation/tests/unit/test_statistical_methods.py +0 -0
  123. {cloudnetpy-1.96.6 → cloudnetpy-1.96.7}/cloudnetpy/model_evaluation/tests/unit/test_tools.py +0 -0
  124. {cloudnetpy-1.96.6 → cloudnetpy-1.96.7}/cloudnetpy/model_evaluation/utils.py +0 -0
  125. {cloudnetpy-1.96.6 → cloudnetpy-1.96.7}/cloudnetpy/plotting/__init__.py +0 -0
  126. {cloudnetpy-1.96.6 → cloudnetpy-1.96.7}/cloudnetpy/plotting/plot_meta.py +0 -0
  127. {cloudnetpy-1.96.6 → cloudnetpy-1.96.7}/cloudnetpy/products/__init__.py +0 -0
  128. {cloudnetpy-1.96.6 → cloudnetpy-1.96.7}/cloudnetpy/products/classification.py +0 -0
  129. {cloudnetpy-1.96.6 → cloudnetpy-1.96.7}/cloudnetpy/products/cod.py +0 -0
  130. {cloudnetpy-1.96.6 → cloudnetpy-1.96.7}/cloudnetpy/products/der.py +0 -0
  131. {cloudnetpy-1.96.6 → cloudnetpy-1.96.7}/cloudnetpy/products/drizzle.py +0 -0
  132. {cloudnetpy-1.96.6 → cloudnetpy-1.96.7}/cloudnetpy/products/drizzle_error.py +0 -0
  133. {cloudnetpy-1.96.6 → cloudnetpy-1.96.7}/cloudnetpy/products/drizzle_tools.py +0 -0
  134. {cloudnetpy-1.96.6 → cloudnetpy-1.96.7}/cloudnetpy/products/epsilon_lidar.py +0 -0
  135. {cloudnetpy-1.96.6 → cloudnetpy-1.96.7}/cloudnetpy/products/epsilon_radar.py +0 -0
  136. {cloudnetpy-1.96.6 → cloudnetpy-1.96.7}/cloudnetpy/products/ier.py +0 -0
  137. {cloudnetpy-1.96.6 → cloudnetpy-1.96.7}/cloudnetpy/products/iwc.py +0 -0
  138. {cloudnetpy-1.96.6 → cloudnetpy-1.96.7}/cloudnetpy/products/iwc_weather_radar.py +0 -0
  139. {cloudnetpy-1.96.6 → cloudnetpy-1.96.7}/cloudnetpy/products/lwc.py +0 -0
  140. {cloudnetpy-1.96.6 → cloudnetpy-1.96.7}/cloudnetpy/products/mie_lu_tables.nc +0 -0
  141. {cloudnetpy-1.96.6 → cloudnetpy-1.96.7}/cloudnetpy/products/mwr_tools.py +0 -0
  142. {cloudnetpy-1.96.6 → cloudnetpy-1.96.7}/cloudnetpy/products/product_tools.py +0 -0
  143. {cloudnetpy-1.96.6 → cloudnetpy-1.96.7}/cloudnetpy/py.typed +0 -0
  144. {cloudnetpy-1.96.6 → cloudnetpy-1.96.7}/cloudnetpy.egg-info/SOURCES.txt +0 -0
  145. {cloudnetpy-1.96.6 → cloudnetpy-1.96.7}/cloudnetpy.egg-info/dependency_links.txt +0 -0
  146. {cloudnetpy-1.96.6 → cloudnetpy-1.96.7}/cloudnetpy.egg-info/entry_points.txt +0 -0
  147. {cloudnetpy-1.96.6 → cloudnetpy-1.96.7}/cloudnetpy.egg-info/top_level.txt +0 -0
  148. {cloudnetpy-1.96.6 → cloudnetpy-1.96.7}/docs/source/conf.py +0 -0
  149. {cloudnetpy-1.96.6 → cloudnetpy-1.96.7}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cloudnetpy
3
- Version: 1.96.6
3
+ Version: 1.96.7
4
4
  Summary: Python package for Cloudnet processing
5
5
  Author: Simo Tukiainen
6
6
  License: MIT License
@@ -35,11 +35,11 @@ Classifier: License :: OSI Approved :: MIT License
35
35
  Classifier: Operating System :: OS Independent
36
36
  Classifier: Programming Language :: Python :: 3
37
37
  Classifier: Topic :: Scientific/Engineering :: Atmospheric Science
38
- Requires-Python: >=3.10
38
+ Requires-Python: >=3.11
39
39
  Description-Content-Type: text/markdown
40
40
  License-File: LICENSE
41
41
  Requires-Dist: atmoslib>=2.4.2
42
- Requires-Dist: ceilopyter>=0.2.0
42
+ Requires-Dist: ceilopyter>=0.2.2
43
43
  Requires-Dist: cloudnet-api-client
44
44
  Requires-Dist: doppy>=0.5.0
45
45
  Requires-Dist: matplotlib
@@ -48,7 +48,6 @@ Requires-Dist: netCDF4
48
48
  Requires-Dist: requests
49
49
  Requires-Dist: rpgpy>=0.14.5
50
50
  Requires-Dist: scipy
51
- Requires-Dist: typing-extensions
52
51
  Provides-Extra: test
53
52
  Requires-Dist: cloudnetpy_qc; extra == "test"
54
53
  Requires-Dist: mypy; extra == "test"
@@ -5,12 +5,11 @@ import logging
5
5
  from collections.abc import Sequence
6
6
  from dataclasses import fields
7
7
  from os import PathLike
8
- from typing import TypedDict
8
+ from typing import NotRequired, TypedDict
9
9
  from uuid import UUID
10
10
 
11
11
  import numpy as np
12
12
  from numpy.typing import NDArray
13
- from typing_extensions import NotRequired
14
13
 
15
14
  from cloudnetpy import output, utils
16
15
  from cloudnetpy.categorize import attenuation, classify
@@ -888,7 +888,7 @@ def main() -> None:
888
888
  "--date",
889
889
  type=str,
890
890
  help="Date in YYYY-MM-DD (default: today)",
891
- default=datetime.datetime.now(tz=datetime.timezone.utc).date().isoformat(),
891
+ default=datetime.datetime.now(tz=datetime.UTC).date().isoformat(),
892
892
  )
893
893
  parser.add_argument(
894
894
  "-p",
@@ -7,13 +7,12 @@ from collections.abc import Iterable, Sequence
7
7
  from os import PathLike
8
8
  from pathlib import Path
9
9
  from types import TracebackType
10
- from typing import Literal
10
+ from typing import Literal, Self
11
11
 
12
12
  import netCDF4
13
13
  import numpy as np
14
14
  import numpy.typing as npt
15
15
  from numpy import ma
16
- from typing_extensions import Self
17
16
 
18
17
  from cloudnetpy import utils
19
18
  from cloudnetpy.exceptions import ValidTimeStampError
@@ -6,11 +6,11 @@ import os
6
6
  from collections.abc import Callable
7
7
  from os import PathLike
8
8
  from types import TracebackType
9
+ from typing import Self
9
10
 
10
11
  import netCDF4
11
12
  import numpy as np
12
13
  import numpy.typing as npt
13
- from typing_extensions import Self
14
14
 
15
15
  from cloudnetpy import utils
16
16
  from cloudnetpy.cloudnetarray import CloudnetArray
@@ -98,6 +98,11 @@ def ceilo2nc(
98
98
  ceilo_obj.sort_time()
99
99
  ceilo_obj.screen_date()
100
100
  ceilo_obj.convert_to_fraction_hour()
101
+ elif isinstance(ceilo_obj, LufftCeilo):
102
+ ceilo_obj.read_ceilometer_file(calibration_factor)
103
+ ceilo_obj.sort_time()
104
+ ceilo_obj.screen_date()
105
+ ceilo_obj.convert_to_fraction_hour()
101
106
  else:
102
107
  ceilo_obj.read_ceilometer_file(calibration_factor)
103
108
  ceilo_obj.check_beta_raw_shape()
@@ -83,7 +83,13 @@ class Ceilometer:
83
83
 
84
84
  def prepare_data(self) -> None:
85
85
  """Add common additional data / metadata and convert into CloudnetArrays."""
86
- zenith_angle = self.data["zenith_angle"]
86
+ zenith_angle = self.data.get("zenith_angle")
87
+ if zenith_angle is None:
88
+ zenith_angle = 3.0
89
+ logging.warning("No zenith angle found, assuming %s degrees", zenith_angle)
90
+ self.data["zenith_angle"] = zenith_angle
91
+ elif zenith_angle == 0:
92
+ logging.warning("Zenith angle 0 degrees - risk of specular reflection")
87
93
  self.data["height"] = np.array(
88
94
  self.site_meta["altitude"]
89
95
  + utils.range_to_height(self.data["range"], zenith_angle),
@@ -97,7 +97,7 @@ def hatpro2l1c(
97
97
  msg = "Timestamps are not increasing"
98
98
  raise RuntimeError(msg)
99
99
  dates = [
100
- datetime.datetime.fromtimestamp(t, tz=datetime.timezone.utc).date()
100
+ datetime.datetime.fromtimestamp(t, tz=datetime.UTC).date()
101
101
  for t in timestamps
102
102
  ]
103
103
  if len(set(dates)) != 1:
@@ -403,7 +403,7 @@ class Kazr(CloudnetInstrument):
403
403
  if not hasattr(self, "date"):
404
404
  self.date = epoch.date()
405
405
  midnight = datetime.datetime.combine(
406
- self.date, datetime.time.min, tzinfo=datetime.timezone.utc
406
+ self.date, datetime.time.min, tzinfo=datetime.UTC
407
407
  )
408
408
  return seconds + (epoch - midnight).total_seconds()
409
409
 
@@ -519,9 +519,7 @@ def _parse_time_units(units: str) -> datetime.datetime:
519
519
  text = " ".join(parts[2:4])
520
520
  for fmt in ("%Y-%m-%d %H:%M:%S", "%Y-%m-%d"):
521
521
  try:
522
- return datetime.datetime.strptime(text, fmt).replace(
523
- tzinfo=datetime.timezone.utc
524
- )
522
+ return datetime.datetime.strptime(text, fmt).replace(tzinfo=datetime.UTC)
525
523
  except ValueError:
526
524
  continue
527
525
  msg = f"Invalid time units: {units}"
@@ -0,0 +1,79 @@
1
+ """Module with a class for Lufft chm15k ceilometer."""
2
+
3
+ import datetime
4
+ from os import PathLike
5
+
6
+ import numpy as np
7
+ import numpy.typing as npt
8
+ from ceilopyter import read_chm15k
9
+ from ceilopyter.version import __version__ as ceilopyter_version
10
+ from numpy import ma
11
+
12
+ from cloudnetpy import utils
13
+ from cloudnetpy.instruments import instruments
14
+ from cloudnetpy.instruments.ceilometer import Ceilometer
15
+
16
+
17
+ class LufftCeilo(Ceilometer):
18
+ """Class for Lufft chm15k ceilometer."""
19
+
20
+ def __init__(
21
+ self,
22
+ file_name: str | PathLike | list[str | PathLike],
23
+ site_meta: dict,
24
+ expected_date: datetime.date | None = None,
25
+ ) -> None:
26
+ super().__init__()
27
+ self.file_name = file_name
28
+ self.site_meta = site_meta
29
+ self.expected_date = expected_date
30
+ self.software = {"ceilopyter": ceilopyter_version}
31
+
32
+ def read_ceilometer_file(self, calibration_factor: float | None = None) -> None:
33
+ """Reads data and metadata from Jenoptik netCDF file."""
34
+ ceilo = read_chm15k(self.file_name, calibration_factor)
35
+ self.data["beta"] = ceilo.beta
36
+ self.data["beta_raw"] = ceilo.beta_raw
37
+ self.data["time"] = ceilo.time
38
+ self.data["range"] = ceilo.range
39
+ if ceilo.zenith_angle is not None:
40
+ self.data["zenith_angle"] = ma.median(ceilo.zenith_angle)
41
+ self.data["calibration_factor"] = ceilo.calibration_factor
42
+ self.serial_number = ceilo.serial_number
43
+ self.instrument = (
44
+ instruments.CHM15KX
45
+ if ceilo.serial_number and ceilo.serial_number.startswith("CHX")
46
+ else instruments.CHM15K
47
+ )
48
+
49
+ def sort_time(self) -> None:
50
+ """Sorts timestamps and removes duplicates."""
51
+ time = self.data["time"]
52
+ _time, ind = np.unique(time, return_index=True)
53
+ self._screen_time_indices(ind)
54
+
55
+ def screen_date(self) -> None:
56
+ time = self.data["time"]
57
+ self.date = time[0].date() if self.expected_date is None else self.expected_date
58
+ is_valid = np.array([t.date() == self.date for t in time])
59
+ self._screen_time_indices(is_valid)
60
+
61
+ def _screen_time_indices(
62
+ self, valid_indices: npt.NDArray[np.intp] | npt.NDArray[np.bool_]
63
+ ) -> None:
64
+ time = self.data["time"]
65
+ n_time = len(time)
66
+ if len(valid_indices) == 0 or (
67
+ valid_indices.dtype == np.bool_ and not np.any(valid_indices)
68
+ ):
69
+ msg = "All timestamps screened"
70
+ raise utils.ValidTimeStampError(msg)
71
+ for key, array in self.data.items():
72
+ if hasattr(array, "shape") and array.shape[:1] == (n_time,):
73
+ self.data[key] = self.data[key][valid_indices]
74
+
75
+ def convert_to_fraction_hour(self) -> None:
76
+ time = self.data["time"]
77
+ midnight = time[0].replace(hour=0, minute=0, second=0, microsecond=0)
78
+ hour = datetime.timedelta(hours=1)
79
+ self.data["time"] = np.array([(t - midnight) / hour for t in time])
@@ -128,7 +128,7 @@ class Mira(NcRadar):
128
128
 
129
129
  """
130
130
 
131
- epoch = datetime.datetime(1970, 1, 1, tzinfo=datetime.timezone.utc)
131
+ epoch = datetime.datetime(1970, 1, 1, tzinfo=datetime.UTC)
132
132
 
133
133
  def __init__(self, full_path: str | PathLike, site_meta: dict) -> None:
134
134
  super().__init__(full_path, site_meta)
@@ -126,7 +126,7 @@ class MrrPro(NcRadar):
126
126
 
127
127
  """
128
128
 
129
- epoch = datetime.datetime(1970, 1, 1, tzinfo=datetime.timezone.utc)
129
+ epoch = datetime.datetime(1970, 1, 1, tzinfo=datetime.UTC)
130
130
 
131
131
  def __init__(self, full_path: PathLike | str, site_meta: dict) -> None:
132
132
  super().__init__(full_path, site_meta)
@@ -223,7 +223,7 @@ class PalaiseauWS(WS):
223
223
  continue
224
224
  timestamp = datetime.datetime.strptime(
225
225
  columns[0], "%Y-%m-%dT%H:%M:%SZ"
226
- ).replace(tzinfo=datetime.timezone.utc)
226
+ ).replace(tzinfo=datetime.UTC)
227
227
  values.append([timestamp] + [float(x) for x in columns[1:]])
228
228
  timestamps.append(timestamp)
229
229
  else:
@@ -750,12 +750,12 @@ def _parse_sirta(filename: str | PathLike) -> dict:
750
750
  parsed: float | datetime.datetime
751
751
  if column == "Date Time (yyyy-mm-ddThh:mm:ss)":
752
752
  parsed = datetime.datetime.strptime(value, "%Y-%m-%dT%H:%M:%S").replace(
753
- tzinfo=datetime.timezone.utc
753
+ tzinfo=datetime.UTC
754
754
  )
755
755
  elif column == "Date Time (yyyy-mm-ddThh:mm:ssZ)":
756
756
  parsed = datetime.datetime.strptime(
757
757
  value, "%Y-%m-%dT%H:%M:%SZ"
758
- ).replace(tzinfo=datetime.timezone.utc)
758
+ ).replace(tzinfo=datetime.UTC)
759
759
  else:
760
760
  try:
761
761
  parsed = float(value)
@@ -794,7 +794,7 @@ class LAquilaWS(WS):
794
794
  continue
795
795
  timestamp = datetime.datetime.strptime(
796
796
  columns[0], "%Y-%m-%dT%H:%M:%SZ"
797
- ).replace(tzinfo=datetime.timezone.utc)
797
+ ).replace(tzinfo=datetime.UTC)
798
798
  data["time"].append(timestamp)
799
799
  data["air_temperature"].append(self._parse_value(columns[1]))
800
800
  data["air_pressure"].append(self._parse_value(columns[2]))
@@ -852,7 +852,7 @@ class ClujWS(WS):
852
852
 
853
853
  def _parse_datetime(self, value: str) -> datetime.datetime:
854
854
  return datetime.datetime.strptime(value, "%d.%m.%y %H:%M:%S.%f").replace(
855
- tzinfo=datetime.timezone.utc
855
+ tzinfo=datetime.UTC
856
856
  )
857
857
 
858
858
  def _parse_value(self, value: str) -> float:
@@ -1,5 +1,5 @@
1
1
  import logging
2
- from datetime import datetime, timezone
2
+ from datetime import UTC, datetime
3
3
  from os import PathLike
4
4
 
5
5
  import numpy as np
@@ -43,7 +43,7 @@ class ObservationManager(DataSource):
43
43
  0,
44
44
  0,
45
45
  0,
46
- tzinfo=timezone.utc,
46
+ tzinfo=UTC,
47
47
  )
48
48
 
49
49
  def _get_radar_frequency(self) -> npt.NDArray | None:
@@ -276,7 +276,7 @@ def merge_history(
276
276
  )
277
277
  except ValueError:
278
278
  return datetime.datetime.min.replace(
279
- tzinfo=datetime.timezone.utc
279
+ tzinfo=datetime.UTC
280
280
  ) # malformed lines to bottom
281
281
 
282
282
  histories.sort(key=parse_time, reverse=True)
@@ -3,7 +3,7 @@
3
3
  import re
4
4
  import textwrap
5
5
  from dataclasses import dataclass
6
- from datetime import date, datetime, timedelta, timezone
6
+ from datetime import UTC, date, datetime, timedelta
7
7
  from os import PathLike
8
8
  from typing import Any
9
9
 
@@ -180,7 +180,7 @@ class FigureData:
180
180
  int(self.file.year),
181
181
  int(self.file.month),
182
182
  int(self.file.day),
183
- tzinfo=timezone.utc,
183
+ tzinfo=UTC,
184
184
  )
185
185
 
186
186
  def _get_valid_variables_and_indices(
@@ -52,9 +52,7 @@ def seconds2hours(time_in_seconds: npt.NDArray) -> npt.NDArray:
52
52
 
53
53
  def seconds2date(
54
54
  time_in_seconds: float,
55
- epoch: datetime.datetime = datetime.datetime(
56
- 2001, 1, 1, tzinfo=datetime.timezone.utc
57
- ),
55
+ epoch: datetime.datetime = datetime.datetime(2001, 1, 1, tzinfo=datetime.UTC),
58
56
  ) -> datetime.datetime:
59
57
  """Converts seconds since some epoch to datetime (UTC).
60
58
 
@@ -753,7 +751,7 @@ def isscalar(array: npt.NDArray | float | list | netCDF4.Variable) -> bool:
753
751
 
754
752
  def get_time() -> str:
755
753
  """Returns current UTC-time."""
756
- t_zone = datetime.timezone.utc
754
+ t_zone = datetime.UTC
757
755
  form = "%Y-%m-%d %H:%M:%S"
758
756
  return f"{datetime.datetime.now(tz=t_zone).strftime(form)} +00:00"
759
757
 
@@ -924,7 +922,7 @@ def str_to_numeric(value: str) -> int | float:
924
922
 
925
923
  def get_epoch(units: str) -> datetime.datetime:
926
924
  """Finds epoch from units string."""
927
- fallback = datetime.datetime(2001, 1, 1, tzinfo=datetime.timezone.utc)
925
+ fallback = datetime.datetime(2001, 1, 1, tzinfo=datetime.UTC)
928
926
  try:
929
927
  date = units.split()[2]
930
928
  except IndexError:
@@ -940,9 +938,9 @@ def get_epoch(units: str) -> datetime.datetime:
940
938
  except ValueError:
941
939
  return fallback
942
940
  year, month, day = date_components
943
- current_year = datetime.datetime.now(tz=datetime.timezone.utc).year
941
+ current_year = datetime.datetime.now(tz=datetime.UTC).year
944
942
  if (1900 < year <= current_year) and (0 < month < 13) and (0 < day < 32):
945
- return datetime.datetime(year, month, day, tzinfo=datetime.timezone.utc)
943
+ return datetime.datetime(year, month, day, tzinfo=datetime.UTC)
946
944
  return fallback
947
945
 
948
946
 
@@ -1,4 +1,4 @@
1
1
  MAJOR = 1
2
2
  MINOR = 96
3
- PATCH = 6
3
+ PATCH = 7
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.6
3
+ Version: 1.96.7
4
4
  Summary: Python package for Cloudnet processing
5
5
  Author: Simo Tukiainen
6
6
  License: MIT License
@@ -35,11 +35,11 @@ Classifier: License :: OSI Approved :: MIT License
35
35
  Classifier: Operating System :: OS Independent
36
36
  Classifier: Programming Language :: Python :: 3
37
37
  Classifier: Topic :: Scientific/Engineering :: Atmospheric Science
38
- Requires-Python: >=3.10
38
+ Requires-Python: >=3.11
39
39
  Description-Content-Type: text/markdown
40
40
  License-File: LICENSE
41
41
  Requires-Dist: atmoslib>=2.4.2
42
- Requires-Dist: ceilopyter>=0.2.0
42
+ Requires-Dist: ceilopyter>=0.2.2
43
43
  Requires-Dist: cloudnet-api-client
44
44
  Requires-Dist: doppy>=0.5.0
45
45
  Requires-Dist: matplotlib
@@ -48,7 +48,6 @@ Requires-Dist: netCDF4
48
48
  Requires-Dist: requests
49
49
  Requires-Dist: rpgpy>=0.14.5
50
50
  Requires-Dist: scipy
51
- Requires-Dist: typing-extensions
52
51
  Provides-Extra: test
53
52
  Requires-Dist: cloudnetpy_qc; extra == "test"
54
53
  Requires-Dist: mypy; extra == "test"
@@ -1,5 +1,5 @@
1
1
  atmoslib>=2.4.2
2
- ceilopyter>=0.2.0
2
+ ceilopyter>=0.2.2
3
3
  cloudnet-api-client
4
4
  doppy>=0.5.0
5
5
  matplotlib
@@ -8,7 +8,6 @@ netCDF4
8
8
  requests
9
9
  rpgpy>=0.14.5
10
10
  scipy
11
- typing-extensions
12
11
 
13
12
  [dev]
14
13
  pre-commit
@@ -4,7 +4,7 @@ description = "Python package for Cloudnet processing"
4
4
  authors = [{name = "Simo Tukiainen"}]
5
5
  readme = "README.md"
6
6
  license = {file = "LICENSE"}
7
- requires-python = ">=3.10"
7
+ requires-python = ">=3.11"
8
8
  classifiers = [
9
9
  "Development Status :: 5 - Production/Stable",
10
10
  "Intended Audience :: Science/Research",
@@ -15,7 +15,7 @@ classifiers = [
15
15
  ]
16
16
  dependencies = [
17
17
  "atmoslib>=2.4.2",
18
- "ceilopyter>=0.2.0",
18
+ "ceilopyter>=0.2.2",
19
19
  "cloudnet-api-client",
20
20
  "doppy>=0.5.0",
21
21
  "matplotlib",
@@ -24,7 +24,6 @@ dependencies = [
24
24
  "requests",
25
25
  "rpgpy>=0.14.5",
26
26
  "scipy",
27
- "typing-extensions",
28
27
  ]
29
28
  dynamic = ["version"]
30
29
 
@@ -1,113 +0,0 @@
1
- """Module with a class for Lufft chm15k ceilometer."""
2
-
3
- import datetime
4
- import logging
5
- from os import PathLike
6
-
7
- import netCDF4
8
- import numpy as np
9
- from numpy import ma
10
-
11
- from cloudnetpy import utils
12
- from cloudnetpy.instruments import instruments
13
- from cloudnetpy.instruments.nc_lidar import NcLidar
14
-
15
-
16
- class LufftCeilo(NcLidar):
17
- """Class for Lufft chm15k ceilometer."""
18
-
19
- def __init__(
20
- self,
21
- file_name: str | PathLike,
22
- site_meta: dict,
23
- expected_date: datetime.date | None = None,
24
- ) -> None:
25
- super().__init__()
26
- self.file_name = file_name
27
- self.site_meta = site_meta
28
- self.expected_date = expected_date
29
- self.is_old_version = False
30
-
31
- def read_ceilometer_file(self, calibration_factor: float | None = None) -> None:
32
- """Reads data and metadata from Jenoptik netCDF file."""
33
- with netCDF4.Dataset(self.file_name) as dataset:
34
- self.dataset = dataset
35
- self._fetch_attributes()
36
- self._fetch_range(reference="upper")
37
- self._fetch_beta_raw(calibration_factor)
38
- self._fetch_time_and_date()
39
- self._fetch_zenith_angle("zenith")
40
-
41
- def _fetch_beta_raw(self, calibration_factor: float | None = None) -> None:
42
- if calibration_factor is None:
43
- logging.warning("Using default calibration factor")
44
- calibration_factor = 3e-12
45
- beta_raw = self._getvar("beta_raw", "beta_att")
46
- beta_raw = ma.array(beta_raw)
47
- old_version = self._get_old_software_version()
48
- if old_version is not None:
49
- self.is_old_version = True
50
- logging.warning(
51
- "Software version %s. Assuming data not range corrected.",
52
- old_version,
53
- )
54
- data_std = self._getvar("stddev")
55
- normalised_apd = self._get_nn()
56
- beta_raw *= utils.transpose(ma.array(data_std / normalised_apd))
57
- beta_raw *= self.data["range"] ** 2
58
- beta_raw *= calibration_factor
59
- self.data["calibration_factor"] = float(calibration_factor)
60
- self.data["beta_raw"] = beta_raw
61
-
62
- def _get_old_software_version(self) -> str | None:
63
- if self.dataset is None:
64
- msg = "No dataset found"
65
- raise RuntimeError(msg)
66
- version = self.dataset.software_version
67
- # In old files, the version is a single integer.
68
- if isinstance(version, np.integer):
69
- return str(version)
70
- # In newer files, the version is a space-separated list: Operating
71
- # system, FPGA, firmware, CloudDetectionMode (added in firmware 0.747).
72
- if isinstance(version, str):
73
- parts = version.split()
74
- firmware = parts[2]
75
- if firmware < "0.702":
76
- return firmware
77
- return None
78
- msg = f"Cannot determine version: {version}"
79
- raise RuntimeError(msg)
80
-
81
- def _get_nn(self) -> float | ma.MaskedArray:
82
- nn1 = self._getvar("nn1", "NN1")
83
- median_nn1 = ma.median(nn1)
84
- # Parameters taken from the matlab code and should be verified
85
- if 120 < median_nn1 < 160:
86
- step_factor, reference, scale = 1.24, 140, 5
87
- elif 3200 < median_nn1 < 4000:
88
- step_factor, reference, scale = 1.035, 3685, 1
89
- else:
90
- logging.warning("Unable to compute normalized APD")
91
- return 1
92
- return step_factor ** (-(nn1 - reference) / scale)
93
-
94
- def _getvar(self, *args: str) -> float | ma.MaskedArray:
95
- if self.dataset is None:
96
- msg = "No dataset found"
97
- raise RuntimeError(msg)
98
- for arg in args:
99
- if arg in self.dataset.variables:
100
- var = self.dataset.variables[arg]
101
- return var[0] if utils.isscalar(var) else var[:]
102
- msg = f"Unable to find variable {args[0]}"
103
- raise ValueError(msg)
104
-
105
- def _fetch_attributes(self) -> None:
106
- self.serial_number = getattr(self.dataset, "device_name", None)
107
- if self.serial_number is None:
108
- self.serial_number = getattr(self.dataset, "source", "")
109
- self.instrument = (
110
- instruments.CHM15KX
111
- if self.serial_number.startswith("CHX")
112
- else instruments.CHM15K
113
- )
File without changes
File without changes
File without changes
File without changes