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.
Files changed (24) hide show
  1. {cloudnetpy_qc-1.24.1/cloudnetpy_qc.egg-info → cloudnetpy_qc-1.30.0}/PKG-INFO +9 -5
  2. {cloudnetpy_qc-1.24.1 → cloudnetpy_qc-1.30.0}/README.md +5 -1
  3. cloudnetpy_qc-1.30.0/cloudnetpy_qc/coverage.py +69 -0
  4. {cloudnetpy_qc-1.24.1 → cloudnetpy_qc-1.30.0}/cloudnetpy_qc/data/cf-standard-name-table.xml +1453 -1108
  5. {cloudnetpy_qc-1.24.1 → cloudnetpy_qc-1.30.0}/cloudnetpy_qc/data/data_quality_config.ini +17 -3
  6. {cloudnetpy_qc-1.24.1 → cloudnetpy_qc-1.30.0}/cloudnetpy_qc/quality.py +214 -102
  7. {cloudnetpy_qc-1.24.1 → cloudnetpy_qc-1.30.0}/cloudnetpy_qc/utils.py +48 -0
  8. {cloudnetpy_qc-1.24.1 → cloudnetpy_qc-1.30.0}/cloudnetpy_qc/variables.py +103 -31
  9. {cloudnetpy_qc-1.24.1 → cloudnetpy_qc-1.30.0}/cloudnetpy_qc/version.py +2 -2
  10. {cloudnetpy_qc-1.24.1 → cloudnetpy_qc-1.30.0/cloudnetpy_qc.egg-info}/PKG-INFO +9 -5
  11. {cloudnetpy_qc-1.24.1 → cloudnetpy_qc-1.30.0}/cloudnetpy_qc.egg-info/SOURCES.txt +1 -0
  12. {cloudnetpy_qc-1.24.1 → cloudnetpy_qc-1.30.0}/pyproject.toml +4 -4
  13. {cloudnetpy_qc-1.24.1 → cloudnetpy_qc-1.30.0}/tests/test_qc.py +1 -0
  14. {cloudnetpy_qc-1.24.1 → cloudnetpy_qc-1.30.0}/LICENSE +0 -0
  15. {cloudnetpy_qc-1.24.1 → cloudnetpy_qc-1.30.0}/MANIFEST.in +0 -0
  16. {cloudnetpy_qc-1.24.1 → cloudnetpy_qc-1.30.0}/cloudnetpy_qc/__init__.py +0 -0
  17. {cloudnetpy_qc-1.24.1 → cloudnetpy_qc-1.30.0}/cloudnetpy_qc/data/area-type-table.xml +0 -0
  18. {cloudnetpy_qc-1.24.1 → cloudnetpy_qc-1.30.0}/cloudnetpy_qc/data/standardized-region-list.xml +0 -0
  19. {cloudnetpy_qc-1.24.1 → cloudnetpy_qc-1.30.0}/cloudnetpy_qc/py.typed +0 -0
  20. {cloudnetpy_qc-1.24.1 → cloudnetpy_qc-1.30.0}/cloudnetpy_qc.egg-info/dependency_links.txt +0 -0
  21. {cloudnetpy_qc-1.24.1 → cloudnetpy_qc-1.30.0}/cloudnetpy_qc.egg-info/requires.txt +0 -0
  22. {cloudnetpy_qc-1.24.1 → cloudnetpy_qc-1.30.0}/cloudnetpy_qc.egg-info/top_level.txt +0 -0
  23. {cloudnetpy_qc-1.24.1 → cloudnetpy_qc-1.30.0}/setup.cfg +0 -0
  24. {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.24.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.10
35
- Classifier: Programming Language :: Python :: 3.11
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 rainfall rate and rainfall amount are consistent. |
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 rainfall rate and rainfall amount are consistent. |
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)