doppy 0.3.1__tar.gz → 0.3.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.

Potentially problematic release.


This version of doppy might be problematic. Click here for more details.

Files changed (43) hide show
  1. {doppy-0.3.1 → doppy-0.3.3}/Cargo.lock +2 -2
  2. {doppy-0.3.1 → doppy-0.3.3}/Cargo.toml +1 -1
  3. {doppy-0.3.1 → doppy-0.3.3}/PKG-INFO +66 -64
  4. doppy-0.3.3/README.md +99 -0
  5. {doppy-0.3.1 → doppy-0.3.3}/src/doppy/netcdf.py +2 -1
  6. {doppy-0.3.1 → doppy-0.3.3}/src/doppy/product/stare.py +83 -0
  7. doppy-0.3.3/src/doppy/product/stare_depol.py +281 -0
  8. {doppy-0.3.1 → doppy-0.3.3}/src/doppy/product/wind.py +69 -0
  9. doppy-0.3.1/README.md +0 -97
  10. doppy-0.3.1/src/doppy/product/stare_depol.py +0 -83
  11. {doppy-0.3.1 → doppy-0.3.3}/LICENSE +0 -0
  12. {doppy-0.3.1 → doppy-0.3.3}/crates/doppy_rs/Cargo.toml +0 -0
  13. {doppy-0.3.1 → doppy-0.3.3}/crates/doppy_rs/src/lib.rs +0 -0
  14. {doppy-0.3.1 → doppy-0.3.3}/crates/doppy_rs/src/raw/halo_hpl.rs +0 -0
  15. {doppy-0.3.1 → doppy-0.3.3}/crates/doppy_rs/src/raw/wls70.rs +0 -0
  16. {doppy-0.3.1 → doppy-0.3.3}/crates/doppy_rs/src/raw.rs +0 -0
  17. {doppy-0.3.1 → doppy-0.3.3}/crates/doprs/.gitignore +0 -0
  18. {doppy-0.3.1 → doppy-0.3.3}/crates/doprs/Cargo.toml +0 -0
  19. {doppy-0.3.1 → doppy-0.3.3}/crates/doprs/src/lib.rs +0 -0
  20. {doppy-0.3.1 → doppy-0.3.3}/crates/doprs/src/raw/error.rs +0 -0
  21. {doppy-0.3.1 → doppy-0.3.3}/crates/doprs/src/raw/halo_hpl.rs +0 -0
  22. {doppy-0.3.1 → doppy-0.3.3}/crates/doprs/src/raw/wls70.rs +0 -0
  23. {doppy-0.3.1 → doppy-0.3.3}/crates/doprs/src/raw.rs +0 -0
  24. {doppy-0.3.1 → doppy-0.3.3}/pyproject.toml +0 -0
  25. {doppy-0.3.1 → doppy-0.3.3}/src/doppy/__init__.py +0 -0
  26. {doppy-0.3.1 → doppy-0.3.3}/src/doppy/__main__.py +0 -0
  27. {doppy-0.3.1 → doppy-0.3.3}/src/doppy/bench.py +0 -0
  28. {doppy-0.3.1 → doppy-0.3.3}/src/doppy/data/__init__.py +0 -0
  29. {doppy-0.3.1 → doppy-0.3.3}/src/doppy/data/api.py +0 -0
  30. {doppy-0.3.1 → doppy-0.3.3}/src/doppy/data/cache.py +0 -0
  31. {doppy-0.3.1 → doppy-0.3.3}/src/doppy/data/exceptions.py +0 -0
  32. {doppy-0.3.1 → doppy-0.3.3}/src/doppy/defaults.py +0 -0
  33. {doppy-0.3.1 → doppy-0.3.3}/src/doppy/exceptions.py +0 -0
  34. {doppy-0.3.1 → doppy-0.3.3}/src/doppy/options.py +0 -0
  35. {doppy-0.3.1 → doppy-0.3.3}/src/doppy/product/__init__.py +0 -0
  36. {doppy-0.3.1 → doppy-0.3.3}/src/doppy/py.typed +0 -0
  37. {doppy-0.3.1 → doppy-0.3.3}/src/doppy/raw/__init__.py +0 -0
  38. {doppy-0.3.1 → doppy-0.3.3}/src/doppy/raw/halo_bg.py +0 -0
  39. {doppy-0.3.1 → doppy-0.3.3}/src/doppy/raw/halo_hpl.py +0 -0
  40. {doppy-0.3.1 → doppy-0.3.3}/src/doppy/raw/halo_sys_params.py +0 -0
  41. {doppy-0.3.1 → doppy-0.3.3}/src/doppy/raw/windcube.py +0 -0
  42. {doppy-0.3.1 → doppy-0.3.3}/src/doppy/raw/wls70.py +0 -0
  43. {doppy-0.3.1 → doppy-0.3.3}/src/doppy/utils.py +0 -0
@@ -106,7 +106,7 @@ checksum = "248e3bacc7dc6baa3b21e405ee045c3047101a49145e7e9eca583ab4c2ca5345"
106
106
 
107
107
  [[package]]
108
108
  name = "doppy_rs"
