cloudnetpy-qc 1.24.1__tar.gz → 1.30.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_qc-1.24.1/cloudnetpy_qc.egg-info → cloudnetpy_qc-1.30.0}/PKG-INFO +9 -5
- {cloudnetpy_qc-1.24.1 → cloudnetpy_qc-1.30.0}/README.md +5 -1
- cloudnetpy_qc-1.30.0/cloudnetpy_qc/coverage.py +69 -0
- {cloudnetpy_qc-1.24.1 → cloudnetpy_qc-1.30.0}/cloudnetpy_qc/data/cf-standard-name-table.xml +1453 -1108
- {cloudnetpy_qc-1.24.1 → cloudnetpy_qc-1.30.0}/cloudnetpy_qc/data/data_quality_config.ini +17 -3
- {cloudnetpy_qc-1.24.1 → cloudnetpy_qc-1.30.0}/cloudnetpy_qc/quality.py +214 -102
- {cloudnetpy_qc-1.24.1 → cloudnetpy_qc-1.30.0}/cloudnetpy_qc/utils.py +48 -0
- {cloudnetpy_qc-1.24.1 → cloudnetpy_qc-1.30.0}/cloudnetpy_qc/variables.py +103 -31
- {cloudnetpy_qc-1.24.1 → cloudnetpy_qc-1.30.0}/cloudnetpy_qc/version.py +2 -2
- {cloudnetpy_qc-1.24.1 → cloudnetpy_qc-1.30.0/cloudnetpy_qc.egg-info}/PKG-INFO +9 -5
- {cloudnetpy_qc-1.24.1 → cloudnetpy_qc-1.30.0}/cloudnetpy_qc.egg-info/SOURCES.txt +1 -0
- {cloudnetpy_qc-1.24.1 → cloudnetpy_qc-1.30.0}/pyproject.toml +4 -4
- {cloudnetpy_qc-1.24.1 → cloudnetpy_qc-1.30.0}/tests/test_qc.py +1 -0
- {cloudnetpy_qc-1.24.1 → cloudnetpy_qc-1.30.0}/LICENSE +0 -0
- {cloudnetpy_qc-1.24.1 → cloudnetpy_qc-1.30.0}/MANIFEST.in +0 -0
- {cloudnetpy_qc-1.24.1 → cloudnetpy_qc-1.30.0}/cloudnetpy_qc/__init__.py +0 -0
- {cloudnetpy_qc-1.24.1 → cloudnetpy_qc-1.30.0}/cloudnetpy_qc/data/area-type-table.xml +0 -0
- {cloudnetpy_qc-1.24.1 → cloudnetpy_qc-1.30.0}/cloudnetpy_qc/data/standardized-region-list.xml +0 -0
- {cloudnetpy_qc-1.24.1 → cloudnetpy_qc-1.30.0}/cloudnetpy_qc/py.typed +0 -0
- {cloudnetpy_qc-1.24.1 → cloudnetpy_qc-1.30.0}/cloudnetpy_qc.egg-info/dependency_links.txt +0 -0
- {cloudnetpy_qc-1.24.1 → cloudnetpy_qc-1.30.0}/cloudnetpy_qc.egg-info/requires.txt +0 -0
- {cloudnetpy_qc-1.24.1 → cloudnetpy_qc-1.30.0}/cloudnetpy_qc.egg-info/top_level.txt +0 -0
- {cloudnetpy_qc-1.24.1 → cloudnetpy_qc-1.30.0}/setup.cfg +0 -0
- {cloudnetpy_qc-1.24.1 → cloudnetpy_qc-1.30.0}/tests/test_utils.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: cloudnetpy_qc
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.30.0
|
|
4
4
|
Summary: Quality control routines for CloudnetPy products
|
|
5
5
|
Author-email: Finnish Meteorological Institute <actris-cloudnet@fmi.fi>
|
|
6
6
|
License: MIT License
|
|
@@ -28,12 +28,12 @@ License: MIT License
|
|
|
28
28
|
Project-URL: Homepage, https://github.com/actris-cloudnet/cloudnetpy-qc
|
|
29
29
|
Project-URL: Repository, https://github.com/actris-cloudnet/cloudnetpy-qc
|
|
30
30
|
Project-URL: Changelog, https://github.com/actris-cloudnet/cloudnetpy-qc/blob/main/CHANGELOG.md
|
|
31
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
31
32
|
Classifier: Intended Audience :: Science/Research
|
|
32
33
|
Classifier: License :: OSI Approved :: MIT License
|
|
33
34
|
Classifier: Operating System :: OS Independent
|
|
34
|
-
Classifier: Programming Language :: Python :: 3
|
|
35
|
-
Classifier:
|
|
36
|
-
Classifier: Topic :: Scientific/Engineering
|
|
35
|
+
Classifier: Programming Language :: Python :: 3
|
|
36
|
+
Classifier: Topic :: Scientific/Engineering :: Atmospheric Science
|
|
37
37
|
Requires-Python: >=3.10
|
|
38
38
|
Description-Content-Type: text/markdown
|
|
39
39
|
License-File: LICENSE
|
|
@@ -80,6 +80,7 @@ print(json_object)
|
|
|
80
80
|
- `timestamp`: UTC timestamp of the test
|
|
81
81
|
- `qcVersion`: `cloudnetpy-qc` version
|
|
82
82
|
- `tests`: `Test[]`
|
|
83
|
+
- `data_coverage`: float
|
|
83
84
|
|
|
84
85
|
### `Test`
|
|
85
86
|
|
|
@@ -137,6 +138,7 @@ print(json_object)
|
|
|
137
138
|
| `TestBrightnessTemperature` | Test that brightness temperature data are valid. |
|
|
138
139
|
| `TestCFConvention` | Test compliance with the CF metadata conventions. |
|
|
139
140
|
| `TestComment` | Check that variables have expected comments. |
|
|
141
|
+
| `TestCompression` | Test netCDF compression. |
|
|
140
142
|
| `TestCoordinateVariables` | Test dimensions of coordinate variables are correct. |
|
|
141
143
|
| `TestCoordinates` | Check that file coordinates match site coordinates. |
|
|
142
144
|
| `TestDataCoverage` | Test that file contains enough data. |
|
|
@@ -155,13 +157,15 @@ print(json_object)
|
|
|
155
157
|
| `TestMask` | Test that data are not completely masked. |
|
|
156
158
|
| `TestMedianLwp` | Test that LWP data are valid. |
|
|
157
159
|
| `TestModelData` | Test that model data are valid. |
|
|
158
|
-
| `TestRainfallConsistency` | Test that
|
|
160
|
+
| `TestRainfallConsistency` | Test that precipitation rate and amount are consistent. |
|
|
161
|
+
| `TestRangeAndHeight` | Test that range and height data are valid. |
|
|
159
162
|
| `TestStandardNames` | Check that variable have expected standard names. |
|
|
160
163
|
| `TestTimeVector` | Test that time vector is continuous. |
|
|
161
164
|
| `TestUnexpectedMask` | Test if data contain unexpected masked values. |
|
|
162
165
|
| `TestUnits` | Check that variables have expected units. |
|
|
163
166
|
| `TestVariableNames` | Check that file contains required variables. |
|
|
164
167
|
| `TestVariableNamesDefined` | Check that variables have expected names. |
|
|
168
|
+
| `TestZenithAngle` | Test lidar zenith angle. |
|
|
165
169
|
|
|
166
170
|
## License
|
|
167
171
|
|
|
@@ -27,6 +27,7 @@ print(json_object)
|
|
|
27
27
|
- `timestamp`: UTC timestamp of the test
|
|
28
28
|
- `qcVersion`: `cloudnetpy-qc` version
|
|
29
29
|
- `tests`: `Test[]`
|
|
30
|
+
- `data_coverage`: float
|
|
30
31
|
|
|
31
32
|
### `Test`
|
|
32
33
|
|
|
@@ -84,6 +85,7 @@ print(json_object)
|
|
|
84
85
|
| `TestBrightnessTemperature` | Test that brightness temperature data are valid. |
|
|
85
86
|
| `TestCFConvention` | Test compliance with the CF metadata conventions. |
|
|
86
87
|
| `TestComment` | Check that variables have expected comments. |
|
|
88
|
+
| `TestCompression` | Test netCDF compression. |
|
|
87
89
|
| `TestCoordinateVariables` | Test dimensions of coordinate variables are correct. |
|
|
88
90
|
| `TestCoordinates` | Check that file coordinates match site coordinates. |
|
|
89
91
|
| `TestDataCoverage` | Test that file contains enough data. |
|
|
@@ -102,13 +104,15 @@ print(json_object)
|
|
|
102
104
|
| `TestMask` | Test that data are not completely masked. |
|
|
103
105
|
| `TestMedianLwp` | Test that LWP data are valid. |
|
|
104
106
|
| `TestModelData` | Test that model data are valid. |
|
|
105
|
-
| `TestRainfallConsistency` | Test that
|
|
107
|
+
| `TestRainfallConsistency` | Test that precipitation rate and amount are consistent. |
|
|
108
|
+
| `TestRangeAndHeight` | Test that range and height data are valid. |
|
|
106
109
|
| `TestStandardNames` | Check that variable have expected standard names. |
|
|
107
110
|
| `TestTimeVector` | Test that time vector is continuous. |
|
|
108
111
|
| `TestUnexpectedMask` | Test if data contain unexpected masked values. |
|
|
109
112
|
| `TestUnits` | Check that variables have expected units. |
|
|
110
113
|
| `TestVariableNames` | Check that file contains required variables. |
|
|
111
114
|
| `TestVariableNamesDefined` | Check that variables have expected names. |
|
|
115
|
+
| `TestZenithAngle` | Test lidar zenith angle. |
|
|
112
116
|
|
|
113
117
|
## License
|
|
114
118
|
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import datetime
|
|
2
|
+
|
|
3
|
+
import netCDF4
|
|
4
|
+
import numpy as np
|
|
5
|
+
|
|
6
|
+
from cloudnetpy_qc.variables import Product
|
|
7
|
+
|
|
8
|
+
RESOLUTIONS = {
|
|
9
|
+
Product.DISDROMETER: datetime.timedelta(minutes=1),
|
|
10
|
+
Product.L3_CF: datetime.timedelta(hours=1),
|
|
11
|
+
Product.L3_IWC: datetime.timedelta(hours=1),
|
|
12
|
+
Product.L3_LWC: datetime.timedelta(hours=1),
|
|
13
|
+
Product.MWR: datetime.timedelta(minutes=5),
|
|
14
|
+
Product.MWR_MULTI: datetime.timedelta(minutes=30),
|
|
15
|
+
Product.MWR_SINGLE: datetime.timedelta(minutes=5),
|
|
16
|
+
Product.WEATHER_STATION: datetime.timedelta(minutes=10),
|
|
17
|
+
Product.RAIN_GAUGE: datetime.timedelta(minutes=1),
|
|
18
|
+
Product.DOPPLER_LIDAR_WIND: datetime.timedelta(hours=1.5),
|
|
19
|
+
Product.CPR_VALIDATION: datetime.timedelta(hours=1.5),
|
|
20
|
+
}
|
|
21
|
+
DEFAULT_RESOLUTION = datetime.timedelta(seconds=30)
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def data_coverage(
|
|
25
|
+
nc: netCDF4.Dataset,
|
|
26
|
+
) -> tuple[float | np.floating, datetime.timedelta, datetime.timedelta] | None:
|
|
27
|
+
time = np.array(nc["time"][:])
|
|
28
|
+
time_unit = datetime.timedelta(hours=1)
|
|
29
|
+
try:
|
|
30
|
+
n_time = len(time)
|
|
31
|
+
except (TypeError, ValueError):
|
|
32
|
+
return None
|
|
33
|
+
if n_time < 2:
|
|
34
|
+
return None
|
|
35
|
+
if nc.cloudnet_file_type == "model":
|
|
36
|
+
expected_res = _model_resolution(nc)
|
|
37
|
+
elif "da10" in getattr(nc, "source", "").lower():
|
|
38
|
+
expected_res = datetime.timedelta(minutes=2)
|
|
39
|
+
else:
|
|
40
|
+
product = Product(nc.cloudnet_file_type)
|
|
41
|
+
expected_res = RESOLUTIONS.get(product, DEFAULT_RESOLUTION)
|
|
42
|
+
duration = get_duration(nc)
|
|
43
|
+
bins = max(1, duration // expected_res)
|
|
44
|
+
hist, _ = np.histogram(time, bins=bins, range=(0, duration / time_unit))
|
|
45
|
+
coverage = np.count_nonzero(hist > 0) / len(hist)
|
|
46
|
+
actual_res = float(np.median(np.diff(time))) * time_unit
|
|
47
|
+
return coverage, expected_res, actual_res
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def _model_resolution(nc: netCDF4.Dataset) -> datetime.timedelta:
|
|
51
|
+
source = nc.source.lower()
|
|
52
|
+
if "gdas" in source or "ecmwf open" in source:
|
|
53
|
+
return datetime.timedelta(hours=3)
|
|
54
|
+
return datetime.timedelta(hours=1)
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
def get_duration(nc: netCDF4.Dataset) -> datetime.timedelta:
|
|
58
|
+
now = datetime.datetime.now(tz=datetime.timezone.utc)
|
|
59
|
+
if now.date() == _get_date(nc):
|
|
60
|
+
midnight = now.replace(hour=0, minute=0, second=0, microsecond=0)
|
|
61
|
+
duration = now - midnight
|
|
62
|
+
else:
|
|
63
|
+
duration = datetime.timedelta(days=1)
|
|
64
|
+
return duration
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
def _get_date(nc: netCDF4.Dataset) -> datetime.date:
|
|
68
|
+
date_in_file = [int(getattr(nc, x)) for x in ("year", "month", "day")]
|
|
69
|
+
return datetime.date(*date_in_file)
|