doppy 0.5.9__cp310-abi3-macosx_10_12_x86_64.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.
doppy/raw/wls77.py ADDED
@@ -0,0 +1,163 @@
1
+ from __future__ import annotations
2
+
3
+ from dataclasses import dataclass
4
+ from datetime import datetime, timezone
5
+ from io import BufferedIOBase
6
+ from pathlib import Path
7
+ from typing import Any, Sequence
8
+
9
+ import numpy as np
10
+ import numpy.typing as npt
11
+ from numpy import datetime64
12
+
13
+ import doppy
14
+ from doppy import exceptions
15
+ from doppy.raw.utils import bytes_from_src
16
+ from doppy.utils import merge_all_equal
17
+
18
+
19
+ @dataclass
20
+ class Wls77:
21
+ time: npt.NDArray[datetime64] # dim: (time, )
22
+ altitude: npt.NDArray[np.float64] # dim: (altitude, )
23
+ position: npt.NDArray[np.float64] # dim: (time, )
24
+ temperature: npt.NDArray[np.float64] # dim: (time, )
25
+ wiper_count: npt.NDArray[np.float64] # dim: (time, )
26
+ cnr: npt.NDArray[np.float64] # dim: (time, altitude)
27
+ radial_velocity: npt.NDArray[np.float64] # dim: (time, altitude)
28
+ radial_velocity_deviation: npt.NDArray[np.float64] # dim: (time, altitude)
29
+ wind_speed: npt.NDArray[np.float64] # dim: (time, altitude)
30
+ wind_direction: npt.NDArray[np.float64] # dim: (time, altitude)
31
+ zonal_wind: npt.NDArray[np.float64] # u := zonal wind?, dim: (time, altitude)
32
+ meridional_wind: npt.NDArray[
33
+ np.float64
34
+ ] # v := meridional wind?, dim: (time, altitude)
35
+ vertical_wind: npt.NDArray[np.float64] # w := vertical wind?, dim: (time, altitude)
36
+ cnr_threshold: float
37
+ system_id: str
38
+
39
+ @classmethod
40
+ def from_srcs(
41
+ cls, data: Sequence[str | bytes | Path | BufferedIOBase]
42
+ ) -> list[Wls77]:
43
+ data_bytes = [bytes_from_src(src) for src in data]
44
+ raws = doppy.rs.raw.wls77.from_bytes_srcs(data_bytes)
45
+ try:
46
+ return [_raw_rs_to_wls77(r) for r in raws]
47
+ except RuntimeError as err:
48
+ raise exceptions.RawParsingError(err) from err
49
+
50
+ @classmethod
51
+ def from_src(cls, data: str | Path | bytes | BufferedIOBase) -> Wls77:
52
+ data_bytes = bytes_from_src(data)
53
+ try:
54
+ return _raw_rs_to_wls77(doppy.rs.raw.wls77.from_bytes_src(data_bytes))
55
+ except RuntimeError as err:
56
+ raise exceptions.RawParsingError(err) from err
57
+
58
+ def __getitem__(
59
+ self,
60
+ index: int
61
+ | slice
62
+ | list[int]
63
+ | npt.NDArray[np.int64]
64
+ | npt.NDArray[np.bool_]
65
+ | tuple[slice, slice],
66
+ ) -> Wls77:
67
+ if isinstance(index, (int, slice, list, np.ndarray)):
68
+ return Wls77(
69
+ time=self.time[index],
70
+ altitude=self.altitude,
71
+ position=self.position[index],
72
+ temperature=self.temperature[index],
73
+ wiper_count=self.wiper_count[index],
74
+ cnr=self.cnr[index],
75
+ radial_velocity=self.radial_velocity[index],
76
+ radial_velocity_deviation=self.radial_velocity_deviation[index],
77
+ wind_speed=self.wind_speed[index],
78
+ wind_direction=self.wind_direction[index],
79
+ zonal_wind=self.zonal_wind[index],
80
+ meridional_wind=self.meridional_wind[index],
81
+ vertical_wind=self.vertical_wind[index],
82
+ system_id=self.system_id,
83
+ cnr_threshold=self.cnr_threshold,
84
+ )
85
+ raise TypeError
86
+
87
+ def sorted_by_time(self) -> Wls77:
88
+ sort_indices = np.argsort(self.time)
89
+ return self[sort_indices]
90
+
91
+ @classmethod
92
+ def merge(cls, raws: Sequence[Wls77]) -> Wls77:
93
+ return cls(
94
+ time=np.concatenate(tuple(r.time for r in raws)),
95
+ altitude=raws[0].altitude,
96
+ position=np.concatenate(tuple(r.position for r in raws)),
97
+ temperature=np.concatenate(tuple(r.temperature for r in raws)),
98
+ wiper_count=np.concatenate(tuple(r.wiper_count for r in raws)),
99
+ cnr=np.concatenate(tuple(r.cnr for r in raws)),
100
+ radial_velocity=np.concatenate(tuple(r.radial_velocity for r in raws)),
101
+ radial_velocity_deviation=np.concatenate(
102
+ tuple(r.radial_velocity_deviation for r in raws)
103
+ ),
104
+ wind_speed=np.concatenate(tuple(r.wind_speed for r in raws)),
105
+ wind_direction=np.concatenate(tuple(r.wind_direction for r in raws)),
106
+ zonal_wind=np.concatenate(tuple(r.zonal_wind for r in raws)),
107
+ meridional_wind=np.concatenate(tuple(r.meridional_wind for r in raws)),
108
+ vertical_wind=np.concatenate(tuple(r.vertical_wind for r in raws)),
109
+ system_id=merge_all_equal("system_id", [r.system_id for r in raws]),
110
+ cnr_threshold=merge_all_equal(
111
+ "cnr_threshold", [r.cnr_threshold for r in raws]
112
+ ),
113
+ )
114
+
115
+ def non_strictly_increasing_timesteps_removed(self) -> Wls77:
116
+ if len(self.time) == 0:
117
+ return self
118
+ mask = np.ones_like(self.time, dtype=np.bool_)
119
+ latest_time = self.time[0]
120
+ for i, t in enumerate(self.time[1:], start=1):
121
+ if t <= latest_time:
122
+ mask[i] = False
123
+ else:
124
+ latest_time = t
125
+ return self[mask]
126
+
127
+
128
+ def _raw_rs_to_wls77(
129
+ raw: dict[str, Any],
130
+ ) -> Wls77:
131
+ time_ts = raw["time"]
132
+ time = np.array(
133
+ [
134
+ datetime64(datetime.fromtimestamp(ts, timezone.utc).replace(tzinfo=None))
135
+ for ts in time_ts
136
+ ]
137
+ )
138
+
139
+ n = time.size
140
+
141
+ return Wls77(
142
+ time=time,
143
+ altitude=np.array(raw["altitude"], dtype=np.float64),
144
+ position=np.array(raw["position"], dtype=np.float64),
145
+ temperature=np.array(raw["temperature"], dtype=np.float64),
146
+ wiper_count=np.array(raw["wiper_count"], dtype=np.float64),
147
+ cnr=np.array(raw["cnr"], dtype=np.float64).reshape(n, -1),
148
+ radial_velocity=np.array(raw["radial_velocity"], dtype=np.float64).reshape(
149
+ n, -1
150
+ ),
151
+ radial_velocity_deviation=np.array(
152
+ raw["radial_velocity_deviation"], dtype=np.float64
153
+ ).reshape(n, -1),
154
+ wind_speed=np.array(raw["wind_speed"], dtype=np.float64).reshape(n, -1),
155
+ wind_direction=np.array(raw["wind_direction"], dtype=np.float64).reshape(n, -1),
156
+ zonal_wind=np.array(raw["zonal_wind"], dtype=np.float64).reshape(n, -1),
157
+ meridional_wind=np.array(raw["meridional_wind"], dtype=np.float64).reshape(
158
+ n, -1
159
+ ),
160
+ vertical_wind=np.array(raw["vertical_wind"], dtype=np.float64).reshape(n, -1),
161
+ cnr_threshold=raw["cnr_threshold"],
162
+ system_id=raw["system_id"],
163
+ )
doppy/rs.abi3.so ADDED
Binary file
doppy/utils.py ADDED
@@ -0,0 +1,24 @@
1
+ from typing import TypeVar, cast
2
+
3
+ import numpy as np
4
+ from numpy.typing import NDArray
5
+
6
+ T = TypeVar("T")
7
+ NT = TypeVar("NT", bound=np.generic)
8
+
9
+
10
+ def merge_all_equal(key: str, lst: list[T]) -> T:
11
+ if len(set(lst)) != 1:
12
+ raise ValueError(f"Cannot merge header key {key} values {lst}")
13
+ return lst[0]
14
+
15
+
16
+ def merge_all_close(key: str, lst: list[NDArray[NT]]) -> NT:
17
+ if len(lst) == 0:
18
+ raise ValueError(f"Cannot merge empty list for key {key}")
19
+ if any(arr.size == 0 for arr in lst):
20
+ raise ValueError(f"Cannot merge key {key}, one or more arrays are empty.")
21
+ arr = np.concatenate([arr.flatten() for arr in lst])
22
+ if not np.allclose(arr, arr[0]):
23
+ raise ValueError(f"Cannot merge key {key}, values are not close enough")
24
+ return cast(NT, arr[0])
@@ -0,0 +1,144 @@
1
+ Metadata-Version: 2.4
2
+ Name: doppy
3
+ Version: 0.5.9
4
+ Classifier: Development Status :: 4 - Beta
5
+ Classifier: Programming Language :: Python :: 3
6
+ Classifier: Programming Language :: Python :: 3.10
7
+ Classifier: Programming Language :: Python :: 3.11
8
+ Classifier: Programming Language :: Python :: 3.12
9
+ Classifier: Programming Language :: Python :: 3.13
10
+ Classifier: License :: OSI Approved :: MIT License
11
+ Classifier: Intended Audience :: Science/Research
12
+ Classifier: Operating System :: OS Independent
13
+ Requires-Dist: requests
14
+ Requires-Dist: urllib3
15
+ Requires-Dist: numpy
16
+ Requires-Dist: netcdf4
17
+ Requires-Dist: matplotlib
18
+ Requires-Dist: scikit-learn
19
+ Requires-Dist: scipy
20
+ Requires-Dist: mypy ; extra == 'dev'
21
+ Requires-Dist: pyright ; extra == 'dev'
22
+ Requires-Dist: ruff ; extra == 'dev'
23
+ Requires-Dist: pytest ; extra == 'dev'
24
+ Requires-Dist: types-requests ; extra == 'dev'
25
+ Requires-Dist: py-spy ; extra == 'dev'
26
+ Requires-Dist: maturin==1.8 ; extra == 'dev'
27
+ Requires-Dist: release-version ; extra == 'dev'
28
+ Requires-Dist: pre-commit ; extra == 'dev'
29
+ Requires-Dist: xarray[io] ; extra == 'dev'
30
+ Requires-Dist: seaborn ; extra == 'dev'
31
+ Requires-Dist: tomli ; extra == 'dev'
32
+ Requires-Dist: aiohttp ; extra == 'dev'
33
+ Requires-Dist: tqdm ; extra == 'dev'
34
+ Provides-Extra: dev
35
+ License-File: LICENSE
36
+ License-File: LICENSE
37
+ Author-email: Niko Leskinen <niko.leskinen@fmi.fi>
38
+ Requires-Python: >=3.10
39
+ Description-Content-Type: text/markdown; charset=UTF-8; variant=GFM
40
+ Project-URL: Homepage, https://github.com/actris-cloudnet/doppy
41
+ Project-URL: Repository, https://github.com/actris-cloudnet/doppy
42
+ Project-URL: Changelog, https://github.com/actris-cloudnet/doppy/blob/main/CHANGELOG.md
43
+ Project-URL: Bug Tracker, https://github.com/actris-cloudnet/doppy/issues
44
+
45
+ # Doppy – Doppler wind lidar processing
46
+
47
+ [![CI](https://github.com/actris-cloudnet/doppy/actions/workflows/ci.yml/badge.svg)](https://github.com/actris-cloudnet/doppy/actions/workflows/ci.yml)
48
+ [![PyPI version](https://badge.fury.io/py/doppy.svg)](https://badge.fury.io/py/doppy)
49
+
50
+ ## Products
51
+
52
+ - Stare: [src](https://github.com/actris-cloudnet/doppy/blob/main/src/doppy/product/stare.py), [Cloudnet examples](https://cloudnet.fmi.fi/search/visualizations?experimental=true&product=doppler-lidar&dateFrom=2024-06-05&dateTo=2024-06-05)
53
+ - Wind: [src](https://github.com/actris-cloudnet/doppy/blob/main/src/doppy/product/wind.py), [Cloudnet examples](https://cloudnet.fmi.fi/search/visualizations?experimental=true&product=doppler-lidar-wind&dateFrom=2024-06-05&dateTo=2024-06-05)
54
+
55
+ ## Instruments
56
+
57
+ - HALO Photonics Streamline lidars (stare, wind)
58
+ - Leosphere WindCube WLS200S (wind)
59
+ - Leosphere WindCube WLS70 (wind)
60
+
61
+ ## Install
62
+
63
+ ```sh
64
+ pip install doppy
65
+ ```
66
+
67
+ ## Usage
68
+
69
+ ### Stare
70
+
71
+ ```python
72
+ import doppy
73
+
74
+ stare = doppy.product.Stare.from_halo_data(
75
+ data=LIST_OF_STARE_FILE_PATHS,
76
+ data_bg=LIST_OF_BACKGROUND_FILE_PATHS,
77
+ bg_correction_method=doppy.options.BgCorrectionMethod.FIT,
78
+ )
79
+
80
+ stare.write_to_netcdf(FILENAME)
81
+ ```
82
+
83
+ ### Stare with depolarisation
84
+
85
+ ```python
86
+ import doppy
87
+
88
+ stare_depol = doppy.product.StareDepol.from_halo_data(
89
+ co_data=LIST_OF_STARE_CO_FILE_PATHS,
90
+ co_data_bg=LIST_OF_BACKGROUND_CO_FILE_PATHS,
91
+ cross_data=LIST_OF_STARE_CROSS_FILE_PATHS,
92
+ cross_data_bg=LIST_OF_BACKGROUND_CROSS_FILE_PATHS,
93
+ bg_correction_method=doppy.options.BgCorrectionMethod.FIT,
94
+ polariser_bleed_through=0,
95
+ )
96
+
97
+ stare_depol.write_to_netcdf(FILENAME)
98
+ ```
99
+
100
+ ### Wind
101
+
102
+ ```python
103
+ import doppy
104
+
105
+ wind = doppy.product.Wind.from_halo_data(
106
+ data=LIST_OF_WIND_SCAN_HPL_FILES,
107
+ )
108
+
109
+ # You can also pass instrument azimuth offset in degrees as an option
110
+ wind = doppy.product.Wind.from_halo_data(
111
+ data=LIST_OF_WIND_SCAN_HPL_FILES,
112
+ options=doppy.product.wind.Options(azimuth_offset_deg=30),
113
+ )
114
+
115
+ # For windcube wls200s use
116
+ wind = doppy.product.Wind.from_windcube_data(
117
+ data=LIST_OF_VAD_NETCDF_FILES,
118
+ )
119
+
120
+ # For windcube wls70 use
121
+ wind = doppy.product.Wind.from_wls70_data(
122
+ data=LIST_OF_RTD_FILES,
123
+ )
124
+
125
+ wind.write_to_netcdf(FILENAME)
126
+ ```
127
+
128
+ ### Raw files
129
+
130
+ ```python
131
+ import doppy
132
+
133
+ # Halo
134
+ raws_hpl = doppy.raw.HaloHpl.from_srcs(LIST_OF_HPL_FILES)
135
+ raws_bg = doppy.raw.HaloBg.from_srcs(LIST_OF_BACKGROUND_FILES)
136
+ raw_system_params = doppy.raw.HaloSysParams.from_src(SYSTEM_PARAMS_FILENAME)
137
+
138
+ # Windcube WLS200S
139
+ raws_wls200s = doppy.raw.WindCube.from_vad_or_dbs_srcs(LIST_OF_VAD_NETCDF_FILES)
140
+
141
+ # Windcube WLS70
142
+ raws_wls70 = doppy.raw.Wls70.from_srcs(LIST_OF_RTD_FILES)
143
+ ```
144
+
@@ -0,0 +1,33 @@
1
+ doppy-0.5.9.dist-info/METADATA,sha256=WVgfZybXdvNySG3RaZGdGyUQBeM6tBEaMkOGDaRQ7As,4404
2
+ doppy-0.5.9.dist-info/WHEEL,sha256=XgR1VxSNigcUD69jquUcXL6D2aWFuJdAo2F9tNo_qRs,106
3
+ doppy-0.5.9.dist-info/entry_points.txt,sha256=9b_Ca7vJoh6AwL3W8qAPh_UmJ_1Pa6hi-TDfCTDjvSk,43
4
+ doppy-0.5.9.dist-info/licenses/LICENSE,sha256=V-0iroMNMI8ctnLgUau1kdFvwhkYhr9vi-5kWKxw2wc,1089
5
+ doppy/__init__.py,sha256=Z9aEUlbPRWRUAoB8_-djkgrJuS4-6pjem4-mVSB6Z9I,191
6
+ doppy/bench.py,sha256=xUsmwLCjNLXwO9l-_SCfq62jxXJ4eiwkS-WlCejcqZE,308
7
+ doppy/data/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
8
+ doppy/data/api.py,sha256=hUIqyCq1wFu89gamK7xK8R58eXAODWvLQHaaS5eu6OY,1875
9
+ doppy/data/cache.py,sha256=cxCZ7HyEQt2EKAGEiMqx3wJ2-5Y3hEAEPQ_XB4gKlkk,1160
10
+ doppy/data/exceptions.py,sha256=6CS6OHIWq8CqlxiceEvC1j0EfWUYoIfM7dW88apQVn4,89
11
+ doppy/defaults.py,sha256=-jR_xAVLf_soZNDu3uJ6mhOZa9L1tfKtt0k0tI6Rd9s,472
12
+ doppy/exceptions.py,sha256=OzdLXmKs3qZrvzwaI0pxjzpM2w9J5Of7dCo_Ekygecc,183
13
+ doppy/netcdf.py,sha256=PuTCVK4yT4dkObo_w2D1lJroHg7l4DJFZxOi6jr1DkQ,4078
14
+ doppy/options.py,sha256=73BDODO4OYHn2qOshhwz6u6G3J1kNd3uj6P0a3V4HBE,205
15
+ doppy/product/__init__.py,sha256=C6s9cX20m9UwRsKo1lZH6TnYFfM5KmsX5MPUyShbgl4,235
16
+ doppy/product/noise_utils.py,sha256=fP2bK2xfCUClQcDc_1FmLUUiU2d0KycrxkXLC5jmJAc,2629
17
+ doppy/product/stare.py,sha256=e3mTaCw0H3Ud3Ql7pYQKzC368OUdQjaVQ8XOhAig1yo,26660
18
+ doppy/product/stare_depol.py,sha256=gSlD13jGLRmHyTDADFs_MO6ECos6wwKF-TL7G7NwHAA,10718
19
+ doppy/product/turbulence.py,sha256=hajTHFr6XXdul8oU9dw4Y58kBwRpUBIfiOfTcvSjq7M,8606
20
+ doppy/product/utils.py,sha256=1mngeUrs_mlRO3Z-bq5OWoFEMxX5uuosLVge1Jrp76s,310
21
+ doppy/product/wind.py,sha256=QyabapzOen_4oXLikmhjAjtlmOis18Ady57hQnrlzw8,15060
22
+ doppy/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
23
+ doppy/raw/__init__.py,sha256=HE-7x27dfw-LJTvReZfspqzNx63Nl0v5ACdYs9EuOFQ,325
24
+ doppy/raw/halo_bg.py,sha256=8t9j-SUF1yJht3vrT6KAYJQyxcg3W-0zr8h0jAEhWes,5815
25
+ doppy/raw/halo_hpl.py,sha256=L83SmH7TLLR55ElG3NuvDt6iKA0rSQ3S8YLg6eQAHeE,16939
26
+ doppy/raw/halo_sys_params.py,sha256=jclE4RbVg63iS3rVNYzvErKYAa3CI1q64xj3oai5tMc,5250
27
+ doppy/raw/utils.py,sha256=EOWIaxAZIiRYa9dI1j50cSd4I058Zq7sz1HOeipZFTg,422
28
+ doppy/raw/windcube.py,sha256=uL6htoeyrJ-zrHV_QM748TT0HyfA3rw7t2dQORx0OAU,19150
29
+ doppy/raw/wls70.py,sha256=OfPczHZPKX4iqCcyjSv0nmkr1osy4pu6krNUi0-G0vM,6319
30
+ doppy/raw/wls77.py,sha256=ciRNy0U1a4OuxbsHGt9HMHAa3Qqukaw57QeNQdkWUj8,6460
31
+ doppy/rs.abi3.so,sha256=uNd4xU4JfBmQMYAkuRydwp5FwrQM1P0IrH-CIddYLgk,2709356
32
+ doppy/utils.py,sha256=cY-tWrArrROX7lg_zJ2M4QJ6GUnU_BjhkUYL5aG9kbA,790
33
+ doppy-0.5.9.dist-info/RECORD,,
@@ -0,0 +1,4 @@
1
+ Wheel-Version: 1.0
2
+ Generator: maturin (1.10.2)
3
+ Root-Is-Purelib: false
4
+ Tag: cp310-abi3-macosx_10_12_x86_64
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ doppy=doppy.__main__:app
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024 Finnish Meteorological Institute
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.