cloudnetpy 1.83.0__tar.gz → 1.84.0__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.
- {cloudnetpy-1.83.0/cloudnetpy.egg-info → cloudnetpy-1.84.0}/PKG-INFO +1 -1
- {cloudnetpy-1.83.0 → cloudnetpy-1.84.0}/cloudnetpy/categorize/categorize.py +1 -1
- cloudnetpy-1.84.0/cloudnetpy/categorize/disdrometer.py +37 -0
- {cloudnetpy-1.83.0 → cloudnetpy-1.84.0}/cloudnetpy/categorize/lidar.py +1 -12
- {cloudnetpy-1.83.0 → cloudnetpy-1.84.0}/cloudnetpy/categorize/mwr.py +6 -9
- {cloudnetpy-1.83.0 → cloudnetpy-1.84.0}/cloudnetpy/instruments/disdrometer/parsivel.py +1 -0
- {cloudnetpy-1.83.0 → cloudnetpy-1.84.0}/cloudnetpy/instruments/weather_station.py +63 -29
- {cloudnetpy-1.83.0 → cloudnetpy-1.84.0}/cloudnetpy/utils.py +56 -1
- {cloudnetpy-1.83.0 → cloudnetpy-1.84.0}/cloudnetpy/version.py +1 -1
- {cloudnetpy-1.83.0 → cloudnetpy-1.84.0/cloudnetpy.egg-info}/PKG-INFO +1 -1
- cloudnetpy-1.83.0/cloudnetpy/categorize/disdrometer.py +0 -60
- {cloudnetpy-1.83.0 → cloudnetpy-1.84.0}/LICENSE +0 -0
- {cloudnetpy-1.83.0 → cloudnetpy-1.84.0}/MANIFEST.in +0 -0
- {cloudnetpy-1.83.0 → cloudnetpy-1.84.0}/README.md +0 -0
- {cloudnetpy-1.83.0 → cloudnetpy-1.84.0}/cloudnetpy/__init__.py +0 -0
- {cloudnetpy-1.83.0 → cloudnetpy-1.84.0}/cloudnetpy/categorize/__init__.py +0 -0
- {cloudnetpy-1.83.0 → cloudnetpy-1.84.0}/cloudnetpy/categorize/atmos_utils.py +0 -0
- {cloudnetpy-1.83.0 → cloudnetpy-1.84.0}/cloudnetpy/categorize/attenuation.py +0 -0
- {cloudnetpy-1.83.0 → cloudnetpy-1.84.0}/cloudnetpy/categorize/attenuations/__init__.py +0 -0
- {cloudnetpy-1.83.0 → cloudnetpy-1.84.0}/cloudnetpy/categorize/attenuations/gas_attenuation.py +0 -0
- {cloudnetpy-1.83.0 → cloudnetpy-1.84.0}/cloudnetpy/categorize/attenuations/liquid_attenuation.py +0 -0
- {cloudnetpy-1.83.0 → cloudnetpy-1.84.0}/cloudnetpy/categorize/attenuations/melting_attenuation.py +0 -0
- {cloudnetpy-1.83.0 → cloudnetpy-1.84.0}/cloudnetpy/categorize/attenuations/rain_attenuation.py +0 -0
- {cloudnetpy-1.83.0 → cloudnetpy-1.84.0}/cloudnetpy/categorize/classify.py +0 -0
- {cloudnetpy-1.83.0 → cloudnetpy-1.84.0}/cloudnetpy/categorize/containers.py +0 -0
- {cloudnetpy-1.83.0 → cloudnetpy-1.84.0}/cloudnetpy/categorize/droplet.py +0 -0
- {cloudnetpy-1.83.0 → cloudnetpy-1.84.0}/cloudnetpy/categorize/falling.py +0 -0
- {cloudnetpy-1.83.0 → cloudnetpy-1.84.0}/cloudnetpy/categorize/freezing.py +0 -0
- {cloudnetpy-1.83.0 → cloudnetpy-1.84.0}/cloudnetpy/categorize/insects.py +0 -0
- {cloudnetpy-1.83.0 → cloudnetpy-1.84.0}/cloudnetpy/categorize/itu.py +0 -0
- {cloudnetpy-1.83.0 → cloudnetpy-1.84.0}/cloudnetpy/categorize/melting.py +0 -0
- {cloudnetpy-1.83.0 → cloudnetpy-1.84.0}/cloudnetpy/categorize/model.py +0 -0
- {cloudnetpy-1.83.0 → cloudnetpy-1.84.0}/cloudnetpy/categorize/radar.py +0 -0
- {cloudnetpy-1.83.0 → cloudnetpy-1.84.0}/cloudnetpy/cli.py +0 -0
- {cloudnetpy-1.83.0 → cloudnetpy-1.84.0}/cloudnetpy/cloudnetarray.py +0 -0
- {cloudnetpy-1.83.0 → cloudnetpy-1.84.0}/cloudnetpy/concat_lib.py +0 -0
- {cloudnetpy-1.83.0 → cloudnetpy-1.84.0}/cloudnetpy/constants.py +0 -0
- {cloudnetpy-1.83.0 → cloudnetpy-1.84.0}/cloudnetpy/datasource.py +0 -0
- {cloudnetpy-1.83.0 → cloudnetpy-1.84.0}/cloudnetpy/exceptions.py +0 -0
- {cloudnetpy-1.83.0 → cloudnetpy-1.84.0}/cloudnetpy/instruments/__init__.py +0 -0
- {cloudnetpy-1.83.0 → cloudnetpy-1.84.0}/cloudnetpy/instruments/basta.py +0 -0
- {cloudnetpy-1.83.0 → cloudnetpy-1.84.0}/cloudnetpy/instruments/bowtie.py +0 -0
- {cloudnetpy-1.83.0 → cloudnetpy-1.84.0}/cloudnetpy/instruments/ceilo.py +0 -0
- {cloudnetpy-1.83.0 → cloudnetpy-1.84.0}/cloudnetpy/instruments/ceilometer.py +0 -0
- {cloudnetpy-1.83.0 → cloudnetpy-1.84.0}/cloudnetpy/instruments/cl61d.py +0 -0
- {cloudnetpy-1.83.0 → cloudnetpy-1.84.0}/cloudnetpy/instruments/cloudnet_instrument.py +0 -0
- {cloudnetpy-1.83.0 → cloudnetpy-1.84.0}/cloudnetpy/instruments/copernicus.py +0 -0
- {cloudnetpy-1.83.0 → cloudnetpy-1.84.0}/cloudnetpy/instruments/disdrometer/__init__.py +0 -0
- {cloudnetpy-1.83.0 → cloudnetpy-1.84.0}/cloudnetpy/instruments/disdrometer/common.py +0 -0
- {cloudnetpy-1.83.0 → cloudnetpy-1.84.0}/cloudnetpy/instruments/disdrometer/thies.py +0 -0
- {cloudnetpy-1.83.0 → cloudnetpy-1.84.0}/cloudnetpy/instruments/fd12p.py +0 -0
- {cloudnetpy-1.83.0 → cloudnetpy-1.84.0}/cloudnetpy/instruments/galileo.py +0 -0
- {cloudnetpy-1.83.0 → cloudnetpy-1.84.0}/cloudnetpy/instruments/hatpro.py +0 -0
- {cloudnetpy-1.83.0 → cloudnetpy-1.84.0}/cloudnetpy/instruments/instruments.py +0 -0
- {cloudnetpy-1.83.0 → cloudnetpy-1.84.0}/cloudnetpy/instruments/lufft.py +0 -0
- {cloudnetpy-1.83.0 → cloudnetpy-1.84.0}/cloudnetpy/instruments/mira.py +0 -0
- {cloudnetpy-1.83.0 → cloudnetpy-1.84.0}/cloudnetpy/instruments/mrr.py +0 -0
- {cloudnetpy-1.83.0 → cloudnetpy-1.84.0}/cloudnetpy/instruments/nc_lidar.py +0 -0
- {cloudnetpy-1.83.0 → cloudnetpy-1.84.0}/cloudnetpy/instruments/nc_radar.py +0 -0
- {cloudnetpy-1.83.0 → cloudnetpy-1.84.0}/cloudnetpy/instruments/pollyxt.py +0 -0
- {cloudnetpy-1.83.0 → cloudnetpy-1.84.0}/cloudnetpy/instruments/radiometrics.py +0 -0
- {cloudnetpy-1.83.0 → cloudnetpy-1.84.0}/cloudnetpy/instruments/rain_e_h3.py +0 -0
- {cloudnetpy-1.83.0 → cloudnetpy-1.84.0}/cloudnetpy/instruments/rpg.py +0 -0
- {cloudnetpy-1.83.0 → cloudnetpy-1.84.0}/cloudnetpy/instruments/rpg_reader.py +0 -0
- {cloudnetpy-1.83.0 → cloudnetpy-1.84.0}/cloudnetpy/instruments/toa5.py +0 -0
- {cloudnetpy-1.83.0 → cloudnetpy-1.84.0}/cloudnetpy/instruments/vaisala.py +0 -0
- {cloudnetpy-1.83.0 → cloudnetpy-1.84.0}/cloudnetpy/metadata.py +0 -0
- {cloudnetpy-1.83.0 → cloudnetpy-1.84.0}/cloudnetpy/model_evaluation/__init__.py +0 -0
- {cloudnetpy-1.83.0 → cloudnetpy-1.84.0}/cloudnetpy/model_evaluation/file_handler.py +0 -0
- {cloudnetpy-1.83.0 → cloudnetpy-1.84.0}/cloudnetpy/model_evaluation/metadata.py +0 -0
- {cloudnetpy-1.83.0 → cloudnetpy-1.84.0}/cloudnetpy/model_evaluation/model_metadata.py +0 -0
- {cloudnetpy-1.83.0 → cloudnetpy-1.84.0}/cloudnetpy/model_evaluation/plotting/__init__.py +0 -0
- {cloudnetpy-1.83.0 → cloudnetpy-1.84.0}/cloudnetpy/model_evaluation/plotting/plot_meta.py +0 -0
- {cloudnetpy-1.83.0 → cloudnetpy-1.84.0}/cloudnetpy/model_evaluation/plotting/plot_tools.py +0 -0
- {cloudnetpy-1.83.0 → cloudnetpy-1.84.0}/cloudnetpy/model_evaluation/plotting/plotting.py +0 -0
- {cloudnetpy-1.83.0 → cloudnetpy-1.84.0}/cloudnetpy/model_evaluation/products/__init__.py +0 -0
- {cloudnetpy-1.83.0 → cloudnetpy-1.84.0}/cloudnetpy/model_evaluation/products/advance_methods.py +0 -0
- {cloudnetpy-1.83.0 → cloudnetpy-1.84.0}/cloudnetpy/model_evaluation/products/grid_methods.py +0 -0
- {cloudnetpy-1.83.0 → cloudnetpy-1.84.0}/cloudnetpy/model_evaluation/products/model_products.py +0 -0
- {cloudnetpy-1.83.0 → cloudnetpy-1.84.0}/cloudnetpy/model_evaluation/products/observation_products.py +0 -0
- {cloudnetpy-1.83.0 → cloudnetpy-1.84.0}/cloudnetpy/model_evaluation/products/product_resampling.py +0 -0
- {cloudnetpy-1.83.0 → cloudnetpy-1.84.0}/cloudnetpy/model_evaluation/products/tools.py +0 -0
- {cloudnetpy-1.83.0 → cloudnetpy-1.84.0}/cloudnetpy/model_evaluation/statistics/__init__.py +0 -0
- {cloudnetpy-1.83.0 → cloudnetpy-1.84.0}/cloudnetpy/model_evaluation/statistics/statistical_methods.py +0 -0
- {cloudnetpy-1.83.0 → cloudnetpy-1.84.0}/cloudnetpy/model_evaluation/tests/__init__.py +0 -0
- {cloudnetpy-1.83.0 → cloudnetpy-1.84.0}/cloudnetpy/model_evaluation/tests/e2e/__init__.py +0 -0
- {cloudnetpy-1.83.0 → cloudnetpy-1.84.0}/cloudnetpy/model_evaluation/tests/e2e/conftest.py +0 -0
- {cloudnetpy-1.83.0 → cloudnetpy-1.84.0}/cloudnetpy/model_evaluation/tests/e2e/process_cf/__init__.py +0 -0
- {cloudnetpy-1.83.0 → cloudnetpy-1.84.0}/cloudnetpy/model_evaluation/tests/e2e/process_cf/main.py +0 -0
- {cloudnetpy-1.83.0 → cloudnetpy-1.84.0}/cloudnetpy/model_evaluation/tests/e2e/process_cf/tests.py +0 -0
- {cloudnetpy-1.83.0 → cloudnetpy-1.84.0}/cloudnetpy/model_evaluation/tests/e2e/process_iwc/__init__.py +0 -0
- {cloudnetpy-1.83.0 → cloudnetpy-1.84.0}/cloudnetpy/model_evaluation/tests/e2e/process_iwc/main.py +0 -0
- {cloudnetpy-1.83.0 → cloudnetpy-1.84.0}/cloudnetpy/model_evaluation/tests/e2e/process_iwc/tests.py +0 -0
- {cloudnetpy-1.83.0 → cloudnetpy-1.84.0}/cloudnetpy/model_evaluation/tests/e2e/process_lwc/__init__.py +0 -0
- {cloudnetpy-1.83.0 → cloudnetpy-1.84.0}/cloudnetpy/model_evaluation/tests/e2e/process_lwc/main.py +0 -0
- {cloudnetpy-1.83.0 → cloudnetpy-1.84.0}/cloudnetpy/model_evaluation/tests/e2e/process_lwc/tests.py +0 -0
- {cloudnetpy-1.83.0 → cloudnetpy-1.84.0}/cloudnetpy/model_evaluation/tests/unit/__init__.py +0 -0
- {cloudnetpy-1.83.0 → cloudnetpy-1.84.0}/cloudnetpy/model_evaluation/tests/unit/conftest.py +0 -0
- {cloudnetpy-1.83.0 → cloudnetpy-1.84.0}/cloudnetpy/model_evaluation/tests/unit/test_advance_methods.py +0 -0
- {cloudnetpy-1.83.0 → cloudnetpy-1.84.0}/cloudnetpy/model_evaluation/tests/unit/test_grid_methods.py +0 -0
- {cloudnetpy-1.83.0 → cloudnetpy-1.84.0}/cloudnetpy/model_evaluation/tests/unit/test_model_products.py +0 -0
- {cloudnetpy-1.83.0 → cloudnetpy-1.84.0}/cloudnetpy/model_evaluation/tests/unit/test_observation_products.py +0 -0
- {cloudnetpy-1.83.0 → cloudnetpy-1.84.0}/cloudnetpy/model_evaluation/tests/unit/test_plot_tools.py +0 -0
- {cloudnetpy-1.83.0 → cloudnetpy-1.84.0}/cloudnetpy/model_evaluation/tests/unit/test_plotting.py +0 -0
- {cloudnetpy-1.83.0 → cloudnetpy-1.84.0}/cloudnetpy/model_evaluation/tests/unit/test_statistical_methods.py +0 -0
- {cloudnetpy-1.83.0 → cloudnetpy-1.84.0}/cloudnetpy/model_evaluation/tests/unit/test_tools.py +0 -0
- {cloudnetpy-1.83.0 → cloudnetpy-1.84.0}/cloudnetpy/model_evaluation/utils.py +0 -0
- {cloudnetpy-1.83.0 → cloudnetpy-1.84.0}/cloudnetpy/output.py +0 -0
- {cloudnetpy-1.83.0 → cloudnetpy-1.84.0}/cloudnetpy/plotting/__init__.py +0 -0
- {cloudnetpy-1.83.0 → cloudnetpy-1.84.0}/cloudnetpy/plotting/plot_meta.py +0 -0
- {cloudnetpy-1.83.0 → cloudnetpy-1.84.0}/cloudnetpy/plotting/plotting.py +0 -0
- {cloudnetpy-1.83.0 → cloudnetpy-1.84.0}/cloudnetpy/products/__init__.py +0 -0
- {cloudnetpy-1.83.0 → cloudnetpy-1.84.0}/cloudnetpy/products/classification.py +0 -0
- {cloudnetpy-1.83.0 → cloudnetpy-1.84.0}/cloudnetpy/products/der.py +0 -0
- {cloudnetpy-1.83.0 → cloudnetpy-1.84.0}/cloudnetpy/products/drizzle.py +0 -0
- {cloudnetpy-1.83.0 → cloudnetpy-1.84.0}/cloudnetpy/products/drizzle_error.py +0 -0
- {cloudnetpy-1.83.0 → cloudnetpy-1.84.0}/cloudnetpy/products/drizzle_tools.py +0 -0
- {cloudnetpy-1.83.0 → cloudnetpy-1.84.0}/cloudnetpy/products/epsilon.py +0 -0
- {cloudnetpy-1.83.0 → cloudnetpy-1.84.0}/cloudnetpy/products/ier.py +0 -0
- {cloudnetpy-1.83.0 → cloudnetpy-1.84.0}/cloudnetpy/products/iwc.py +0 -0
- {cloudnetpy-1.83.0 → cloudnetpy-1.84.0}/cloudnetpy/products/lwc.py +0 -0
- {cloudnetpy-1.83.0 → cloudnetpy-1.84.0}/cloudnetpy/products/mie_lu_tables.nc +0 -0
- {cloudnetpy-1.83.0 → cloudnetpy-1.84.0}/cloudnetpy/products/mwr_tools.py +0 -0
- {cloudnetpy-1.83.0 → cloudnetpy-1.84.0}/cloudnetpy/products/product_tools.py +0 -0
- {cloudnetpy-1.83.0 → cloudnetpy-1.84.0}/cloudnetpy/py.typed +0 -0
- {cloudnetpy-1.83.0 → cloudnetpy-1.84.0}/cloudnetpy.egg-info/SOURCES.txt +0 -0
- {cloudnetpy-1.83.0 → cloudnetpy-1.84.0}/cloudnetpy.egg-info/dependency_links.txt +0 -0
- {cloudnetpy-1.83.0 → cloudnetpy-1.84.0}/cloudnetpy.egg-info/entry_points.txt +0 -0
- {cloudnetpy-1.83.0 → cloudnetpy-1.84.0}/cloudnetpy.egg-info/requires.txt +0 -0
- {cloudnetpy-1.83.0 → cloudnetpy-1.84.0}/cloudnetpy.egg-info/top_level.txt +0 -0
- {cloudnetpy-1.83.0 → cloudnetpy-1.84.0}/docs/source/conf.py +0 -0
- {cloudnetpy-1.83.0 → cloudnetpy-1.84.0}/pyproject.toml +0 -0
- {cloudnetpy-1.83.0 → cloudnetpy-1.84.0}/setup.cfg +0 -0
@@ -93,7 +93,7 @@ def generate_categorize(
|
|
93
93
|
if data.disdrometer is not None:
|
94
94
|
data.disdrometer.interpolate_to_grid(time)
|
95
95
|
if data.mwr is not None:
|
96
|
-
data.mwr.
|
96
|
+
data.mwr.interpolate_to_grid(time)
|
97
97
|
data.model.calc_attenuations(data.radar.radar_frequency)
|
98
98
|
data.model.interpolate_to_common_height()
|
99
99
|
model_gap_ind = data.model.interpolate_to_grid(time, height)
|
@@ -0,0 +1,37 @@
|
|
1
|
+
"""Mwr module, containing the :class:`Mwr` class."""
|
2
|
+
|
3
|
+
from os import PathLike
|
4
|
+
|
5
|
+
import numpy.typing as npt
|
6
|
+
|
7
|
+
from cloudnetpy.datasource import DataSource
|
8
|
+
from cloudnetpy.exceptions import DisdrometerDataError
|
9
|
+
from cloudnetpy.utils import interpolate_1d
|
10
|
+
|
11
|
+
|
12
|
+
class Disdrometer(DataSource):
|
13
|
+
"""Disdrometer class, child of DataSource.
|
14
|
+
|
15
|
+
Args:
|
16
|
+
----
|
17
|
+
full_path: Cloudnet Level 1b disdrometer file.
|
18
|
+
|
19
|
+
"""
|
20
|
+
|
21
|
+
def __init__(self, full_path: str | PathLike) -> None:
|
22
|
+
super().__init__(full_path)
|
23
|
+
self._init_rainfall_rate()
|
24
|
+
|
25
|
+
def interpolate_to_grid(self, time_grid: npt.NDArray) -> None:
|
26
|
+
for key, array in self.data.items():
|
27
|
+
self.data[key].data = interpolate_1d(
|
28
|
+
self.time, array.data, time_grid, max_time=1
|
29
|
+
)
|
30
|
+
|
31
|
+
def _init_rainfall_rate(self) -> None:
|
32
|
+
keys = ("rainfall_rate", "n_particles")
|
33
|
+
for key in keys:
|
34
|
+
if key not in self.dataset.variables:
|
35
|
+
msg = f"variable {key} is missing"
|
36
|
+
raise DisdrometerDataError(msg)
|
37
|
+
self.append_data(self.dataset.variables[key][:], key)
|
@@ -4,12 +4,11 @@ import logging
|
|
4
4
|
from os import PathLike
|
5
5
|
from typing import Literal
|
6
6
|
|
7
|
-
import numpy as np
|
8
7
|
import numpy.typing as npt
|
9
8
|
from numpy import ma
|
10
9
|
|
11
10
|
from cloudnetpy.datasource import DataSource
|
12
|
-
from cloudnetpy.utils import interpolate_2d_nearest
|
11
|
+
from cloudnetpy.utils import get_gap_ind, interpolate_2d_nearest
|
13
12
|
|
14
13
|
|
15
14
|
class Lidar(DataSource):
|
@@ -70,13 +69,3 @@ class Lidar(DataSource):
|
|
70
69
|
self.append_data(float(self.getvar("wavelength")), "lidar_wavelength")
|
71
70
|
self.append_data(0.5, "beta_error")
|
72
71
|
self.append_data(3.0, "beta_bias")
|
73
|
-
|
74
|
-
|
75
|
-
def get_gap_ind(
|
76
|
-
grid: npt.NDArray, new_grid: npt.NDArray, threshold: float
|
77
|
-
) -> list[int]:
|
78
|
-
return [
|
79
|
-
ind
|
80
|
-
for ind, value in enumerate(new_grid)
|
81
|
-
if np.min(np.abs(grid - value)) > threshold
|
82
|
-
]
|
@@ -8,6 +8,7 @@ import numpy.typing as npt
|
|
8
8
|
from cloudnetpy import utils
|
9
9
|
from cloudnetpy.constants import G_TO_KG
|
10
10
|
from cloudnetpy.datasource import DataSource
|
11
|
+
from cloudnetpy.utils import interpolate_1d
|
11
12
|
|
12
13
|
|
13
14
|
class Mwr(DataSource):
|
@@ -23,15 +24,11 @@ class Mwr(DataSource):
|
|
23
24
|
self._init_lwp_data()
|
24
25
|
self._init_lwp_error()
|
25
26
|
|
26
|
-
def
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
"""
|
33
|
-
for array in self.data.values():
|
34
|
-
array.rebin_data(self.time, time_grid)
|
27
|
+
def interpolate_to_grid(self, time_grid: npt.NDArray, max_time: float = 1) -> None:
|
28
|
+
for key, array in self.data.items():
|
29
|
+
self.data[key].data = interpolate_1d(
|
30
|
+
self.time, array.data, time_grid, max_time=max_time
|
31
|
+
)
|
35
32
|
|
36
33
|
def _init_lwp_data(self) -> None:
|
37
34
|
lwp = self.dataset.variables["lwp"][:]
|
@@ -205,6 +205,7 @@ TOA5_HEADERS = {
|
|
205
205
|
"precipitation": "_rain_accum",
|
206
206
|
"rain accum [mm]": "_rain_accum",
|
207
207
|
"weatherCodeWaWa": "synop_WaWa",
|
208
|
+
"wawa": "synop_WaWa",
|
208
209
|
"weather_code_wawa": "synop_WaWa",
|
209
210
|
"radarReflectivity": "radar_reflectivity",
|
210
211
|
"radar_reflectivity": "radar_reflectivity",
|
@@ -70,6 +70,8 @@ def ws2nc(
|
|
70
70
|
ws = LimassolWS(weather_station_file, site_meta)
|
71
71
|
elif site_meta["name"] == "L'Aquila":
|
72
72
|
ws = LAquilaWS(weather_station_file, site_meta)
|
73
|
+
elif site_meta["name"] == "Maïdo Observatory":
|
74
|
+
ws = MaidoWS(weather_station_file, site_meta)
|
73
75
|
else:
|
74
76
|
msg = "Unsupported site"
|
75
77
|
raise ValueError(msg)
|
@@ -162,6 +164,26 @@ class WS(CSVFile):
|
|
162
164
|
|
163
165
|
|
164
166
|
class PalaiseauWS(WS):
|
167
|
+
expected_header_identifiers: tuple[str, ...] = (
|
168
|
+
"DateTime(yyyy-mm-ddThh:mm:ssZ)",
|
169
|
+
"Windspeed(m/s)",
|
170
|
+
"Winddirection(deg",
|
171
|
+
"Airtemperature",
|
172
|
+
"Relativehumidity(%)",
|
173
|
+
"Pressure(hPa)",
|
174
|
+
"Precipitationrate(mm/min)",
|
175
|
+
"precipitation",
|
176
|
+
)
|
177
|
+
keys: tuple[str, ...] = (
|
178
|
+
"wind_speed",
|
179
|
+
"wind_direction",
|
180
|
+
"air_temperature",
|
181
|
+
"relative_humidity",
|
182
|
+
"air_pressure",
|
183
|
+
"rainfall_rate",
|
184
|
+
"rainfall_amount",
|
185
|
+
)
|
186
|
+
|
165
187
|
def __init__(self, filenames: Sequence[str | PathLike], site_meta: dict) -> None:
|
166
188
|
super().__init__(site_meta)
|
167
189
|
self.filenames = filenames
|
@@ -175,16 +197,16 @@ class PalaiseauWS(WS):
|
|
175
197
|
for row in data:
|
176
198
|
if not (columns := row.split()):
|
177
199
|
continue
|
178
|
-
if
|
179
|
-
header_row = "".join(columns)
|
180
|
-
if header_row not in header:
|
181
|
-
header.append(header_row)
|
182
|
-
else:
|
200
|
+
if re.match(r"\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}Z", columns[0]):
|
183
201
|
timestamp = datetime.datetime.strptime(
|
184
202
|
columns[0], "%Y-%m-%dT%H:%M:%SZ"
|
185
203
|
).replace(tzinfo=datetime.timezone.utc)
|
186
204
|
values.append([timestamp] + [float(x) for x in columns[1:]])
|
187
205
|
timestamps.append(timestamp)
|
206
|
+
else:
|
207
|
+
header_row = "".join(columns)
|
208
|
+
if header_row not in header:
|
209
|
+
header.append(header_row)
|
188
210
|
|
189
211
|
self._validate_header(header)
|
190
212
|
return {"time": timestamps, "values": values}
|
@@ -204,16 +226,9 @@ class PalaiseauWS(WS):
|
|
204
226
|
]
|
205
227
|
|
206
228
|
def add_data(self) -> None:
|
207
|
-
|
208
|
-
"
|
209
|
-
|
210
|
-
"air_temperature",
|
211
|
-
"relative_humidity",
|
212
|
-
"air_pressure",
|
213
|
-
"rainfall_rate",
|
214
|
-
"rainfall_amount",
|
215
|
-
)
|
216
|
-
for ind, key in enumerate(keys):
|
229
|
+
for ind, key in enumerate(self.keys):
|
230
|
+
if key.startswith("_"):
|
231
|
+
continue
|
217
232
|
array = [row[ind + 1] for row in self._data["values"]]
|
218
233
|
array_masked = ma.masked_invalid(array)
|
219
234
|
self.data[key] = CloudnetArray(array_masked, key)
|
@@ -223,27 +238,46 @@ class PalaiseauWS(WS):
|
|
223
238
|
self.data["rainfall_amount"][:] / 1000
|
224
239
|
) # mm -> m
|
225
240
|
|
226
|
-
|
227
|
-
def _validate_header(header: list[str]) -> None:
|
228
|
-
expected_identifiers = [
|
229
|
-
"DateTime(yyyy-mm-ddThh:mm:ssZ)",
|
230
|
-
"Windspeed(m/s)",
|
231
|
-
"Winddirection(deg",
|
232
|
-
"Airtemperature",
|
233
|
-
"Relativehumidity(%)",
|
234
|
-
"Pressure(hPa)",
|
235
|
-
"Precipitationrate(mm/min)",
|
236
|
-
"precipitation",
|
237
|
-
]
|
241
|
+
def _validate_header(self, header: list[str]) -> None:
|
238
242
|
column_titles = [row for row in header if "Col." in row]
|
239
243
|
error_msg = "Unexpected weather station file format"
|
240
|
-
if len(column_titles) != len(
|
244
|
+
if len(column_titles) != len(self.expected_header_identifiers):
|
241
245
|
raise ValueError(error_msg)
|
242
|
-
for title, identifier in zip(
|
246
|
+
for title, identifier in zip(
|
247
|
+
column_titles, self.expected_header_identifiers, strict=True
|
248
|
+
):
|
243
249
|
if identifier not in title:
|
244
250
|
raise ValueError(error_msg)
|
245
251
|
|
246
252
|
|
253
|
+
class MaidoWS(PalaiseauWS):
|
254
|
+
expected_header_identifiers = (
|
255
|
+
"DateTimeyyyy-mm-ddThh:mm:ssZ",
|
256
|
+
"Winddirection-average",
|
257
|
+
"Windspeed-maximumvalue(m/s)",
|
258
|
+
"Windspeed-average(m/s)",
|
259
|
+
"Pressure-average(hPa)",
|
260
|
+
"Relativehumidity-maximumvalue(%)",
|
261
|
+
"Relativehumidity-average(%)",
|
262
|
+
"Airtemperature-minimumvalue",
|
263
|
+
"Airtemperature-average",
|
264
|
+
)
|
265
|
+
|
266
|
+
keys = (
|
267
|
+
"wind_direction",
|
268
|
+
"_wind_speed_max",
|
269
|
+
"wind_speed",
|
270
|
+
"air_pressure",
|
271
|
+
"_relative_humidity_max",
|
272
|
+
"relative_humidity",
|
273
|
+
"_air_temperature_min",
|
274
|
+
"air_temperature",
|
275
|
+
)
|
276
|
+
|
277
|
+
def convert_rainfall_amount(self) -> None:
|
278
|
+
pass
|
279
|
+
|
280
|
+
|
247
281
|
class BucharestWS(PalaiseauWS):
|
248
282
|
def convert_rainfall_rate(self) -> None:
|
249
283
|
rainfall_rate = self.data["rainfall_rate"][:]
|
@@ -3,6 +3,7 @@
|
|
3
3
|
import base64
|
4
4
|
import datetime
|
5
5
|
import hashlib
|
6
|
+
import logging
|
6
7
|
import os
|
7
8
|
import re
|
8
9
|
import textwrap
|
@@ -17,7 +18,12 @@ import numpy as np
|
|
17
18
|
import numpy.typing as npt
|
18
19
|
from numpy import ma
|
19
20
|
from scipy import ndimage, stats
|
20
|
-
from scipy.interpolate import
|
21
|
+
from scipy.interpolate import (
|
22
|
+
RectBivariateSpline,
|
23
|
+
RegularGridInterpolator,
|
24
|
+
griddata,
|
25
|
+
interp1d,
|
26
|
+
)
|
21
27
|
|
22
28
|
from cloudnetpy.cloudnetarray import CloudnetArray
|
23
29
|
from cloudnetpy.constants import SEC_IN_DAY, SEC_IN_HOUR, SEC_IN_MINUTE
|
@@ -413,6 +419,55 @@ def interpolate_2d_nearest(
|
|
413
419
|
return fun((xx, yy)).T
|
414
420
|
|
415
421
|
|
422
|
+
def interpolate_1d(
|
423
|
+
time: npt.NDArray, y: ma.MaskedArray, time_new: npt.NDArray, max_time: float
|
424
|
+
) -> npt.NDArray:
|
425
|
+
"""1D linear interpolation preserving the mask.
|
426
|
+
|
427
|
+
Args:
|
428
|
+
time: 1D array in fraction hour.
|
429
|
+
y: 1D masked array, data values.
|
430
|
+
time_new: 1D array, new time coordinates.
|
431
|
+
max_time: Maximum allowed gap in minutes. Values outside this gap will
|
432
|
+
be masked.
|
433
|
+
"""
|
434
|
+
if np.max(time) > 24 or np.min(time) < 0:
|
435
|
+
msg = "Time vector must be in fraction hours between 0 and 24"
|
436
|
+
raise ValueError(msg)
|
437
|
+
if ma.is_masked(y):
|
438
|
+
if y.mask.all():
|
439
|
+
return ma.masked_all(time_new.shape)
|
440
|
+
time = time[~y.mask]
|
441
|
+
y = y[~y.mask]
|
442
|
+
fun = interp1d(time, y, fill_value=(y[0], y[-1]), bounds_error=False)
|
443
|
+
interpolated = ma.array(fun(time_new))
|
444
|
+
bad_idx = get_gap_ind(time, time_new, max_time / 60)
|
445
|
+
|
446
|
+
if len(bad_idx) > 0:
|
447
|
+
msg = f"Unable to interpolate for {len(bad_idx)} time steps"
|
448
|
+
logging.warning(msg)
|
449
|
+
interpolated[bad_idx] = ma.masked
|
450
|
+
|
451
|
+
return interpolated
|
452
|
+
|
453
|
+
|
454
|
+
def get_gap_ind(
|
455
|
+
grid: npt.NDArray, new_grid: npt.NDArray, threshold: float
|
456
|
+
) -> list[int]:
|
457
|
+
"""Finds indices in new_grid that are too far from grid."""
|
458
|
+
if grid.size == 0:
|
459
|
+
return list(range(len(new_grid)))
|
460
|
+
idxs = np.searchsorted(grid, new_grid)
|
461
|
+
left_dist = np.where(idxs > 0, np.abs(new_grid - grid[idxs - 1]), np.inf)
|
462
|
+
right_dist = np.where(
|
463
|
+
idxs < len(grid),
|
464
|
+
np.abs(new_grid - grid[np.clip(idxs, 0, len(grid) - 1)]),
|
465
|
+
np.inf,
|
466
|
+
)
|
467
|
+
nearest = np.minimum(left_dist, right_dist)
|
468
|
+
return np.where(nearest > threshold)[0].tolist()
|
469
|
+
|
470
|
+
|
416
471
|
def calc_relative_error(reference: npt.NDArray, array: npt.NDArray) -> npt.NDArray:
|
417
472
|
"""Calculates relative error (%)."""
|
418
473
|
return ((array - reference) / reference) * 100
|
@@ -1,60 +0,0 @@
|
|
1
|
-
"""Mwr module, containing the :class:`Mwr` class."""
|
2
|
-
|
3
|
-
import logging
|
4
|
-
from os import PathLike
|
5
|
-
|
6
|
-
import numpy as np
|
7
|
-
import numpy.typing as npt
|
8
|
-
from numpy import ma
|
9
|
-
from scipy.interpolate import interp1d
|
10
|
-
|
11
|
-
from cloudnetpy.categorize.lidar import get_gap_ind
|
12
|
-
from cloudnetpy.datasource import DataSource
|
13
|
-
from cloudnetpy.exceptions import DisdrometerDataError
|
14
|
-
|
15
|
-
|
16
|
-
class Disdrometer(DataSource):
|
17
|
-
"""Disdrometer class, child of DataSource.
|
18
|
-
|
19
|
-
Args:
|
20
|
-
----
|
21
|
-
full_path: Cloudnet Level 1b disdrometer file.
|
22
|
-
|
23
|
-
"""
|
24
|
-
|
25
|
-
def __init__(self, full_path: str | PathLike) -> None:
|
26
|
-
super().__init__(full_path)
|
27
|
-
self._init_rainfall_rate()
|
28
|
-
|
29
|
-
def interpolate_to_grid(self, time_grid: npt.NDArray) -> None:
|
30
|
-
for key, array in self.data.items():
|
31
|
-
self.data[key].data = self._interpolate(array.data, time_grid)
|
32
|
-
|
33
|
-
def _init_rainfall_rate(self) -> None:
|
34
|
-
keys = ("rainfall_rate", "n_particles")
|
35
|
-
for key in keys:
|
36
|
-
if key not in self.dataset.variables:
|
37
|
-
msg = f"variable {key} is missing"
|
38
|
-
raise DisdrometerDataError(msg)
|
39
|
-
self.append_data(self.dataset.variables[key][:], key)
|
40
|
-
|
41
|
-
def _interpolate(self, y: ma.MaskedArray, x_new: npt.NDArray) -> npt.NDArray:
|
42
|
-
time = self.time
|
43
|
-
mask = ma.getmask(y)
|
44
|
-
if mask is not ma.nomask:
|
45
|
-
if np.all(mask):
|
46
|
-
return ma.masked_all(x_new.shape)
|
47
|
-
not_masked = ~mask
|
48
|
-
y = y[not_masked]
|
49
|
-
time = time[not_masked]
|
50
|
-
fun = interp1d(time, y, fill_value="extrapolate")
|
51
|
-
interpolated_array = ma.array(fun(x_new))
|
52
|
-
max_time = 1 / 60 # min -> fraction hour
|
53
|
-
mask_ind = get_gap_ind(time, x_new, max_time)
|
54
|
-
|
55
|
-
if len(mask_ind) > 0:
|
56
|
-
msg = f"Unable to interpolate disdrometer for {len(mask_ind)} time steps"
|
57
|
-
logging.warning(msg)
|
58
|
-
interpolated_array[mask_ind] = ma.masked
|
59
|
-
|
60
|
-
return interpolated_array
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
{cloudnetpy-1.83.0 → cloudnetpy-1.84.0}/cloudnetpy/categorize/attenuations/gas_attenuation.py
RENAMED
File without changes
|
{cloudnetpy-1.83.0 → cloudnetpy-1.84.0}/cloudnetpy/categorize/attenuations/liquid_attenuation.py
RENAMED
File without changes
|
{cloudnetpy-1.83.0 → cloudnetpy-1.84.0}/cloudnetpy/categorize/attenuations/melting_attenuation.py
RENAMED
File without changes
|
{cloudnetpy-1.83.0 → cloudnetpy-1.84.0}/cloudnetpy/categorize/attenuations/rain_attenuation.py
RENAMED
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
|
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
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
{cloudnetpy-1.83.0 → cloudnetpy-1.84.0}/cloudnetpy/model_evaluation/products/advance_methods.py
RENAMED
File without changes
|
{cloudnetpy-1.83.0 → cloudnetpy-1.84.0}/cloudnetpy/model_evaluation/products/grid_methods.py
RENAMED
File without changes
|
{cloudnetpy-1.83.0 → cloudnetpy-1.84.0}/cloudnetpy/model_evaluation/products/model_products.py
RENAMED
File without changes
|
{cloudnetpy-1.83.0 → cloudnetpy-1.84.0}/cloudnetpy/model_evaluation/products/observation_products.py
RENAMED
File without changes
|
{cloudnetpy-1.83.0 → cloudnetpy-1.84.0}/cloudnetpy/model_evaluation/products/product_resampling.py
RENAMED
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
{cloudnetpy-1.83.0 → cloudnetpy-1.84.0}/cloudnetpy/model_evaluation/tests/e2e/process_cf/__init__.py
RENAMED
File without changes
|
{cloudnetpy-1.83.0 → cloudnetpy-1.84.0}/cloudnetpy/model_evaluation/tests/e2e/process_cf/main.py
RENAMED
File without changes
|
{cloudnetpy-1.83.0 → cloudnetpy-1.84.0}/cloudnetpy/model_evaluation/tests/e2e/process_cf/tests.py
RENAMED
File without changes
|
File without changes
|
{cloudnetpy-1.83.0 → cloudnetpy-1.84.0}/cloudnetpy/model_evaluation/tests/e2e/process_iwc/main.py
RENAMED
File without changes
|
{cloudnetpy-1.83.0 → cloudnetpy-1.84.0}/cloudnetpy/model_evaluation/tests/e2e/process_iwc/tests.py
RENAMED
File without changes
|
File without changes
|
{cloudnetpy-1.83.0 → cloudnetpy-1.84.0}/cloudnetpy/model_evaluation/tests/e2e/process_lwc/main.py
RENAMED
File without changes
|
{cloudnetpy-1.83.0 → cloudnetpy-1.84.0}/cloudnetpy/model_evaluation/tests/e2e/process_lwc/tests.py
RENAMED
File without changes
|
File without changes
|
File without changes
|
File without changes
|
{cloudnetpy-1.83.0 → cloudnetpy-1.84.0}/cloudnetpy/model_evaluation/tests/unit/test_grid_methods.py
RENAMED
File without changes
|
File without changes
|
File without changes
|
{cloudnetpy-1.83.0 → cloudnetpy-1.84.0}/cloudnetpy/model_evaluation/tests/unit/test_plot_tools.py
RENAMED
File without changes
|
{cloudnetpy-1.83.0 → cloudnetpy-1.84.0}/cloudnetpy/model_evaluation/tests/unit/test_plotting.py
RENAMED
File without changes
|
File without changes
|
{cloudnetpy-1.83.0 → cloudnetpy-1.84.0}/cloudnetpy/model_evaluation/tests/unit/test_tools.py
RENAMED
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
|
File without changes
|
File without changes
|
File without changes
|