cloudnetpy 1.70.2__py3-none-any.whl → 1.71.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.
- cloudnetpy/plotting/plot_meta.py +5 -0
- cloudnetpy/products/epsilon.py +202 -0
- cloudnetpy/version.py +2 -2
- {cloudnetpy-1.70.2.dist-info → cloudnetpy-1.71.1.dist-info}/METADATA +2 -1
- {cloudnetpy-1.70.2.dist-info → cloudnetpy-1.71.1.dist-info}/RECORD +9 -8
- {cloudnetpy-1.70.2.dist-info → cloudnetpy-1.71.1.dist-info}/LICENSE +0 -0
- {cloudnetpy-1.70.2.dist-info → cloudnetpy-1.71.1.dist-info}/WHEEL +0 -0
- {cloudnetpy-1.70.2.dist-info → cloudnetpy-1.71.1.dist-info}/entry_points.txt +0 -0
- {cloudnetpy-1.70.2.dist-info → cloudnetpy-1.71.1.dist-info}/top_level.txt +0 -0
cloudnetpy/plotting/plot_meta.py
CHANGED
@@ -0,0 +1,202 @@
|
|
1
|
+
from os import PathLike
|
2
|
+
from pathlib import Path
|
3
|
+
|
4
|
+
import doppy
|
5
|
+
import doppy.netcdf
|
6
|
+
import netCDF4
|
7
|
+
import numpy as np
|
8
|
+
import numpy.typing as npt
|
9
|
+
import scipy.constants
|
10
|
+
from doppy.product.turbulence import HorizontalWind, Options, Turbulence, VerticalWind
|
11
|
+
from scipy.interpolate import LinearNDInterpolator, NearestNDInterpolator
|
12
|
+
|
13
|
+
import cloudnetpy
|
14
|
+
from cloudnetpy.output import copy_variables
|
15
|
+
from cloudnetpy.utils import get_time, get_uuid
|
16
|
+
|
17
|
+
|
18
|
+
def generate_epsilon_from_lidar(
|
19
|
+
doppler_lidar_file: str | PathLike,
|
20
|
+
doppler_lidar_wind_file: str | PathLike,
|
21
|
+
output_file: str | PathLike,
|
22
|
+
uuid: str | None,
|
23
|
+
):
|
24
|
+
sliding_window_in_seconds = 3 * 60
|
25
|
+
uuid = uuid if uuid is not None else get_uuid()
|
26
|
+
opts = _get_options(doppler_lidar_file)
|
27
|
+
opts.period = sliding_window_in_seconds
|
28
|
+
vert = _vertical_wind_from_doppler_lidar_file(doppler_lidar_file)
|
29
|
+
hori = _horizontal_wind_from_doppler_lidar_file(doppler_lidar_wind_file)
|
30
|
+
turb = Turbulence.from_winds(vert, hori, opts)
|
31
|
+
|
32
|
+
with (
|
33
|
+
netCDF4.Dataset(Path(doppler_lidar_file), "r") as nc_src,
|
34
|
+
doppy.netcdf.Dataset(Path(output_file), format="NETCDF4_CLASSIC") as nc,
|
35
|
+
):
|
36
|
+
nc.add_dimension("time")
|
37
|
+
nc.add_dimension("height", size=len(turb.height))
|
38
|
+
nc.add_time(
|
39
|
+
name="time",
|
40
|
+
dimensions=("time",),
|
41
|
+
standard_name="time",
|
42
|
+
long_name="Time UTC",
|
43
|
+
data=turb.time,
|
44
|
+
dtype="f8",
|
45
|
+
)
|
46
|
+
nc.add_variable(
|
47
|
+
name="height",
|
48
|
+
dimensions=("height",),
|
49
|
+
units="m",
|
50
|
+
data=turb.height,
|
51
|
+
standard_name=nc_src["height"].standard_name,
|
52
|
+
long_name=nc_src["height"].long_name,
|
53
|
+
dtype="f4",
|
54
|
+
)
|
55
|
+
nc.add_variable(
|
56
|
+
name="epsilon",
|
57
|
+
dimensions=("time", "height"),
|
58
|
+
units="m2 s-3",
|
59
|
+
data=turb.turbulent_kinetic_energy_dissipation_rate,
|
60
|
+
mask=turb.mask,
|
61
|
+
dtype="f4",
|
62
|
+
long_name="Dissipation rate of turbulent kinetic energy",
|
63
|
+
)
|
64
|
+
nc.add_scalar_variable(
|
65
|
+
name="ray_accumulation_time",
|
66
|
+
units="s",
|
67
|
+
long_name="Ray accumulation time",
|
68
|
+
data=opts.ray_accumulation_time,
|
69
|
+
dtype="f4",
|
70
|
+
)
|
71
|
+
nc.add_scalar_variable(
|
72
|
+
name="rolling_window_period",
|
73
|
+
units="s",
|
74
|
+
long_name="Rolling window period",
|
75
|
+
data=opts.period,
|
76
|
+
dtype="f4",
|
77
|
+
)
|
78
|
+
|
79
|
+
nc.add_attribute("file_uuid", uuid)
|
80
|
+
nc.add_attribute("cloudnet_file_type", "epsilon-lidar")
|
81
|
+
nc.add_attribute("doppy_version", doppy.__version__)
|
82
|
+
nc.add_attribute("cloudnetpy_version", cloudnetpy.__version__)
|
83
|
+
nc.add_attribute(
|
84
|
+
"title",
|
85
|
+
"Dissipation rate of turbulent kinetic energy (lidar) "
|
86
|
+
f"from {nc_src.location}",
|
87
|
+
)
|
88
|
+
|
89
|
+
copy_attributes_from_src(doppler_lidar_file, output_file)
|
90
|
+
|
91
|
+
with (
|
92
|
+
netCDF4.Dataset(output_file, "r+") as nc_out,
|
93
|
+
netCDF4.Dataset(doppler_lidar_file, "r") as nc_src_stare,
|
94
|
+
netCDF4.Dataset(doppler_lidar_wind_file, "r") as nc_src_wind,
|
95
|
+
):
|
96
|
+
copy_variables(
|
97
|
+
nc_src_stare, nc_out, ("latitude", "longitude", "altitude", "source")
|
98
|
+
)
|
99
|
+
nc_out.source_file_uuids = f"{nc_src_stare.file_uuid}, {nc_src_wind.file_uuid}"
|
100
|
+
sources = {nc_src_stare.source, nc_src_wind.source}
|
101
|
+
nc_out.source = ", ".join(sources)
|
102
|
+
history = (
|
103
|
+
f"{get_time()} - epsilon-lidar file created using doppy "
|
104
|
+
f"v{doppy.__version__} and cloudnetpy v{cloudnetpy.__version__}\n"
|
105
|
+
f"{nc_src_stare.history}\n"
|
106
|
+
f"{nc_src_wind.history}"
|
107
|
+
)
|
108
|
+
history = "\n".join(
|
109
|
+
line.strip() for line in history.splitlines() if line.strip()
|
110
|
+
)
|
111
|
+
nc_out.history = history
|
112
|
+
nc_out.references = "https://doi.org/10.1175/2010JTECHA1455.1"
|
113
|
+
return uuid
|
114
|
+
|
115
|
+
|
116
|
+
def copy_attributes_from_src(src: str | PathLike, trg: str | PathLike) -> None:
|
117
|
+
with netCDF4.Dataset(src, "r") as nc_src, netCDF4.Dataset(trg, "a") as nc_trg:
|
118
|
+
for attr in ("year", "month", "day", "location", "Conventions"):
|
119
|
+
nc_trg.setncattr(attr, nc_src.getncattr(attr))
|
120
|
+
|
121
|
+
|
122
|
+
def _horizontal_wind_from_doppler_lidar_file(
|
123
|
+
doppler_lidar_wind_file: str | PathLike,
|
124
|
+
) -> HorizontalWind:
|
125
|
+
with netCDF4.Dataset(doppler_lidar_wind_file, "r") as nc:
|
126
|
+
time = _datetime64_from_nc_var(nc["time"])
|
127
|
+
height = np.array(nc["height"][:].data, dtype=np.float64)
|
128
|
+
uwind = np.array(nc["uwind"][:].data, dtype=np.float64)
|
129
|
+
vwind = np.array(nc["vwind"][:].data, dtype=np.float64)
|
130
|
+
umask = np.array(nc["uwind"][:].mask, dtype=np.bool_)
|
131
|
+
vmask = np.array(nc["vwind"][:].mask, dtype=np.bool_)
|
132
|
+
V = np.sqrt(uwind**2 + vwind**2)
|
133
|
+
mask = umask | vmask
|
134
|
+
t = np.broadcast_to(time[:, None], mask.shape)[~mask]
|
135
|
+
h = np.broadcast_to(height[None, :], mask.shape)[~mask]
|
136
|
+
interp_linear = LinearNDInterpolator(list(zip(t, h, strict=False)), V[~mask])
|
137
|
+
interp_nearest = NearestNDInterpolator(list(zip(t, h, strict=False)), V[~mask])
|
138
|
+
T, H = np.meshgrid(time, height, indexing="ij")
|
139
|
+
V_linear = interp_linear(T, H)
|
140
|
+
V_nearest = interp_nearest(T, H)
|
141
|
+
isnan = np.isnan(V_linear)
|
142
|
+
V_interp = V_linear
|
143
|
+
V_interp[isnan] = V_nearest[isnan]
|
144
|
+
if np.isnan(V_interp).any():
|
145
|
+
msg = "Unexpected nans"
|
146
|
+
raise ValueError(msg)
|
147
|
+
return HorizontalWind(time=time, height=height, V=V_interp)
|
148
|
+
|
149
|
+
|
150
|
+
def _get_options(doppler_lidar_file: str | PathLike) -> Options:
|
151
|
+
with netCDF4.Dataset(doppler_lidar_file, "r") as nc:
|
152
|
+
if "ray_accumulation_time" in nc.variables:
|
153
|
+
return Options(ray_accumulation_time=nc["ray_accumulation_time"][:])
|
154
|
+
if "pulses_per_ray" in nc.variables:
|
155
|
+
prf = _infer_pulse_repetition_frequency(
|
156
|
+
np.array(nc["range"][:].data, dtype=np.float64)
|
157
|
+
)
|
158
|
+
return Options(ray_accumulation_time=float(nc["pulses_per_ray"][:] / prf))
|
159
|
+
msg = "Missing ray info"
|
160
|
+
raise ValueError(msg)
|
161
|
+
|
162
|
+
|
163
|
+
def _infer_pulse_repetition_frequency(range_: npt.NDArray[np.float64]):
|
164
|
+
c = scipy.constants.c
|
165
|
+
dist = range_.max() - range_.min()
|
166
|
+
round_trip_time = 2 * dist / c
|
167
|
+
|
168
|
+
T_LOW = 1 / 10_000 # Halo XR instruments operate on lower frequency
|
169
|
+
T_HIGH = 1 / 15_000 # Rest should operate on higher frequency
|
170
|
+
if round_trip_time / T_HIGH < 1:
|
171
|
+
return 15e3
|
172
|
+
if round_trip_time / T_LOW < 1:
|
173
|
+
return 10e3
|
174
|
+
msg = f"Suspiciously large range ({dist}m). " "Cannot infer pulse repetition rate"
|
175
|
+
raise ValueError(msg)
|
176
|
+
|
177
|
+
|
178
|
+
def _vertical_wind_from_doppler_lidar_file(
|
179
|
+
doppler_lidar_file: str | PathLike,
|
180
|
+
) -> VerticalWind:
|
181
|
+
with netCDF4.Dataset(doppler_lidar_file, "r") as nc:
|
182
|
+
time = _datetime64_from_nc_var(nc["time"])
|
183
|
+
height = np.array(nc["height"][:].data, dtype=np.float64)
|
184
|
+
w = np.array(nc["v"][:].data, dtype=np.float64)
|
185
|
+
mask = np.array(nc["v"][:].mask, dtype=np.bool_)
|
186
|
+
if isinstance(mask, np.ndarray) and mask.any():
|
187
|
+
w[mask] = np.nan
|
188
|
+
|
189
|
+
return VerticalWind(time=time, height=height, w=w, mask=mask)
|
190
|
+
|
191
|
+
|
192
|
+
def _datetime64_from_nc_var(var: netCDF4.Variable) -> npt.NDArray[np.datetime64]:
|
193
|
+
return np.array(
|
194
|
+
netCDF4.num2date(
|
195
|
+
var[:].data,
|
196
|
+
units=var.units,
|
197
|
+
calendar=var.calendar,
|
198
|
+
only_use_cftime_datetimes=False,
|
199
|
+
only_use_python_datetimes=True,
|
200
|
+
),
|
201
|
+
dtype="datetime64[us]",
|
202
|
+
)
|
cloudnetpy/version.py
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.2
|
2
2
|
Name: cloudnetpy
|
3
|
-
Version: 1.
|
3
|
+
Version: 1.71.1
|
4
4
|
Summary: Python package for Cloudnet processing
|
5
5
|
Author: Simo Tukiainen
|
6
6
|
License: MIT License
|
@@ -42,6 +42,7 @@ Requires-Python: >=3.10
|
|
42
42
|
Description-Content-Type: text/markdown
|
43
43
|
License-File: LICENSE
|
44
44
|
Requires-Dist: cloudnetpy_qc>=1.15.0
|
45
|
+
Requires-Dist: doppy>=0.5.0
|
45
46
|
Requires-Dist: matplotlib
|
46
47
|
Requires-Dist: mwrpy>=1.2.0
|
47
48
|
Requires-Dist: netCDF4
|
@@ -9,7 +9,7 @@ cloudnetpy/metadata.py,sha256=BDEpgwZ58PHznc1gi11gtNNV4kFiMAmlHnF4huTy7nw,5982
|
|
9
9
|
cloudnetpy/output.py,sha256=lq4YSeMT_d-j4rlQkKm9KIZ8boupTBBBKV1eUawpmCI,15672
|
10
10
|
cloudnetpy/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
11
11
|
cloudnetpy/utils.py,sha256=U0iMIKPiKLrLVAfs_u9pPuoWYW1RJHcM8dbLF9a4yIA,29796
|
12
|
-
cloudnetpy/version.py,sha256=
|
12
|
+
cloudnetpy/version.py,sha256=Jpj6HUmEXjg2ZHK10S2ho3h_9Khi4cQ_qHcHcBrM7AU,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
|
@@ -101,7 +101,7 @@ cloudnetpy/model_evaluation/tests/unit/test_plotting.py,sha256=h9V8JKmrO4v9bOvv-
|
|
101
101
|
cloudnetpy/model_evaluation/tests/unit/test_statistical_methods.py,sha256=Ra3r4V0qbqkpDuaTYvEIbaasl0nZ5gmTLR4eGC0glBQ,9724
|
102
102
|
cloudnetpy/model_evaluation/tests/unit/test_tools.py,sha256=Ia_VrLdV2NstX5gbx_3AZTOAlrgLAy_xFZ8fHYVX0xI,3817
|
103
103
|
cloudnetpy/plotting/__init__.py,sha256=lg9Smn4BI0dVBgnDLC3JVJ4GmwoSnO-qoSd4ApvwV6Y,107
|
104
|
-
cloudnetpy/plotting/plot_meta.py,sha256=
|
104
|
+
cloudnetpy/plotting/plot_meta.py,sha256=qfyZJNis937uM-NJseer8i4FO7I_v5jhQPyFl5Uszi8,17390
|
105
105
|
cloudnetpy/plotting/plotting.py,sha256=Hi_n3TjzqR2KjZgalFHGxsb7jTsqub9nWzZyscfk6xA,38385
|
106
106
|
cloudnetpy/products/__init__.py,sha256=2hRb5HG9hNrxH1if5laJkLeFeaZCd5W1q3hh4ewsX0E,273
|
107
107
|
cloudnetpy/products/classification.py,sha256=KwAiBSgFwDqhM114NIgYiUjj8HoYc7gAlc8E1QgcSig,8207
|
@@ -109,6 +109,7 @@ cloudnetpy/products/der.py,sha256=soypE7uSEP4uHUCCQVEhyXsKY6e9mzV9B_2S5GUizqk,12
|
|
109
109
|
cloudnetpy/products/drizzle.py,sha256=58C9Mo6oRXR8KpbVPghbJvHvFX9GfS3xUp058pbf0qw,10804
|
110
110
|
cloudnetpy/products/drizzle_error.py,sha256=4GwlHRtNbk9ks7bGtXCco-wXbcDOKeAQwKmbhzut6Qk,6132
|
111
111
|
cloudnetpy/products/drizzle_tools.py,sha256=HLxUQ89mFNo6IIe6Cj3ZH-TPkJdpMxKCOt4cOOmcLs0,11002
|
112
|
+
cloudnetpy/products/epsilon.py,sha256=fthijjUAa7bEhoObRiTOGr4_uRgCpXSfqxIOPD2NGT4,7617
|
112
113
|
cloudnetpy/products/ier.py,sha256=70jyYrhO-kAHuQ3CpDVcyKKuHT3c9Eby6ADHHlPjAFY,5986
|
113
114
|
cloudnetpy/products/iwc.py,sha256=FQtYFYnMNuDnjuK1ee3zOfzPtKsoWH95CXtEz1iplZI,9462
|
114
115
|
cloudnetpy/products/lwc.py,sha256=sl6Al2tuH3KkCBrPbWTmuz3jlD5UQJ4D6qBsn1tt2CQ,18962
|
@@ -116,9 +117,9 @@ cloudnetpy/products/mie_lu_tables.nc,sha256=It4fYpqJXlqOgL8jeZ-PxGzP08PMrELIDVe5
|
|
116
117
|
cloudnetpy/products/mwr_tools.py,sha256=rd7UC67O4fsIE5SaHVZ4qWvUJTj41ZGwgQWPwZzOM14,5377
|
117
118
|
cloudnetpy/products/product_tools.py,sha256=uu4l6reuGbPcW3TgttbaSrqIKbyYGhBVTdnC7opKvmg,11101
|
118
119
|
docs/source/conf.py,sha256=IKiFWw6xhUd8NrCg0q7l596Ck1d61XWeVjIFHVSG9Og,1490
|
119
|
-
cloudnetpy-1.
|
120
|
-
cloudnetpy-1.
|
121
|
-
cloudnetpy-1.
|
122
|
-
cloudnetpy-1.
|
123
|
-
cloudnetpy-1.
|
124
|
-
cloudnetpy-1.
|
120
|
+
cloudnetpy-1.71.1.dist-info/LICENSE,sha256=wcZF72bdaoG9XugpyE95Juo7lBQOwLuTKBOhhtANZMM,1094
|
121
|
+
cloudnetpy-1.71.1.dist-info/METADATA,sha256=-4IIIVCrDs5UmXIrXQmlWzZ-Q9sV5SVodXEjgh_kdqc,5872
|
122
|
+
cloudnetpy-1.71.1.dist-info/WHEEL,sha256=jB7zZ3N9hIM9adW7qlTAyycLYW9npaWKLRzaoVcLKcM,91
|
123
|
+
cloudnetpy-1.71.1.dist-info/entry_points.txt,sha256=HhY7LwCFk4qFgDlXx_Fy983ZTd831WlhtdPIzV-Y3dY,51
|
124
|
+
cloudnetpy-1.71.1.dist-info/top_level.txt,sha256=ibSPWRr6ojS1i11rtBFz2_gkIe68mggj7aeswYfaOo0,16
|
125
|
+
cloudnetpy-1.71.1.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|