cloudnetpy 1.79.1__py3-none-any.whl → 1.80.1__py3-none-any.whl

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.
@@ -4,6 +4,8 @@ import logging
4
4
  from itertools import islice
5
5
 
6
6
  import netCDF4
7
+ import numpy as np
8
+ from ceilopyter import read_ct25k
7
9
  from numpy import ma
8
10
 
9
11
  from cloudnetpy import output, utils
@@ -74,38 +76,52 @@ def ceilo2nc(
74
76
  range_corrected = site_meta.get("range_corrected", True)
75
77
  if range_corrected is False:
76
78
  logging.warning("Raw data not range-corrected.")
77
- ceilo_obj.read_ceilometer_file(calibration_factor)
78
- ceilo_obj.check_beta_raw_shape()
79
- n_negatives = _get_n_negatives(ceilo_obj)
80
- ceilo_obj.data["beta"] = ceilo_obj.calc_screened_product(
81
- ceilo_obj.data["beta_raw"],
82
- snr_limit,
83
- range_corrected=range_corrected,
84
- n_negatives=n_negatives,
85
- )
86
- ceilo_obj.data["beta_smooth"] = ceilo_obj.calc_beta_smooth(
87
- ceilo_obj.data["beta"],
88
- snr_limit,
89
- range_corrected=range_corrected,
90
- n_negatives=n_negatives,
91
- )
92
- if ceilo_obj.instrument is None or ceilo_obj.instrument.model is None:
93
- msg = "Failed to read ceilometer model"
94
- raise RuntimeError(msg)
95
- if (
96
- any(
97
- model in ceilo_obj.instrument.model.lower()
98
- for model in ("cl61", "chm15k", "chm15kx", "cl51", "cl31")
79
+ if isinstance(ceilo_obj, Ct25k):
80
+ c_obj = read_ct25k(full_path, calibration_factor, range_corrected)
81
+ ceilo_obj.data["beta"] = c_obj.beta
82
+ ceilo_obj.data["beta_raw"] = c_obj.beta_raw
83
+ ceilo_obj.data["time"] = c_obj.time
84
+ ceilo_obj.data["range"] = c_obj.range
85
+ if c_obj.zenith_angle is not None:
86
+ ceilo_obj.data["zenith_angle"] = np.median(c_obj.zenith_angle)
87
+ ceilo_obj.data["calibration_factor"] = c_obj.calibration_factor
88
+ ceilo_obj.sort_time()
89
+ ceilo_obj.screen_date()
90
+ ceilo_obj.convert_to_fraction_hour()
91
+ else:
92
+ ceilo_obj.read_ceilometer_file(calibration_factor)
93
+ ceilo_obj.check_beta_raw_shape()
94
+ n_negatives = _get_n_negatives(ceilo_obj)
95
+ ceilo_obj.data["beta"] = ceilo_obj.calc_screened_product(
96
+ ceilo_obj.data["beta_raw"],
97
+ snr_limit,
98
+ range_corrected=range_corrected,
99
+ n_negatives=n_negatives,
100
+ )
101
+ ceilo_obj.data["beta_smooth"] = ceilo_obj.calc_beta_smooth(
102
+ ceilo_obj.data["beta"],
103
+ snr_limit,
104
+ range_corrected=range_corrected,
105
+ n_negatives=n_negatives,
99
106
  )
100
- and range_corrected
101
- ):
102
- mask = ceilo_obj.data["beta_smooth"].mask
103
- ceilo_obj.data["beta"] = ma.masked_where(mask, ceilo_obj.data["beta_raw"])
104
- ceilo_obj.data["beta"][ceilo_obj.data["beta"] <= 0] = ma.masked
105
- if "depolarisation" in ceilo_obj.data:
106
- ceilo_obj.data["depolarisation"].mask = ceilo_obj.data["beta"].mask
107
+ if ceilo_obj.instrument is None or ceilo_obj.instrument.model is None:
108
+ msg = "Failed to read ceilometer model"
109
+ raise RuntimeError(msg)
110
+ if (
111
+ any(
112
+ model in ceilo_obj.instrument.model.lower()
113
+ for model in ("cl61", "chm15k", "chm15kx", "cl51", "cl31")
114
+ )
115
+ and range_corrected
116
+ ):
117
+ mask = ceilo_obj.data["beta_smooth"].mask
118
+ ceilo_obj.data["beta"] = ma.masked_where(mask, ceilo_obj.data["beta_raw"])
119
+ ceilo_obj.data["beta"][ceilo_obj.data["beta"] <= 0] = ma.masked
120
+ if "depolarisation" in ceilo_obj.data:
121
+ ceilo_obj.data["depolarisation"].mask = ceilo_obj.data["beta"].mask
107
122
  ceilo_obj.screen_depol()
108
123
  ceilo_obj.screen_invalid_values()
124
+ ceilo_obj.screen_sunbeam()
109
125
  ceilo_obj.prepare_data()
110
126
  ceilo_obj.data_to_cloudnet_arrays()
111
127
  ceilo_obj.add_site_geolocation()
@@ -137,6 +137,24 @@ class Ceilometer:
137
137
  msg = f"Invalid beta_raw shape: {beta_raw.shape}"
138
138
  raise ValidTimeStampError(msg)
139
139
 
140
+ def screen_sunbeam(self) -> None:
141
+ high_alt_mask = self.data["range"] > 10000
142
+ if not np.any(high_alt_mask):
143
+ return
144
+
145
+ is_data = ~self.data["beta"][:, high_alt_mask].mask
146
+ n_bins = 20
147
+
148
+ n_profiles, n_heights = is_data.shape
149
+ bin_size = n_heights // n_bins
150
+ reshaped = is_data[:, : bin_size * n_bins].reshape(n_profiles, n_bins, bin_size)
151
+
152
+ valid_profiles = np.any(reshaped, axis=2).sum(axis=1) < 15
153
+
154
+ for key, value in self.data.items():
155
+ if key == "time" or (isinstance(value, np.ndarray) and value.ndim == 2):
156
+ self.data[key] = value[valid_profiles]
157
+
140
158
 
141
159
  class NoisyData:
142
160
  def __init__(
@@ -46,18 +46,18 @@ class VaisalaCeilo(Ceilometer):
46
46
  self.data["calibration_factor"] = calibration_factor or 1.0
47
47
  self.data["beta_raw"] *= self.data["calibration_factor"]
48
48
  self.data["zenith_angle"] = np.median([d.tilt_angle for d in data])
49
- self._sort_time()
50
- self._screen_date()
51
- self._convert_to_fraction_hour()
49
+ self.sort_time()
50
+ self.screen_date()
51
+ self.convert_to_fraction_hour()
52
52
  self._store_ceilometer_info()
53
53
 
54
- def _sort_time(self):
54
+ def sort_time(self):
55
55
  """Sorts timestamps and removes duplicates."""
56
56
  time = self.data["time"]
57
57
  _time, ind = np.unique(time, return_index=True)
58
58
  self._screen_time_indices(ind)
59
59
 
60
- def _screen_date(self):
60
+ def screen_date(self):
61
61
  time = self.data["time"]
62
62
  if self.sane_date is None:
63
63
  self.sane_date = time[0].date()
@@ -79,7 +79,7 @@ class VaisalaCeilo(Ceilometer):
79
79
  if hasattr(array, "shape") and array.shape[:1] == (n_time,):
80
80
  self.data[key] = self.data[key][valid_indices]
81
81
 
82
- def _convert_to_fraction_hour(self):
82
+ def convert_to_fraction_hour(self):
83
83
  time = self.data["time"]
84
84
  midnight = time[0].replace(hour=0, minute=0, second=0, microsecond=0)
85
85
  hour = datetime.timedelta(hours=1)
@@ -113,6 +113,7 @@ class Ct25k(VaisalaCeilo):
113
113
 
114
114
  def __init__(self, full_path, site_meta, expected_date=None):
115
115
  super().__init__(read_ct_file, full_path, site_meta, expected_date)
116
+ self._store_ceilometer_info()
116
117
 
117
118
  def _store_ceilometer_info(self):
118
119
  self.instrument = instruments.CT25K
cloudnetpy/version.py CHANGED
@@ -1,4 +1,4 @@
1
1
  MAJOR = 1
2
- MINOR = 79
2
+ MINOR = 80
3
3
  PATCH = 1
4
4
  __version__ = f"{MAJOR}.{MINOR}.{PATCH}"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cloudnetpy
3
- Version: 1.79.1
3
+ Version: 1.80.1
4
4
  Summary: Python package for Cloudnet processing
5
5
  Author: Simo Tukiainen
6
6
  License: MIT License
@@ -38,7 +38,7 @@ 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: ceilopyter
41
+ Requires-Dist: ceilopyter>=0.2.0
42
42
  Requires-Dist: doppy>=0.5.0
43
43
  Requires-Dist: matplotlib
44
44
  Requires-Dist: mwrpy>=1.3.0
@@ -9,7 +9,7 @@ cloudnetpy/metadata.py,sha256=lO7BCbVAzFoH3Nq-VuezYX0f7MnbG1Zp11g5GSiuQwM,6189
9
9
  cloudnetpy/output.py,sha256=gupxt4f_-eUrFsWMto8tnknoV-p9QauC9L6CJAqBILU,15988
10
10
  cloudnetpy/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
11
11
  cloudnetpy/utils.py,sha256=WczDeGN408XSgGeaRLXFmlLjgAS67lK1osV0YEuKmwo,32027
12
- cloudnetpy/version.py,sha256=l8L_HNpJqIkeEmJ8zUGir5O1urLeyDtTP8h6HO2_SFY,72
12
+ cloudnetpy/version.py,sha256=3m_TWVm1w7D_LWUssqw3Dz6luV3AUQL5hIn7k2KVs78,72
13
13
  cloudnetpy/categorize/__init__.py,sha256=s-SJaysvVpVVo5kidiruWQO6p3gv2TXwY1wEHYO5D6I,44
14
14
  cloudnetpy/categorize/atmos_utils.py,sha256=RcmbKxm2COkE7WEya0mK3yX5rzUbrewRVh3ekm01RtM,10598
15
15
  cloudnetpy/categorize/attenuation.py,sha256=Y_-fzmQTltWTqIZTulJhovC7a6ifpMcaAazDJcnMIOc,990
@@ -35,8 +35,8 @@ cloudnetpy/categorize/attenuations/rain_attenuation.py,sha256=qazJzRyXf9vbjJhh4y
35
35
  cloudnetpy/instruments/__init__.py,sha256=PEgrrQNoiOuN_ctYilmt4LV2QCLg1likPjJdWtuGlLs,528
36
36
  cloudnetpy/instruments/basta.py,sha256=Lb_EhQTI93S5Bd9osDbCE_tC8gZreRsHz7D2_dFOjmE,3793
37
37
  cloudnetpy/instruments/bowtie.py,sha256=EyE8HAE8rjO7JelJDbQte_rnwE3VoVJVc6TBpSNK3IU,3930
38
- cloudnetpy/instruments/ceilo.py,sha256=QQ4pK_GmvQVUgTj1Wc3w8kM6VMKgOxO28pCPrrN1Avg,9664
39
- cloudnetpy/instruments/ceilometer.py,sha256=XS2hVJ7rn9WOUKq19wpNL5MJr59fKSEWHC_1pOE_Bm4,12323
38
+ cloudnetpy/instruments/ceilo.py,sha256=arXI7i8UiTVIk4N1P8Mnpgs_oXN79ReeBjpYuqqwL04,10473
39
+ cloudnetpy/instruments/ceilometer.py,sha256=8DzOUC7PUZYLfCC9t9LA5YSsF78xs4B4VjBLx6S-wDE,12980
40
40
  cloudnetpy/instruments/cl61d.py,sha256=0QMqXHIy0hn2mksAwTdaKMOaEWjsZmj7QZ8hCbcHwxE,2225
41
41
  cloudnetpy/instruments/cloudnet_instrument.py,sha256=SGPsRYYoGPoRoDY7hHJcKUVX0A23X0Telc00Fu01PnY,4495
42
42
  cloudnetpy/instruments/copernicus.py,sha256=hCphEKyFCc3f1uLRdjL2435kuh64M5q-V1bI68bzGbA,6528
@@ -55,7 +55,7 @@ cloudnetpy/instruments/rain_e_h3.py,sha256=JEg4Ko7ZdfjAUJwJ1BWdTkm4K7r3s8WKrPb-H
55
55
  cloudnetpy/instruments/rpg.py,sha256=m3-xLJ-w2T7Ip7jBveWsGrts4tmNvdc-Lb4HebvHQjQ,17319
56
56
  cloudnetpy/instruments/rpg_reader.py,sha256=ThztFuVrWxhmWVAfZTfQDeUiKK1XMTbtv08IBe8GK98,11364
57
57
  cloudnetpy/instruments/toa5.py,sha256=CfmmBMv5iMGaWHIGBK01Rw24cuXC1R1RMNTXkmsm340,1760
58
- cloudnetpy/instruments/vaisala.py,sha256=RKAw_fVry4YOUF0i2_-2jLIc6_H85oL8USA4ji9rh0o,4583
58
+ cloudnetpy/instruments/vaisala.py,sha256=W_yu_f92cOq8RiiqDLj7bswxu9UMS3TITPWzP5xPdvA,4615
59
59
  cloudnetpy/instruments/weather_station.py,sha256=pZK7I5bk1USDRoTeIhZoWzbka9ciea5ypA3oIzZX-7g,24549
60
60
  cloudnetpy/instruments/disdrometer/__init__.py,sha256=lyjwttWvFvuwYxEkusoAvgRcbBmglmOp5HJOpXUqLWo,93
61
61
  cloudnetpy/instruments/disdrometer/common.py,sha256=g52iK2aNp3Z88kovUmGVpC54NZomPa9D871gzO0AmQ4,9267
@@ -117,10 +117,10 @@ cloudnetpy/products/lwc.py,sha256=sl6Al2tuH3KkCBrPbWTmuz3jlD5UQJ4D6qBsn1tt2CQ,18
117
117
  cloudnetpy/products/mie_lu_tables.nc,sha256=It4fYpqJXlqOgL8jeZ-PxGzP08PMrELIDVe55y9ob58,16637951
118
118
  cloudnetpy/products/mwr_tools.py,sha256=8HPZpQMTojKZP1JS1S83IE0sxmbDE9bxlaWoqmGnUZE,6199
119
119
  cloudnetpy/products/product_tools.py,sha256=uu4l6reuGbPcW3TgttbaSrqIKbyYGhBVTdnC7opKvmg,11101
120
- cloudnetpy-1.79.1.dist-info/licenses/LICENSE,sha256=wcZF72bdaoG9XugpyE95Juo7lBQOwLuTKBOhhtANZMM,1094
120
+ cloudnetpy-1.80.1.dist-info/licenses/LICENSE,sha256=wcZF72bdaoG9XugpyE95Juo7lBQOwLuTKBOhhtANZMM,1094
121
121
  docs/source/conf.py,sha256=IKiFWw6xhUd8NrCg0q7l596Ck1d61XWeVjIFHVSG9Og,1490
122
- cloudnetpy-1.79.1.dist-info/METADATA,sha256=JtMnhiVSz-jUPZS17gY4BKPyUjYqhvuYl9YB7KC7lxU,5796
123
- cloudnetpy-1.79.1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
124
- cloudnetpy-1.79.1.dist-info/entry_points.txt,sha256=HhY7LwCFk4qFgDlXx_Fy983ZTd831WlhtdPIzV-Y3dY,51
125
- cloudnetpy-1.79.1.dist-info/top_level.txt,sha256=ibSPWRr6ojS1i11rtBFz2_gkIe68mggj7aeswYfaOo0,16
126
- cloudnetpy-1.79.1.dist-info/RECORD,,
122
+ cloudnetpy-1.80.1.dist-info/METADATA,sha256=to7qpA_egtY91A4EKfa0SckgPWNMr2AkbZ2iWM8VYzA,5803
123
+ cloudnetpy-1.80.1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
124
+ cloudnetpy-1.80.1.dist-info/entry_points.txt,sha256=HhY7LwCFk4qFgDlXx_Fy983ZTd831WlhtdPIzV-Y3dY,51
125
+ cloudnetpy-1.80.1.dist-info/top_level.txt,sha256=ibSPWRr6ojS1i11rtBFz2_gkIe68mggj7aeswYfaOo0,16
126
+ cloudnetpy-1.80.1.dist-info/RECORD,,