109
- version = "0.3.1"
109
+ version = "0.3.3"
110
110
  dependencies = [
111
111
  "doprs",
112
112
  "numpy",
@@ -115,7 +115,7 @@ dependencies = [
115
115
 
116
116
  [[package]]
117
117
  name = "doprs"
118
- version = "0.3.1"
118
+ version = "0.3.3"
119
119
  dependencies = [
120
120
  "chrono",
121
121
  "rayon",
@@ -4,6 +4,6 @@ resolver = "2"
4
4
 
5
5
  [workspace.package]
6
6
  edition = "2021"
7
- version = "0.3.1"
7
+ version = "0.3.3"
8
8
  authors = ["Niko Leskinen <niko.leskinen@fmi.fi>"]
9
9
  license-file = "LICENSE"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: doppy
3
- Version: 0.3.1
3
+ Version: 0.3.3
4
4
  Classifier: Development Status :: 4 - Beta
5
5
  Classifier: Programming Language :: Python :: 3
6
6
  Classifier: Programming Language :: Python :: 3.10
@@ -44,8 +44,8 @@ Project-URL: Bug Tracker, https://github.com/actris-cloudnet/doppy/issues
44
44
 
45
45
  ## Products
46
46
 
47
- - [Stare](https://github.com/actris-cloudnet/doppy/blob/main/src/doppy/product/stare.py): [Examples](https://cloudnet.fmi.fi/search/visualizations?experimental=true&product=doppler-lidar&dateFrom=2024-06-05&dateTo=2024-06-05)
48
- - [Wind](https://github.com/actris-cloudnet/doppy/blob/main/src/doppy/product/wind.py): [Examples](https://cloudnet.fmi.fi/search/visualizations?experimental=true&product=doppler-lidar-wind&dateFrom=2024-06-05&dateTo=2024-06-05)
47
+ - 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)
48
+ - 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)
49
49
 
50
50
  ## Instruments
51
51
 
@@ -61,6 +61,8 @@ pip install doppy
61
61
 
62
62
  ## Usage
63
63
 
64
+ ### Stare
65
+
64
66
  ```python
65
67
  import doppy
66
68
 
@@ -70,68 +72,68 @@ stare = doppy.product.Stare.from_halo_data(
70
72
  bg_correction_method=doppy.options.BgCorrectionMethod.FIT,
71
73
  )
72
74
 
75
+ stare.write_to_netcdf(FILENAME)
76
+ ```
77
+
78
+ ### Stare with depolarisation
79
+
80
+ ```python
81
+ import doppy
82
+
83
+ stare_depol = doppy.product.StareDepol.from_halo_data(
84
+ co_data=LIST_OF_STARE_CO_FILE_PATHS,
85
+ co_data_bg=LIST_OF_BACKGROUND_CO_FILE_PATHS,
86
+ cross_data=LIST_OF_STARE_CROSS_FILE_PATHS,
87
+ cross_data_bg=LIST_OF_BACKGROUND_CROSS_FILE_PATHS,
88
+ bg_correction_method=doppy.options.BgCorrectionMethod.FIT,
89
+ polariser_bleed_through=0,
90
+ )
91
+
92
+ stare_depol.write_to_netcdf(FILENAME)
93
+ ```
94
+
95
+ ### Wind
96
+
97
+ ```python
98
+ import doppy
99
+
100
+ wind = doppy.product.Wind.from_halo_data(
101
+ data=LIST_OF_WIND_SCAN_HPL_FILES,
102
+ )
103
+
104
+ # You can also pass instrument azimuth offset in degrees as an option
105
+ wind = doppy.product.Wind.from_halo_data(
106
+ data=LIST_OF_WIND_SCAN_HPL_FILES,
107
+ options=doppy.product.wind.Options(azimuth_offset_deg=30),
108
+ )
109
+
110
+ # For windcube wls200s use
111
+ wind = doppy.product.Wind.from_windcube_data(
112
+ data=LIST_OF_VAD_NETCDF_FILES,
113
+ )
114
+
115
+ # For windcube wls70 use
116
+ wind = doppy.product.Wind.from_wls70_data(
117
+ data=LIST_OF_RTD_FILES,
118
+ )
119
+
120
+ wind.write_to_netcdf(FILENAME)
121
+ ```
122
+
123
+ ### Raw files
124
+
125
+ ```python
126
+ import doppy
127
+
128
+ # Halo
129
+ raws_hpl = doppy.raw.HaloHpl.from_srcs(LIST_OF_HPL_FILES)
130
+ raws_bg = doppy.raw.HaloBg.from_srcs(LIST_OF_BACKGROUND_FILES)
131
+ raw_system_params = doppy.raw.HaloSysParams.from_src(SYSTEM_PARAMS_FILENAME)
73
132
 
74
- (
75
- doppy.netcdf.Dataset(FILENAME)
76
- .add_dimension("time")
77
- .add_dimension("range")
78
- .add_time(
79
- name="time",
80
- dimensions=("time",),
81
- standard_name="time",
82
- long_name="Time UTC",
83
- data=stare.time,
84
- dtype="f8",
85
- )
86
- .add_variable(
87
- name="range",
88
- dimensions=("range",),
89
- units="m",
90
- data=stare.radial_distance,
91
- dtype="f4",
92
- )
93
- .add_variable(
94
- name="elevation",
95
- dimensions=("time",),
96
- units="degrees",
97
- data=stare.elevation,
98
- dtype="f4",
99
- long_name="elevation from horizontal",
100
- )
101
- .add_variable(
102
- name="beta_raw",
103
- dimensions=("time", "range"),
104
- units="sr-1 m-1",
105
- data=stare.beta,
106
- dtype="f4",
107
- )
108
- .add_variable(
109
- name="beta",
110
- dimensions=("time", "range"),
111
- units="sr-1 m-1",
112
- data=stare.beta,
113
- dtype="f4",
114
- mask=stare.mask,
115
- )
116
- .add_variable(
117
- name="v",
118
- dimensions=("time", "range"),
119
- units="m s-1",
120
- long_name="Doppler velocity",
121
- data=stare.radial_velocity,
122
- dtype="f4",
123
- mask=stare.mask,
124
- )
125
- .add_scalar_variable(
126
- name="wavelength",
127
- units="m",
128
- standard_name="radiation_wavelength",
129
- data=stare.wavelength,
130
- dtype="f4",
131
- )
132
- .add_attribute("serial_number", stare.system_id)
133
- .add_attribute("doppy_version", doppy.__version__)
134
- ).close()
133
+ # Windcube WLS200S
134
+ raws_wls200s = doppy.raw.WindCube.from_vad_srcs(LIST_OF_VAD_NETCDF_FILES)
135
135
 
136
+ # Windcube WLS70
137
+ raws_wls70 = doppy.raw.Wls70.from_srcs(LIST_OF_RTD_FILES)
136
138
  ```
137
139
 
doppy-0.3.3/README.md ADDED
@@ -0,0 +1,99 @@
1
+ # Doppy – Doppler wind lidar processing
2
+
3
+ [![CI](https://github.com/actris-cloudnet/doppy/actions/workflows/ci.yml/badge.svg)](https://github.com/actris-cloudnet/doppy/actions/workflows/ci.yml)
4
+ [![PyPI version](https://badge.fury.io/py/doppy.svg)](https://badge.fury.io/py/doppy)
5
+
6
+ ## Products
7
+
8
+ - 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)
9
+ - 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)
10
+
11
+ ## Instruments
12
+
13
+ - HALO Photonics Streamline lidars (stare, wind)
14
+ - Leosphere WindCube WLS200S (wind)
15
+ - Leosphere WindCube WLS70 (wind)
16
+
17
+ ## Install
18
+
19
+ ```sh
20
+ pip install doppy
21
+ ```
22
+
23
+ ## Usage
24
+
25
+ ### Stare
26
+
27
+ ```python
28
+ import doppy
29
+
30
+ stare = doppy.product.Stare.from_halo_data(
31
+ data=LIST_OF_STARE_FILE_PATHS,
32
+ data_bg=LIST_OF_BACKGROUND_FILE_PATHS,
33
+ bg_correction_method=doppy.options.BgCorrectionMethod.FIT,
34
+ )
35
+
36
+ stare.write_to_netcdf(FILENAME)
37
+ ```
38
+
39
+ ### Stare with depolarisation
40
+
41
+ ```python
42
+ import doppy
43
+
44
+ stare_depol = doppy.product.StareDepol.from_halo_data(
45
+ co_data=LIST_OF_STARE_CO_FILE_PATHS,
46
+ co_data_bg=LIST_OF_BACKGROUND_CO_FILE_PATHS,
47
+ cross_data=LIST_OF_STARE_CROSS_FILE_PATHS,
48
+ cross_data_bg=LIST_OF_BACKGROUND_CROSS_FILE_PATHS,
49
+ bg_correction_method=doppy.options.BgCorrectionMethod.FIT,
50
+ polariser_bleed_through=0,
51
+ )
52
+
53
+ stare_depol.write_to_netcdf(FILENAME)
54
+ ```
55
+
56
+ ### Wind
57
+
58
+ ```python
59
+ import doppy
60
+
61
+ wind = doppy.product.Wind.from_halo_data(
62
+ data=LIST_OF_WIND_SCAN_HPL_FILES,
63
+ )
64
+
65
+ # You can also pass instrument azimuth offset in degrees as an option
66
+ wind = doppy.product.Wind.from_halo_data(
67
+ data=LIST_OF_WIND_SCAN_HPL_FILES,
68
+ options=doppy.product.wind.Options(azimuth_offset_deg=30),
69
+ )
70
+
71
+ # For windcube wls200s use
72
+ wind = doppy.product.Wind.from_windcube_data(
73
+ data=LIST_OF_VAD_NETCDF_FILES,
74
+ )
75
+
76
+ # For windcube wls70 use
77
+ wind = doppy.product.Wind.from_wls70_data(
78
+ data=LIST_OF_RTD_FILES,
79
+ )
80
+
81
+ wind.write_to_netcdf(FILENAME)
82
+ ```
83
+
84
+ ### Raw files
85
+
86
+ ```python
87
+ import doppy
88
+
89
+ # Halo
90
+ raws_hpl = doppy.raw.HaloHpl.from_srcs(LIST_OF_HPL_FILES)
91
+ raws_bg = doppy.raw.HaloBg.from_srcs(LIST_OF_BACKGROUND_FILES)
92
+ raw_system_params = doppy.raw.HaloSysParams.from_src(SYSTEM_PARAMS_FILENAME)
93
+
94
+ # Windcube WLS200S
95
+ raws_wls200s = doppy.raw.WindCube.from_vad_srcs(LIST_OF_VAD_NETCDF_FILES)
96
+
97
+ # Windcube WLS70
98
+ raws_wls70 = doppy.raw.Wls70.from_srcs(LIST_OF_RTD_FILES)
99
+ ```
@@ -1,5 +1,6 @@
1
1
  from __future__ import annotations
2
2
 
3
+ import pathlib
3
4
  import warnings
4
5
  from types import TracebackType
5
6
  from typing import Literal, TypeAlias
@@ -12,7 +13,7 @@ NetCDFDataType: TypeAlias = Literal["f4", "f8", "i4", "i8", "u4", "u8"]
12
13
 
13
14
 
14
15
  class Dataset:
15
- def __init__(self, filename: str) -> None:
16
+ def __init__(self, filename: str | pathlib.Path) -> None:
16
17
  self.nc = netCDF4.Dataset(filename, mode="w")
17
18
 
18
19
  def __enter__(self) -> Dataset:
@@ -29,6 +29,28 @@ class Stare:
29
29
  wavelength: float
30
30
  system_id: str
31
31
 
32
+ def __getitem__(
33
+ self,
34
+ index: int
35
+ | slice
36
+ | list[int]
37
+ | npt.NDArray[np.int64]
38
+ | npt.NDArray[np.bool_]
39
+ | tuple[slice, slice],
40
+ ) -> Stare:
41
+ if isinstance(index, (int, slice, list, np.ndarray)):
42
+ return Stare(
43
+ time=self.time[index],
44
+ radial_distance=self.radial_distance,
45
+ elevation=self.elevation[index],
46
+ beta=self.beta[index],
47
+ radial_velocity=self.radial_velocity[index],
48
+ mask=self.mask[index],
49
+ wavelength=self.wavelength,
50
+ system_id=self.system_id,
51
+ )
52
+ raise TypeError
53
+
32
54
  @classmethod
33
55
  def from_halo_data(
34
56
  cls,
@@ -93,6 +115,67 @@ class Stare:
93
115
  system_id=raw.header.system_id,
94
116
  )
95
117
 
118
+ def write_to_netcdf(self, filename: str | Path) -> None:
119
+ with doppy.netcdf.Dataset(filename) as nc:
120
+ nc.add_dimension("time")
121
+ nc.add_dimension("range")
122
+ nc.add_time(
123
+ name="time",
124
+ dimensions=("time",),
125
+ standard_name="time",
126
+ long_name="Time UTC",
127
+ data=self.time,
128
+ dtype="f8",
129
+ )
130
+ nc.add_variable(
131
+ name="range",
132
+ dimensions=("range",),
133
+ units="m",
134
+ data=self.radial_distance,
135
+ dtype="f4",
136
+ )
137
+ nc.add_variable(
138
+ name="elevation",
139
+ dimensions=("time",),
140
+ units="degrees",
141
+ data=self.elevation,
142
+ dtype="f4",
143
+ long_name="elevation from horizontal",
144
+ )
145
+ nc.add_variable(
146
+ name="beta_raw",
147
+ dimensions=("time", "range"),
148
+ units="sr-1 m-1",
149
+ data=self.beta,
150
+ dtype="f4",
151
+ )
152
+ nc.add_variable(
153
+ name="beta",
154
+ dimensions=("time", "range"),
155
+ units="sr-1 m-1",
156
+ data=self.beta,
157
+ dtype="f4",
158
+ mask=self.mask,
159
+ )
160
+ nc.add_variable(
161
+ name="v",
162
+ dimensions=("time", "range"),
163
+ units="m s-1",
164
+ long_name="Doppler velocity",
165
+ data=self.radial_velocity,
166
+ dtype="f4",
167
+ mask=self.mask,
168
+ )
169
+ nc.add_scalar_variable(
170
+ name="wavelength",
171
+ units="m",
172
+ standard_name="radiation_wavelength",
173
+ data=self.wavelength,
174
+ dtype="f4",
175
+ )
176
+ nc.add_attribute("serial_number", self.system_id)
177
+ nc.add_attribute("doppy_version", doppy.__version__)
178
+
96
179
 
97
180
  def _compute_noise_mask(
98
181
  intensity: npt.NDArray[np.float64],
@@ -0,0 +1,281 @@
1
+ from __future__ import annotations
2
+
3
+ from dataclasses import dataclass
4
+ from io import BufferedIOBase
5
+ from pathlib import Path
6
+ from typing import Sequence
7
+
8
+ import numpy as np
9
+ import numpy.typing as npt
10
+
11
+ import doppy
12
+ from doppy import options
13
+ from doppy.product.stare import Stare
14
+
15
+
16
+ @dataclass
17
+ class StareDepol:
18
+ """
19
+ Stare product with depolarisation ratio derived from co-polarised and
20
+ cross-polarised stare data.
21
+
22
+ Attributes:
23
+ -----------
24
+ time
25
+ An array of datetime64 objects representing the observation times.
26
+ radial_distance
27
+ An array of radial distances from the observation point, in meters.
28
+ elevation
29
+ An array of elevation angles corresponding to the observation points, in
30
+ degrees.
31
+ beta
32
+ An array of backscatter coefficients for the co-polarised signal, in
33
+ sr-1 m-1.
34
+ beta_cross
35
+ An array of backscatter coefficients for the cross-polarised signal, in
36
+ sr-1 m-1.
37
+ radial_velocity
38
+ An array of radial velocities of the co-polarised signal, in m s-1.
39
+ mask
40
+ A boolean array indicating signal (True) or noise (False) data points.
41
+ depolarisation
42
+ An array of depolarisation ratios calculated as the ratio of
43
+ co-polarised to cross-polarised backscatter coefficients.
44
+ wavelength
45
+ The wavelength of the lidar, in meters.
46
+ system_id
47
+ A string identifier for the lidar.
48
+
49
+
50
+ Raises
51
+ ------
52
+ ValueError
53
+ If the input `co` and `cross` products have mismatched wavelengths,
54
+ system IDs, radial distances, or elevation angles, this exception is
55
+ raised.
56
+
57
+
58
+ References
59
+ ----------
60
+ Aerosol particle depolarization ratio at 1565 nm measured with a Halo Doppler lidar
61
+ authors: Ville Vakkari, Holger Baars, Stephanie Bohlmann, Johannes Bühl,
62
+ Mika Komppula, Rodanthi-Elisavet Mamouri, and Ewan James O'Connor
63
+ doi: https://doi.org/10.5194/acp-21-5807-2021
64
+ """
65
+
66
+ time: npt.NDArray[np.datetime64]
67
+ radial_distance: npt.NDArray[np.float64]
68
+ elevation: npt.NDArray[np.float64]
69
+ beta: npt.NDArray[np.float64]
70
+ beta_cross: npt.NDArray[np.float64]
71
+ radial_velocity: npt.NDArray[np.float64]
72
+ mask: npt.NDArray[np.bool_]
73
+ depolarisation: npt.NDArray[np.float64]
74
+ mask_depolarisation: npt.NDArray[np.bool_]
75
+ mask_beta_cross: npt.NDArray[np.bool_]
76
+ polariser_bleed_through: float
77
+ wavelength: float
78
+ system_id: str
79
+
80
+ def __init__(
81
+ self,
82
+ co: Stare,
83
+ cross: Stare,
84
+ polariser_bleed_through: float = 0.0,
85
+ ):
86
+ """
87
+ Parameters
88
+ ----------
89
+ co: Stare
90
+ The co-polarised data.
91
+ cross: Stare
92
+ The cross-polarised data. The `cross.time` array is expected to be sorted.
93
+ polariser_bleed_through: float, default=0.0
94
+ The amount of bleed-through from the polariser.
95
+ """
96
+
97
+ if not np.isclose(co.wavelength, cross.wavelength):
98
+ raise ValueError(
99
+ "Different wavelength in co and cross: "
100
+ f"{co.wavelength} vs {cross.wavelength}"
101
+ )
102
+ if co.system_id != cross.system_id:
103
+ raise ValueError(
104
+ "Different system ID in co and cross: "
105
+ f"{co.system_id} vs {cross.system_id}"
106
+ )
107
+ if not np.allclose(co.radial_distance, cross.radial_distance, atol=1):
108
+ raise ValueError("Different radial distance in co and cross")
109
+
110
+ if co.beta.shape[1] != cross.beta.shape[1]:
111
+ raise ValueError(
112
+ "Range dimension mismatch in co and cross: "
113
+ f"{co.beta.shape[1]} vs {cross.beta.shape[1]}"
114
+ )
115
+
116
+ ind = np.searchsorted(cross.time, co.time, side="left")
117
+ pick_ind = ind < len(cross.time)
118
+ time_diff_threshold = 2 * np.median(np.diff(co.time))
119
+ co_cross_timediff_below_threshold = (
120
+ cross.time[ind[pick_ind]] - co.time[pick_ind] < time_diff_threshold
121
+ )
122
+ pick_ind[pick_ind] &= co_cross_timediff_below_threshold
123
+
124
+ if not np.allclose(
125
+ co.elevation[pick_ind], cross.elevation[ind[pick_ind]], atol=1
126
+ ):
127
+ raise ValueError("Different elevation in co and cross")
128
+
129
+ depolarisation = np.full_like(co.beta, np.nan)
130
+ co_beta = co.beta[pick_ind]
131
+ depolarisation[pick_ind] = (
132
+ cross.beta[ind[pick_ind]] - polariser_bleed_through * co_beta
133
+ ) / co_beta
134
+ cross_beta = np.full_like(co.beta, np.nan)
135
+ cross_beta[pick_ind] = cross.beta[ind[pick_ind]]
136
+
137
+ self.time = co.time
138
+ self.radial_distance = co.radial_distance
139
+ self.elevation = co.elevation
140
+ self.beta = co.beta
141
+ self.beta_cross = cross_beta
142
+ self.radial_velocity = co.radial_velocity
143
+ self.mask = co.mask
144
+ self.depolarisation = depolarisation
145
+ self.mask_depolarisation = np.isnan(depolarisation)
146
+ self.mask_beta_cross = np.isnan(self.beta_cross)
147
+ self.polariser_bleed_through = polariser_bleed_through
148
+ self.wavelength = co.wavelength
149
+ self.system_id = co.system_id
150
+
151
+ @classmethod
152
+ def from_halo_data(
153
+ cls,
154
+ co_data: Sequence[str]
155
+ | Sequence[Path]
156
+ | Sequence[bytes]
157
+ | Sequence[BufferedIOBase],
158
+ co_data_bg: Sequence[str]
159
+ | Sequence[Path]
160
+ | Sequence[tuple[bytes, str]]
161
+ | Sequence[tuple[BufferedIOBase, str]],
162
+ cross_data: Sequence[str]
163
+ | Sequence[Path]
164
+ | Sequence[bytes]
165
+ | Sequence[BufferedIOBase],
166
+ cross_data_bg: Sequence[str]
167
+ | Sequence[Path]
168
+ | Sequence[tuple[bytes, str]]
169
+ | Sequence[tuple[BufferedIOBase, str]],
170
+ bg_correction_method: options.BgCorrectionMethod,
171
+ polariser_bleed_through: float = 0,
172
+ ) -> StareDepol:
173
+ co = Stare.from_halo_data(
174
+ data=co_data, data_bg=co_data_bg, bg_correction_method=bg_correction_method
175
+ )
176
+ cross = Stare.from_halo_data(
177
+ data=cross_data,
178
+ data_bg=cross_data_bg,
179
+ bg_correction_method=bg_correction_method,
180
+ )
181
+ return cls(co, cross, polariser_bleed_through)
182
+
183
+ def write_to_netcdf(self, filename: str | Path) -> None:
184
+ with doppy.netcdf.Dataset(filename) as nc:
185
+ nc.add_dimension("time")
186
+ nc.add_dimension("range")
187
+ nc.add_time(
188
+ name="time",
189
+ dimensions=("time",),
190
+ standard_name="time",
191
+ long_name="Time UTC",
192
+ data=self.time,
193
+ dtype="f8",
194
+ )
195
+ nc.add_variable(
196
+ name="range",
197
+ dimensions=("range",),
198
+ units="m",
199
+ data=self.radial_distance,
200
+ dtype="f4",
201
+ )
202
+ nc.add_variable(
203
+ name="elevation",
204
+ dimensions=("time",),
205
+ units="degrees",
206
+ data=self.elevation,
207
+ dtype="f4",
208
+ long_name="elevation from horizontal",
209
+ )
210
+ nc.add_variable(
211
+ name="beta_raw",
212
+ dimensions=("time", "range"),
213
+ units="sr-1 m-1",
214
+ data=self.beta,
215
+ dtype="f4",
216
+ )
217
+ nc.add_variable(
218
+ name="beta",
219
+ dimensions=("time", "range"),
220
+ units="sr-1 m-1",
221
+ data=self.beta,
222
+ dtype="f4",
223
+ mask=self.mask,
224
+ )
225
+ nc.add_variable(
226
+ name="v",
227
+ dimensions=("time", "range"),
228
+ units="m s-1",
229
+ long_name="Doppler velocity",
230
+ data=self.radial_velocity,
231
+ dtype="f4",
232
+ mask=self.mask,
233
+ )
234
+ nc.add_scalar_variable(
235
+ name="wavelength",
236
+ units="m",
237
+ standard_name="radiation_wavelength",
238
+ data=self.wavelength,
239
+ dtype="f4",
240
+ )
241
+ nc.add_variable(
242
+ name="depolarisation_raw",
243
+ dimensions=("time", "range"),
244
+ units="1",
245
+ data=self.depolarisation,
246
+ dtype="f4",
247
+ mask=self.mask_depolarisation,
248
+ )
249
+ nc.add_variable(
250
+ name="depolarisation",
251
+ dimensions=("time", "range"),
252
+ units="1",
253
+ data=self.depolarisation,
254
+ dtype="f4",
255
+ mask=self.mask | self.mask_depolarisation,
256
+ )
257
+ nc.add_variable(
258
+ name="beta_cross_raw",
259
+ dimensions=("time", "range"),
260
+ units="sr-1 m-1",
261
+ data=self.beta_cross,
262
+ mask=self.mask_beta_cross,
263
+ dtype="f4",
264
+ )
265
+ nc.add_variable(
266
+ name="beta_cross",
267
+ dimensions=("time", "range"),
268
+ units="sr-1 m-1",
269
+ data=self.beta_cross,
270
+ mask=self.mask | self.mask_beta_cross,
271
+ dtype="f4",
272
+ )
273
+ nc.add_scalar_variable(
274
+ name="polariser_bleed_through",
275
+ units="1",
276
+ long_name="Polariser bleed-through",
277
+ data=self.polariser_bleed_through,
278
+ dtype="f4",
279
+ )
280
+ nc.add_attribute("serial_number", self.system_id)
281
+ nc.add_attribute("doppy_version", doppy.__version__)
@@ -32,6 +32,7 @@ class Wind:
32
32
  vertical_wind: npt.NDArray[np.float64]
33
33
  mask: npt.NDArray[np.bool_]
34
34
  system_id: str
35
+ options: Options | None
35
36
 
36
37
  @functools.cached_property
37
38
  def horizontal_wind_speed(self) -> npt.NDArray[np.float64]:
@@ -104,6 +105,7 @@ class Wind:
104
105
  vertical_wind=wind[:, :, 2],
105
106
  mask=mask,
106
107
  system_id=raw.header.system_id,
108
+ options=options,
107
109
  )
108
110
 
109
111
  @classmethod
@@ -163,6 +165,7 @@ class Wind:
163
165
  vertical_wind=wind[:, :, 2],
164
166
  mask=mask,
165
167
  system_id=raw.system_id,
168
+ options=options,
166
169
  )
167
170
 
168
171
  @classmethod
@@ -211,8 +214,74 @@ class Wind:
211
214
  vertical_wind=raw.vertical_wind,
212
215
  mask=mask,
213
216
  system_id=raw.system_id,
217
+ options=options,
214
218
  )
215
219
 
220
+ def write_to_netcdf(self, filename: str | Path) -> None:
221
+ with doppy.netcdf.Dataset(filename) as nc:
222
+ nc.add_dimension("time")
223
+ nc.add_dimension("height")
224
+ nc.add_time(
225
+ name="time",
226
+ dimensions=("time",),
227
+ standard_name="time",
228
+ long_name="Time UTC",
229
+ data=self.time,
230
+ dtype="f8",
231
+ )
232
+ nc.add_variable(
233
+ name="height",
234
+ dimensions=("height",),
235
+ units="m",
236
+ data=self.height,
237
+ dtype="f4",
238
+ )
239
+ nc.add_variable(
240
+ name="uwind_raw",
241
+ dimensions=("time", "height"),
242
+ units="m s-1",
243
+ data=self.zonal_wind,
244
+ dtype="f4",
245
+ long_name="Non-screened zonal wind",
246
+ )
247
+ nc.add_variable(
248
+ name="uwind",
249
+ dimensions=("time", "height"),
250
+ units="m s-1",
251
+ data=self.zonal_wind,
252
+ mask=self.mask,
253
+ dtype="f4",
254
+ long_name="Zonal wind",
255
+ )
256
+ nc.add_variable(
257
+ name="vwind_raw",
258
+ dimensions=("time", "height"),
259
+ units="m s-1",
260
+ data=self.meridional_wind,
261
+ dtype="f4",
262
+ long_name="Non-screened meridional wind",
263
+ )
264
+ nc.add_variable(
265
+ name="vwind",
266
+ dimensions=("time", "height"),
267
+ units="m s-1",
268
+ data=self.meridional_wind,
269
+ mask=self.mask,
270
+ dtype="f4",
271
+ long_name="Meridional wind",
272
+ )
273
+ nc.add_attribute("serial_number", self.system_id)
274
+ nc.add_attribute("doppy_version", doppy.__version__)
275
+ if self.options is not None and self.options.azimuth_offset_deg is not None:
276
+ nc.add_scalar_variable(
277
+ name="azimuth_offset",
278
+ units="degrees",
279
+ data=self.options.azimuth_offset_deg,
280
+ dtype="f4",
281
+ long_name="Azimuth offset of the instrument "
282
+ "(positive clockwise from north)",
283
+ )
284
+
216
285
 
217
286
  def _compute_wind(
218
287
  raw: doppy.raw.HaloHpl | doppy.raw.WindCube,
doppy-0.3.1/README.md DELETED
@@ -1,97 +0,0 @@
1
- # Doppy – Doppler wind lidar processing
2
-
3
- [![CI](https://github.com/actris-cloudnet/doppy/actions/workflows/ci.yml/badge.svg)](https://github.com/actris-cloudnet/doppy/actions/workflows/ci.yml)
4
- [![PyPI version](https://badge.fury.io/py/doppy.svg)](https://badge.fury.io/py/doppy)
5
-
6
- ## Products
7
-
8
- - [Stare](https://github.com/actris-cloudnet/doppy/blob/main/src/doppy/product/stare.py): [Examples](https://cloudnet.fmi.fi/search/visualizations?experimental=true&product=doppler-lidar&dateFrom=2024-06-05&dateTo=2024-06-05)
9
- - [Wind](https://github.com/actris-cloudnet/doppy/blob/main/src/doppy/product/wind.py): [Examples](https://cloudnet.fmi.fi/search/visualizations?experimental=true&product=doppler-lidar-wind&dateFrom=2024-06-05&dateTo=2024-06-05)
10
-
11
- ## Instruments
12
-
13
- - HALO Photonics Streamline lidars (stare, wind)
14
- - Leosphere WindCube WLS200S (wind)
15
- - Leosphere WindCube WLS70 (wind)
16
-
17
- ## Install
18
-
19
- ```sh
20
- pip install doppy
21
- ```
22
-
23
- ## Usage
24
-
25
- ```python
26
- import doppy
27
-
28
- stare = doppy.product.Stare.from_halo_data(
29
- data=LIST_OF_STARE_FILE_PATHS,
30
- data_bg=LIST_OF_BACKGROUND_FILE_PATHS,
31
- bg_correction_method=doppy.options.BgCorrectionMethod.FIT,
32
- )
33
-
34
-
35
- (
36
- doppy.netcdf.Dataset(FILENAME)
37
- .add_dimension("time")
38
- .add_dimension("range")
39
- .add_time(
40
- name="time",
41
- dimensions=("time",),
42
- standard_name="time",
43
- long_name="Time UTC",
44
- data=stare.time,
45
- dtype="f8",
46
- )
47
- .add_variable(
48
- name="range",
49
- dimensions=("range",),
50
- units="m",
51
- data=stare.radial_distance,
52
- dtype="f4",
53
- )
54
- .add_variable(
55
- name="elevation",
56
- dimensions=("time",),
57
- units="degrees",
58
- data=stare.elevation,
59
- dtype="f4",
60
- long_name="elevation from horizontal",
61
- )
62
- .add_variable(
63
- name="beta_raw",
64
- dimensions=("time", "range"),
65
- units="sr-1 m-1",
66
- data=stare.beta,
67
- dtype="f4",
68
- )
69
- .add_variable(
70
- name="beta",
71
- dimensions=("time", "range"),
72
- units="sr-1 m-1",
73
- data=stare.beta,
74
- dtype="f4",
75
- mask=stare.mask,
76
- )
77
- .add_variable(
78
- name="v",
79
- dimensions=("time", "range"),
80
- units="m s-1",
81
- long_name="Doppler velocity",
82
- data=stare.radial_velocity,
83
- dtype="f4",
84
- mask=stare.mask,
85
- )
86
- .add_scalar_variable(
87
- name="wavelength",
88
- units="m",
89
- standard_name="radiation_wavelength",
90
- data=stare.wavelength,
91
- dtype="f4",
92
- )
93
- .add_attribute("serial_number", stare.system_id)
94
- .add_attribute("doppy_version", doppy.__version__)
95
- ).close()
96
-
97
- ```
@@ -1,83 +0,0 @@
1
- import numpy as np
2
- import numpy.typing as npt
3
-
4
- from doppy.product.stare import Stare
5
-
6
-
7
- class StareDepol:
8
- """
9
- Stare product with depolarisation ratio derived from co-polarised and
10
- cross-polarised stare data.
11
-
12
- Attributes:
13
- -----------
14
- time
15
- An array of datetime64 objects representing the observation times.
16
- radial_distance
17
- An array of radial distances from the observation point, in meters.
18
- elevation
19
- An array of elevation angles corresponding to the observation points, in
20
- degrees.
21
- beta
22
- An array of backscatter coefficients for the co-polarised signal, in
23
- sr-1 m-1.
24
- radial_velocity
25
- An array of radial velocities of the co-polarised signal, in m s-1.
26
- mask
27
- A boolean array indicating signal (True) or noise (False) data points.
28
- depolarisation
29
- An array of depolarisation ratios calculated as the ratio of
30
- co-polarised to cross-polarised backscatter coefficients.
31
- wavelength
32
- The wavelength of the lidar, in meters.
33
- system_id
34
- A string identifier for the lidar.
35
-
36
- Raises
37
- ------
38
- ValueError
39
- If the input `co` and `cross` products have mismatched wavelengths,
40
- system IDs, radial distances, or elevation angles, this exception is
41
- raised.
42
- """
43
-
44
- time: npt.NDArray[np.datetime64]
45
- radial_distance: npt.NDArray[np.float64]
46
- elevation: npt.NDArray[np.float64]
47
- beta: npt.NDArray[np.float64]
48
- radial_velocity: npt.NDArray[np.float64]
49
- mask: npt.NDArray[np.bool_]
50
- depolarisation: npt.NDArray[np.float64]
51
- wavelength: float
52
- system_id: str
53
-
54
- def __init__(self, co: Stare, cross: Stare):
55
- if co.wavelength != cross.wavelength:
56
- raise ValueError(
57
- "Different wavelength in co and cross: "
58
- f"{co.wavelength} vs {cross.wavelength}"
59
- )
60
- if co.system_id != cross.system_id:
61
- raise ValueError(
62
- "Different system ID in co and cross: "
63
- f"{co.system_id} vs {cross.system_id}"
64
- )
65
- if not np.allclose(co.radial_distance, cross.radial_distance, atol=1):
66
- raise ValueError("Different radial distance in co and cross")
67
-
68
- time_ind = np.argmin(np.abs(co.time - cross.time[:, np.newaxis]), axis=0)
69
- cross_elevation = cross.elevation[time_ind]
70
- cross_beta = cross.beta[time_ind, :]
71
-
72
- if not np.allclose(co.elevation, cross_elevation, atol=1):
73
- raise ValueError("Different elevation in co and cross")
74
-
75
- self.time = co.time
76
- self.radial_distance = co.radial_distance
77
- self.elevation = co.elevation
78
- self.beta = co.beta
79
- self.radial_velocity = co.radial_velocity
80
- self.mask = co.mask
81
- self.depolarisation = cross_beta / co.beta
82
- self.wavelength = co.wavelength
83
- self.system_id = co.system_id
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes