pydartdiags 0.0.3b0__tar.gz → 0.0.41__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 pydartdiags might be problematic. Click here for more details.
- {pydartdiags-0.0.3b0 → pydartdiags-0.0.41}/PKG-INFO +22 -15
- {pydartdiags-0.0.3b0 → pydartdiags-0.0.41}/README.md +11 -8
- {pydartdiags-0.0.3b0 → pydartdiags-0.0.41}/pyproject.toml +6 -6
- pydartdiags-0.0.41/setup.cfg +4 -0
- pydartdiags-0.0.41/setup.py +26 -0
- {pydartdiags-0.0.3b0 → pydartdiags-0.0.41}/src/pydartdiags/obs_sequence/obs_sequence.py +73 -74
- {pydartdiags-0.0.3b0 → pydartdiags-0.0.41}/src/pydartdiags/plots/plots.py +27 -24
- pydartdiags-0.0.41/src/pydartdiags.egg-info/PKG-INFO +399 -0
- pydartdiags-0.0.41/src/pydartdiags.egg-info/SOURCES.txt +16 -0
- pydartdiags-0.0.41/src/pydartdiags.egg-info/dependency_links.txt +1 -0
- pydartdiags-0.0.41/src/pydartdiags.egg-info/requires.txt +4 -0
- pydartdiags-0.0.41/src/pydartdiags.egg-info/top_level.txt +1 -0
- pydartdiags-0.0.41/tests/test_obs_sequence.py +29 -0
- pydartdiags-0.0.41/tests/test_plots.py +52 -0
- pydartdiags-0.0.3b0/.gitignore +0 -4
- pydartdiags-0.0.3b0/docs/images/bias.png +0 -0
- pydartdiags-0.0.3b0/docs/images/rankhist.png +0 -0
- pydartdiags-0.0.3b0/docs/images/rmse.png +0 -0
- pydartdiags-0.0.3b0/src/pydartdiags/obs_sequence/composite_types.yaml +0 -35
- pydartdiags-0.0.3b0/src/pydartdiags/plots/tests/test_rank_histogram.py +0 -18
- {pydartdiags-0.0.3b0 → pydartdiags-0.0.41}/LICENSE +0 -0
- {pydartdiags-0.0.3b0 → pydartdiags-0.0.41}/src/pydartdiags/__init__.py +0 -0
- {pydartdiags-0.0.3b0 → pydartdiags-0.0.41}/src/pydartdiags/obs_sequence/__init__.py +0 -0
- {pydartdiags-0.0.3b0 → pydartdiags-0.0.41}/src/pydartdiags/plots/__init__.py +0 -0
|
@@ -1,29 +1,36 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
2
|
Name: pydartdiags
|
|
3
|
-
Version: 0.0.
|
|
3
|
+
Version: 0.0.41
|
|
4
4
|
Summary: Observation Sequence Diagnostics for DART
|
|
5
|
+
Home-page: https://github.com/NCAR/pyDARTdiags.git
|
|
6
|
+
Author: Helen Kershaw
|
|
7
|
+
Author-email: Helen Kershaw <hkershaw@ucar.edu>
|
|
5
8
|
Project-URL: Homepage, https://github.com/NCAR/pyDARTdiags.git
|
|
6
9
|
Project-URL: Issues, https://github.com/NCAR/pyDARTdiags/issues
|
|
7
|
-
|
|
8
|
-
|
|
10
|
+
Project-URL: Documentation, https://ncar.github.io/pyDARTdiags
|
|
11
|
+
Classifier: Programming Language :: Python :: 3
|
|
9
12
|
Classifier: License :: OSI Approved :: Apache Software License
|
|
10
13
|
Classifier: Operating System :: OS Independent
|
|
11
|
-
Classifier: Programming Language :: Python :: 3
|
|
12
14
|
Requires-Python: >=3.8
|
|
13
|
-
|
|
15
|
+
Description-Content-Type: text/markdown
|
|
16
|
+
License-File: LICENSE
|
|
14
17
|
Requires-Dist: pandas>=2.2.0
|
|
18
|
+
Requires-Dist: numpy>=1.26
|
|
15
19
|
Requires-Dist: plotly>=5.22.0
|
|
16
|
-
|
|
20
|
+
Requires-Dist: pyyaml>=6.0.2
|
|
17
21
|
|
|
18
22
|
# pyDARTdiags
|
|
19
23
|
|
|
20
|
-
pyDARTdiags is a
|
|
24
|
+
pyDARTdiags is a Python library for obsevation space diagnostics for the Data Assimilation Research Testbed ([DART](https://github.com/NCAR/DART)).
|
|
21
25
|
|
|
22
26
|
pyDARTdiags is under initial development, so please use caution.
|
|
23
27
|
The MATLAB [observation space diagnostics](https://docs.dart.ucar.edu/en/latest/guide/matlab-observation-space.html) are available through [DART](https://github.com/NCAR/DART).
|
|
24
28
|
|
|
25
29
|
|
|
26
|
-
pyDARTdiags can be installed through pip.
|
|
30
|
+
pyDARTdiags can be installed through pip: https://pypi.org/project/pydartdiags/
|
|
31
|
+
Documenation : https://ncar.github.io/pyDARTdiags/
|
|
32
|
+
|
|
33
|
+
We recommend installing pydartdiags in a virtual enviroment:
|
|
27
34
|
|
|
28
35
|
|
|
29
36
|
```
|
|
@@ -35,14 +42,14 @@ pip install pydartdiags
|
|
|
35
42
|
## Example importing the obs\_sequence and plots modules
|
|
36
43
|
|
|
37
44
|
```python
|
|
38
|
-
from pydartdiags.obs_sequence import obs_sequence as
|
|
45
|
+
from pydartdiags.obs_sequence import obs_sequence as obsq
|
|
39
46
|
from pydartdiags.plots import plots
|
|
40
47
|
```
|
|
41
48
|
|
|
42
49
|
## Examining the dataframe
|
|
43
50
|
|
|
44
51
|
```python
|
|
45
|
-
obs_seq =
|
|
52
|
+
obs_seq = obsq.obs_sequence('obs_seq.final.ascii')
|
|
46
53
|
obs_seq.df.head()
|
|
47
54
|
```
|
|
48
55
|
|
|
@@ -203,7 +210,7 @@ obs_seq.df.head()
|
|
|
203
210
|
Find the numeber of assimilated (used) observations vs. possible observations by type
|
|
204
211
|
|
|
205
212
|
```python
|
|
206
|
-
|
|
213
|
+
obsq.possible_vs_used(obs_seq.df)
|
|
207
214
|
```
|
|
208
215
|
|
|
209
216
|
<table border="1" class="dataframe">
|
|
@@ -360,7 +367,7 @@ obs_seq.possible_vs_used(obs_seq.df)
|
|
|
360
367
|
* plot the rank histogram
|
|
361
368
|
|
|
362
369
|
```python
|
|
363
|
-
df_qc0 =
|
|
370
|
+
df_qc0 = obsq.select_by_dart_qc(obs_seq.df, 0)
|
|
364
371
|
plots.plot_rank_histogram(df_qc0)
|
|
365
372
|
```
|
|
366
373
|

|
|
@@ -376,7 +383,7 @@ plots.plot_rank_histogram(df_qc0)
|
|
|
376
383
|
hPalevels = [0.0, 100.0, 150.0, 200.0, 250.0, 300.0, 400.0, 500.0, 700, 850, 925, 1000]# float("inf")] # Pa?
|
|
377
384
|
plevels = [i * 100 for i in hPalevels]
|
|
378
385
|
|
|
379
|
-
df_qc0 =
|
|
386
|
+
df_qc0 = obsq.select_by_dart_qc(obs_seq.df, 0) # only qc 0
|
|
380
387
|
df_profile, figrmse, figbias = plots.plot_profile(df_qc0, plevels)
|
|
381
388
|
```
|
|
382
389
|
|
|
@@ -389,4 +396,4 @@ Contributions are welcome! If you have a feature request, bug report, or a sugge
|
|
|
389
396
|
|
|
390
397
|
## License
|
|
391
398
|
|
|
392
|
-
|
|
399
|
+
pyDARTdiags is released under the Apache License 2.0. For more details, see the LICENSE file in the root directory of this source tree or visit [Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0).
|
|
@@ -1,12 +1,15 @@
|
|
|
1
1
|
# pyDARTdiags
|
|
2
2
|
|
|
3
|
-
pyDARTdiags is a
|
|
3
|
+
pyDARTdiags is a Python library for obsevation space diagnostics for the Data Assimilation Research Testbed ([DART](https://github.com/NCAR/DART)).
|
|
4
4
|
|
|
5
5
|
pyDARTdiags is under initial development, so please use caution.
|
|
6
6
|
The MATLAB [observation space diagnostics](https://docs.dart.ucar.edu/en/latest/guide/matlab-observation-space.html) are available through [DART](https://github.com/NCAR/DART).
|
|
7
7
|
|
|
8
8
|
|
|
9
|
-
pyDARTdiags can be installed through pip.
|
|
9
|
+
pyDARTdiags can be installed through pip: https://pypi.org/project/pydartdiags/
|
|
10
|
+
Documenation : https://ncar.github.io/pyDARTdiags/
|
|
11
|
+
|
|
12
|
+
We recommend installing pydartdiags in a virtual enviroment:
|
|
10
13
|
|
|
11
14
|
|
|
12
15
|
```
|
|
@@ -18,14 +21,14 @@ pip install pydartdiags
|
|
|
18
21
|
## Example importing the obs\_sequence and plots modules
|
|
19
22
|
|
|
20
23
|
```python
|
|
21
|
-
from pydartdiags.obs_sequence import obs_sequence as
|
|
24
|
+
from pydartdiags.obs_sequence import obs_sequence as obsq
|
|
22
25
|
from pydartdiags.plots import plots
|
|
23
26
|
```
|
|
24
27
|
|
|
25
28
|
## Examining the dataframe
|
|
26
29
|
|
|
27
30
|
```python
|
|
28
|
-
obs_seq =
|
|
31
|
+
obs_seq = obsq.obs_sequence('obs_seq.final.ascii')
|
|
29
32
|
obs_seq.df.head()
|
|
30
33
|
```
|
|
31
34
|
|
|
@@ -186,7 +189,7 @@ obs_seq.df.head()
|
|
|
186
189
|
Find the numeber of assimilated (used) observations vs. possible observations by type
|
|
187
190
|
|
|
188
191
|
```python
|
|
189
|
-
|
|
192
|
+
obsq.possible_vs_used(obs_seq.df)
|
|
190
193
|
```
|
|
191
194
|
|
|
192
195
|
<table border="1" class="dataframe">
|
|
@@ -343,7 +346,7 @@ obs_seq.possible_vs_used(obs_seq.df)
|
|
|
343
346
|
* plot the rank histogram
|
|
344
347
|
|
|
345
348
|
```python
|
|
346
|
-
df_qc0 =
|
|
349
|
+
df_qc0 = obsq.select_by_dart_qc(obs_seq.df, 0)
|
|
347
350
|
plots.plot_rank_histogram(df_qc0)
|
|
348
351
|
```
|
|
349
352
|

|
|
@@ -359,7 +362,7 @@ plots.plot_rank_histogram(df_qc0)
|
|
|
359
362
|
hPalevels = [0.0, 100.0, 150.0, 200.0, 250.0, 300.0, 400.0, 500.0, 700, 850, 925, 1000]# float("inf")] # Pa?
|
|
360
363
|
plevels = [i * 100 for i in hPalevels]
|
|
361
364
|
|
|
362
|
-
df_qc0 =
|
|
365
|
+
df_qc0 = obsq.select_by_dart_qc(obs_seq.df, 0) # only qc 0
|
|
363
366
|
df_profile, figrmse, figbias = plots.plot_profile(df_qc0, plevels)
|
|
364
367
|
```
|
|
365
368
|
|
|
@@ -372,4 +375,4 @@ Contributions are welcome! If you have a feature request, bug report, or a sugge
|
|
|
372
375
|
|
|
373
376
|
## License
|
|
374
377
|
|
|
375
|
-
|
|
378
|
+
pyDARTdiags is released under the Apache License 2.0. For more details, see the LICENSE file in the root directory of this source tree or visit [Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0).
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
[build-system]
|
|
2
|
-
requires = ["
|
|
3
|
-
build-backend = "
|
|
2
|
+
requires = ["setuptools", "wheel"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "pydartdiags"
|
|
7
|
-
version = "0.0.
|
|
7
|
+
version = "0.0.41"
|
|
8
8
|
authors = [
|
|
9
9
|
{ name="Helen Kershaw", email="hkershaw@ucar.edu" },
|
|
10
10
|
]
|
|
@@ -19,12 +19,12 @@ classifiers = [
|
|
|
19
19
|
dependencies = [
|
|
20
20
|
"pandas>=2.2.0",
|
|
21
21
|
"numpy>=1.26",
|
|
22
|
-
"plotly>=5.22.0"
|
|
22
|
+
"plotly>=5.22.0",
|
|
23
|
+
"pyyaml>=6.0.2"
|
|
23
24
|
]
|
|
24
25
|
|
|
25
26
|
[project.urls]
|
|
26
27
|
Homepage = "https://github.com/NCAR/pyDARTdiags.git"
|
|
27
28
|
Issues = "https://github.com/NCAR/pyDARTdiags/issues"
|
|
29
|
+
Documentation = "https://ncar.github.io/pyDARTdiags"
|
|
28
30
|
|
|
29
|
-
[tool.hatch.build.targets.wheel]
|
|
30
|
-
packages = ["src/pydartdiags"]
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
from setuptools import setup, find_packages
|
|
2
|
+
|
|
3
|
+
setup(
|
|
4
|
+
name="pydartdiags",
|
|
5
|
+
version="0.0.41",
|
|
6
|
+
packages=find_packages(where="src"),
|
|
7
|
+
package_dir={"": "src"},
|
|
8
|
+
author="Helen Kershaw",
|
|
9
|
+
author_email="hkershaw@ucar.edu",
|
|
10
|
+
description="Observation Sequence Diagnostics for DART",
|
|
11
|
+
long_description=open("README.md").read(),
|
|
12
|
+
long_description_content_type="text/markdown",
|
|
13
|
+
url="https://github.com/NCAR/pyDARTdiags.git",
|
|
14
|
+
classifiers=[
|
|
15
|
+
"Programming Language :: Python :: 3",
|
|
16
|
+
"License :: OSI Approved :: Apache Software License",
|
|
17
|
+
"Operating System :: OS Independent",
|
|
18
|
+
],
|
|
19
|
+
python_requires=">=3.8",
|
|
20
|
+
install_requires=[
|
|
21
|
+
"pandas>=2.2.0",
|
|
22
|
+
"numpy>=1.26",
|
|
23
|
+
"plotly>=5.22.0",
|
|
24
|
+
"pyyaml>=6.0.2"
|
|
25
|
+
],
|
|
26
|
+
)
|
|
@@ -5,37 +5,38 @@ import os
|
|
|
5
5
|
import yaml
|
|
6
6
|
|
|
7
7
|
class obs_sequence:
|
|
8
|
-
"""Create an obs_sequence object from an ascii observation
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
8
|
+
"""Create an obs_sequence object from an ascii observation sequence file.
|
|
9
|
+
|
|
10
|
+
Attributes:
|
|
11
|
+
df (pandas.DataFrame): DataFrame containing all the observations.
|
|
12
|
+
all_obs (list): List of all observations, each observation is a list.
|
|
13
|
+
header (str): Header from the ascii file.
|
|
14
|
+
vert (dict): Dictionary of dart vertical units.
|
|
15
|
+
types (dict): Dictionary of types in the observation sequence file.
|
|
16
|
+
copie_names (list): Names of copies in the observation sequence file.
|
|
17
|
+
Spelled 'copie' to avoid conflict with the Python built-in copy function.
|
|
18
|
+
Spaces are replaced with underscores in copie_names.
|
|
19
|
+
|
|
20
|
+
Parameters:
|
|
21
|
+
file : the input observation sequence ascii file
|
|
22
|
+
|
|
23
|
+
Example:
|
|
24
|
+
Read the observation sequence from file:
|
|
25
|
+
``obs_seq = obs_sequence('/home/data/obs_seq.final.ascii.small')``
|
|
26
|
+
Access the resulting pandas DataFrame:
|
|
27
|
+
``obs_seq.df``
|
|
28
|
+
|
|
29
|
+
For 3D sphere models: latitude and longitude are in degrees in the DataFrame
|
|
30
|
+
|
|
31
|
+
Calculations:
|
|
32
|
+
|
|
33
|
+
- sq_err = (mean-obs)**2
|
|
34
|
+
- bias = (mean-obs)
|
|
35
|
+
- rmse = sqrt( sum((mean-obs)**2)/n )
|
|
36
|
+
- bias = sum((mean-obs)/n)
|
|
37
|
+
- spread = sum(sd)
|
|
38
|
+
- totalspread = sqrt(sum(sd+obs_err_var))
|
|
39
|
+
|
|
39
40
|
"""
|
|
40
41
|
## static variables
|
|
41
42
|
# vertrical coordinate:
|
|
@@ -59,7 +60,8 @@ class obs_sequence:
|
|
|
59
60
|
'AIRS observation',
|
|
60
61
|
'GTSPP observation',
|
|
61
62
|
'SST observation',
|
|
62
|
-
'observations'
|
|
63
|
+
'observations',
|
|
64
|
+
'WOD observation']
|
|
63
65
|
|
|
64
66
|
def __init__(self, file):
|
|
65
67
|
self.loc_mod = 'None'
|
|
@@ -101,6 +103,7 @@ class obs_sequence:
|
|
|
101
103
|
|
|
102
104
|
def obs_to_list(self, obs):
|
|
103
105
|
"""put single observation into a list
|
|
106
|
+
|
|
104
107
|
discards obs_def
|
|
105
108
|
"""
|
|
106
109
|
data = []
|
|
@@ -170,7 +173,7 @@ class obs_sequence:
|
|
|
170
173
|
def write_obs_seq(self, file, df=None):
|
|
171
174
|
"""
|
|
172
175
|
Write the observation sequence to a file.
|
|
173
|
-
|
|
176
|
+
|
|
174
177
|
This function writes the observation sequence to disk.
|
|
175
178
|
If no DataFrame is provided, it writes the obs_sequence object to a file using the
|
|
176
179
|
header and all observations stored in the object.
|
|
@@ -178,19 +181,17 @@ class obs_sequence:
|
|
|
178
181
|
then writes the DataFrame obs to an obs_sequence file. Note the DataFrame is assumed
|
|
179
182
|
to have been created from obs_sequence object.
|
|
180
183
|
|
|
181
|
-
|
|
184
|
+
|
|
182
185
|
Parameters:
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
and self.all_obs.
|
|
187
|
-
|
|
186
|
+
file (str): The path to the file where the observation sequence will be written.
|
|
187
|
+
df (pandas.DataFrame, optional): A DataFrame containing the observation data. If not provided, the function uses self.header and self.all_obs.
|
|
188
|
+
|
|
188
189
|
Returns:
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
190
|
+
None
|
|
191
|
+
|
|
192
|
+
Examples:
|
|
193
|
+
``obs_seq.write_obs_seq('/path/to/output/file')``
|
|
194
|
+
``obs_seq.write_obs_seq('/path/to/output/file', df=obs_seq.df)``
|
|
194
195
|
"""
|
|
195
196
|
with open(file, 'w') as f:
|
|
196
197
|
|
|
@@ -281,14 +282,13 @@ class obs_sequence:
|
|
|
281
282
|
"""
|
|
282
283
|
Extracts the names of the copies from the header of an obs_seq file.
|
|
283
284
|
|
|
284
|
-
|
|
285
285
|
Parameters:
|
|
286
|
-
|
|
286
|
+
header (list): A list of strings representing the lines in the header of the obs_seq file.
|
|
287
287
|
|
|
288
288
|
Returns:
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
289
|
+
tuple: A tuple containing two elements:
|
|
290
|
+
- copie_names (list): A list of strings representing the copy names with underscores for spaces.
|
|
291
|
+
- len(copie_names) (int): The number of copy names.
|
|
292
292
|
"""
|
|
293
293
|
for i, line in enumerate(header):
|
|
294
294
|
if "num_obs:" in line and "max_num_obs:" in line:
|
|
@@ -348,15 +348,13 @@ class obs_sequence:
|
|
|
348
348
|
components and adds them to the DataFrame.
|
|
349
349
|
|
|
350
350
|
Parameters:
|
|
351
|
-
|
|
352
|
-
If 'use_default', the default configuration is used.
|
|
353
|
-
Otherwise, a custom YAML configuration can be provided.
|
|
351
|
+
composite_types (str, optional): The YAML configuration for composite types. If 'use_default', the default configuration is used. Otherwise, a custom YAML configuration can be provided.
|
|
354
352
|
|
|
355
353
|
Returns:
|
|
356
|
-
|
|
354
|
+
pd.DataFrame: The updated DataFrame with the new composite rows added.
|
|
357
355
|
|
|
358
356
|
Raises:
|
|
359
|
-
|
|
357
|
+
Exception: If there are repeat values in the components.
|
|
360
358
|
"""
|
|
361
359
|
|
|
362
360
|
if composite_types == 'use_default':
|
|
@@ -386,10 +384,10 @@ def load_yaml_to_dict(file_path):
|
|
|
386
384
|
Load a YAML file and convert it to a dictionary.
|
|
387
385
|
|
|
388
386
|
Parameters:
|
|
389
|
-
|
|
387
|
+
file_path (str): The path to the YAML file.
|
|
390
388
|
|
|
391
389
|
Returns:
|
|
392
|
-
|
|
390
|
+
dict: The YAML file content as a dictionary.
|
|
393
391
|
"""
|
|
394
392
|
try:
|
|
395
393
|
with open(file_path, 'r') as file:
|
|
@@ -402,8 +400,9 @@ def load_yaml_to_dict(file_path):
|
|
|
402
400
|
def convert_dart_time(seconds, days):
|
|
403
401
|
"""covert from seconds, days after 1601 to datetime object
|
|
404
402
|
|
|
405
|
-
|
|
406
|
-
|
|
403
|
+
Note:
|
|
404
|
+
- base year for Gregorian calendar is 1601
|
|
405
|
+
- dart time is seconds, days since 1601
|
|
407
406
|
"""
|
|
408
407
|
time = dt.datetime(1601,1,1) + dt.timedelta(days=days, seconds=seconds)
|
|
409
408
|
return time
|
|
@@ -413,14 +412,14 @@ def select_by_dart_qc(df, dart_qc):
|
|
|
413
412
|
Selects rows from a DataFrame based on the DART quality control flag.
|
|
414
413
|
|
|
415
414
|
Parameters:
|
|
416
|
-
|
|
417
|
-
|
|
415
|
+
df (DataFrame): A pandas DataFrame.
|
|
416
|
+
dart_qc (int): The DART quality control flag to select.
|
|
418
417
|
|
|
419
418
|
Returns:
|
|
420
|
-
|
|
419
|
+
DataFrame: A DataFrame containing only the rows with the specified DART quality control flag.
|
|
421
420
|
|
|
422
421
|
Raises:
|
|
423
|
-
|
|
422
|
+
ValueError: If the DART quality control flag is not present in the DataFrame.
|
|
424
423
|
"""
|
|
425
424
|
if dart_qc not in df['DART_quality_control'].unique():
|
|
426
425
|
raise ValueError(f"DART quality control flag '{dart_qc}' not found in DataFrame.")
|
|
@@ -432,10 +431,10 @@ def select_failed_qcs(df):
|
|
|
432
431
|
Selects rows from a DataFrame where the DART quality control flag is greater than 0.
|
|
433
432
|
|
|
434
433
|
Parameters:
|
|
435
|
-
|
|
434
|
+
df (DataFrame): A pandas DataFrame.
|
|
436
435
|
|
|
437
436
|
Returns:
|
|
438
|
-
|
|
437
|
+
DataFrame: A DataFrame containing only the rows with a DART quality control flag greater than 0.
|
|
439
438
|
"""
|
|
440
439
|
return df[df['DART_quality_control'] > 0]
|
|
441
440
|
|
|
@@ -450,14 +449,14 @@ def possible_vs_used(df):
|
|
|
450
449
|
used observations.
|
|
451
450
|
|
|
452
451
|
Parameters:
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
452
|
+
df (pd.DataFrame): A DataFrame with at least two columns: 'type' for the observation type and 'observation'
|
|
453
|
+
for the observation data. It may also contain other columns required by the `select_failed_qcs` function
|
|
454
|
+
to determine failed quality control checks.
|
|
456
455
|
|
|
457
456
|
Returns:
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
457
|
+
pd.DataFrame: A DataFrame with three columns: 'type', 'possible', and 'used'. 'type' is the observation type,
|
|
458
|
+
'possible' is the count of all observations of that type, and 'used' is the count of observations of that type
|
|
459
|
+
that passed quality control checks.
|
|
461
460
|
|
|
462
461
|
"""
|
|
463
462
|
possible = df.groupby('type')['observation'].count()
|
|
@@ -476,12 +475,12 @@ def construct_composit(df_comp, composite, components):
|
|
|
476
475
|
specified columns using the square root of the sum of squares method.
|
|
477
476
|
|
|
478
477
|
Parameters:
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
478
|
+
df_comp (pd.DataFrame): The DataFrame containing the component rows to be combined.
|
|
479
|
+
composite (str): The type name for the new composite rows.
|
|
480
|
+
components (list of str): A list containing the type names of the two components to be combined.
|
|
482
481
|
|
|
483
482
|
Returns:
|
|
484
|
-
|
|
483
|
+
merged_df (pd.DataFrame): The updated DataFrame with the new composite rows added.
|
|
485
484
|
"""
|
|
486
485
|
selected_rows = df_comp[df_comp['type'] == components[0].upper()]
|
|
487
486
|
selected_rows_v = df_comp[df_comp['type'] == components[1].upper()]
|
|
@@ -6,6 +6,7 @@ import pandas as pd
|
|
|
6
6
|
def plot_rank_histogram(df):
|
|
7
7
|
"""
|
|
8
8
|
Plots a rank histogram colored by observation type.
|
|
9
|
+
|
|
9
10
|
All histogram bars are initalized to be hidden and can be toggled visible in the plot's legend
|
|
10
11
|
"""
|
|
11
12
|
_, _, df_hist = calculate_rank(df)
|
|
@@ -27,12 +28,12 @@ def calculate_rank(df):
|
|
|
27
28
|
size plus one.
|
|
28
29
|
|
|
29
30
|
Parameters:
|
|
30
|
-
|
|
31
|
-
|
|
31
|
+
df (pd.DataFrame): A DataFrame with columns for mean, standard deviation, observed values,
|
|
32
|
+
ensemble size, and observation type. The DataFrame should have one row per observation.
|
|
32
33
|
|
|
33
34
|
Returns:
|
|
34
|
-
|
|
35
|
-
|
|
35
|
+
tuple: A tuple containing the rank array, ensemble size, and a result DataFrame. The result
|
|
36
|
+
DataFrame contains columns for 'rank' and 'obstype'.
|
|
36
37
|
"""
|
|
37
38
|
ensemble_values = df.filter(regex='prior_ensemble_member').to_numpy().copy()
|
|
38
39
|
std_dev = np.sqrt(df['obs_err_var']).to_numpy()
|
|
@@ -72,24 +73,24 @@ def plot_profile(df, levels):
|
|
|
72
73
|
the vertical profile in the atmosphere correctly.
|
|
73
74
|
|
|
74
75
|
Parameters:
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
76
|
+
df (pd.DataFrame): The input DataFrame containing at least the 'vertical' column for pressure levels,
|
|
77
|
+
and other columns required by the `rmse_bias` function for calculating RMSE and Bias.
|
|
78
|
+
levels (array-like): The bin edges for categorizing the 'vertical' column values into pressure levels.
|
|
78
79
|
|
|
79
80
|
Returns:
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
81
|
+
tuple: A tuple containing the DataFrame with RMSE and Bias calculations, the RMSE plot figure, and the
|
|
82
|
+
Bias plot figure. The DataFrame includes a 'plevels' column representing the categorized pressure levels
|
|
83
|
+
and 'hPa' column representing the midpoint of each pressure level bin.
|
|
83
84
|
|
|
84
85
|
Raises:
|
|
85
|
-
|
|
86
|
+
ValueError: If there are missing values in the 'vertical' column of the input DataFrame.
|
|
86
87
|
|
|
87
88
|
Note:
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
89
|
+
- The function modifies the input DataFrame by adding 'plevels' and 'hPa' columns.
|
|
90
|
+
- The 'hPa' values are calculated as half the midpoint of each pressure level bin, which may need
|
|
91
|
+
adjustment based on the specific requirements for pressure level representation.
|
|
92
|
+
- The plots are generated using Plotly Express and are displayed inline. The y-axis of the plots is
|
|
93
|
+
reversed to align with standard atmospheric pressure level representation.
|
|
93
94
|
"""
|
|
94
95
|
|
|
95
96
|
pd.options.mode.copy_on_write = True
|
|
@@ -116,15 +117,17 @@ def mean_then_sqrt(x):
|
|
|
116
117
|
Calculates the mean of an array-like object and then takes the square root of the result.
|
|
117
118
|
|
|
118
119
|
Parameters:
|
|
119
|
-
|
|
120
|
-
|
|
120
|
+
arr (array-like): An array-like object (such as a list or a pandas Series).
|
|
121
|
+
The elements should be numeric.
|
|
121
122
|
|
|
122
123
|
Returns:
|
|
123
|
-
|
|
124
|
+
float: The square root of the mean of the input array.
|
|
124
125
|
|
|
125
126
|
Raises:
|
|
126
|
-
|
|
127
|
+
TypeError: If the input is not an array-like object containing numeric values.
|
|
128
|
+
ValueError: If the input array is empty.
|
|
127
129
|
"""
|
|
130
|
+
|
|
128
131
|
return np.sqrt(np.mean(x))
|
|
129
132
|
|
|
130
133
|
def rmse_bias(df):
|
|
@@ -139,14 +142,14 @@ def rmse_bias_by_obs_type(df, obs_type):
|
|
|
139
142
|
Calculate the RMSE and bias for a given observation type.
|
|
140
143
|
|
|
141
144
|
Parameters:
|
|
142
|
-
|
|
143
|
-
|
|
145
|
+
df (DataFrame): A pandas DataFrame.
|
|
146
|
+
obs_type (str): The observation type for which to calculate the RMSE and bias.
|
|
144
147
|
|
|
145
148
|
Returns:
|
|
146
|
-
|
|
149
|
+
DataFrame: A DataFrame containing the RMSE and bias for the given observation type.
|
|
147
150
|
|
|
148
151
|
Raises:
|
|
149
|
-
|
|
152
|
+
ValueError: If the observation type is not present in the DataFrame.
|
|
150
153
|
"""
|
|
151
154
|
if obs_type not in df['type'].unique():
|
|
152
155
|
raise ValueError(f"Observation type '{obs_type}' not found in DataFrame.")
|
|
@@ -0,0 +1,399 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: pydartdiags
|
|
3
|
+
Version: 0.0.41
|
|
4
|
+
Summary: Observation Sequence Diagnostics for DART
|
|
5
|
+
Home-page: https://github.com/NCAR/pyDARTdiags.git
|
|
6
|
+
Author: Helen Kershaw
|
|
7
|
+
Author-email: Helen Kershaw <hkershaw@ucar.edu>
|
|
8
|
+
Project-URL: Homepage, https://github.com/NCAR/pyDARTdiags.git
|
|
9
|
+
Project-URL: Issues, https://github.com/NCAR/pyDARTdiags/issues
|
|
10
|
+
Project-URL: Documentation, https://ncar.github.io/pyDARTdiags
|
|
11
|
+
Classifier: Programming Language :: Python :: 3
|
|
12
|
+
Classifier: License :: OSI Approved :: Apache Software License
|
|
13
|
+
Classifier: Operating System :: OS Independent
|
|
14
|
+
Requires-Python: >=3.8
|
|
15
|
+
Description-Content-Type: text/markdown
|
|
16
|
+
License-File: LICENSE
|
|
17
|
+
Requires-Dist: pandas>=2.2.0
|
|
18
|
+
Requires-Dist: numpy>=1.26
|
|
19
|
+
Requires-Dist: plotly>=5.22.0
|
|
20
|
+
Requires-Dist: pyyaml>=6.0.2
|
|
21
|
+
|
|
22
|
+
# pyDARTdiags
|
|
23
|
+
|
|
24
|
+
pyDARTdiags is a Python library for obsevation space diagnostics for the Data Assimilation Research Testbed ([DART](https://github.com/NCAR/DART)).
|
|
25
|
+
|
|
26
|
+
pyDARTdiags is under initial development, so please use caution.
|
|
27
|
+
The MATLAB [observation space diagnostics](https://docs.dart.ucar.edu/en/latest/guide/matlab-observation-space.html) are available through [DART](https://github.com/NCAR/DART).
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
pyDARTdiags can be installed through pip: https://pypi.org/project/pydartdiags/
|
|
31
|
+
Documenation : https://ncar.github.io/pyDARTdiags/
|
|
32
|
+
|
|
33
|
+
We recommend installing pydartdiags in a virtual enviroment:
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
```
|
|
37
|
+
python3 -m venv dartdiags
|
|
38
|
+
source dartdiags/bin/activate
|
|
39
|
+
pip install pydartdiags
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
## Example importing the obs\_sequence and plots modules
|
|
43
|
+
|
|
44
|
+
```python
|
|
45
|
+
from pydartdiags.obs_sequence import obs_sequence as obsq
|
|
46
|
+
from pydartdiags.plots import plots
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
## Examining the dataframe
|
|
50
|
+
|
|
51
|
+
```python
|
|
52
|
+
obs_seq = obsq.obs_sequence('obs_seq.final.ascii')
|
|
53
|
+
obs_seq.df.head()
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
<table border="1" class="dataframe">
|
|
57
|
+
<thead>
|
|
58
|
+
<tr style="text-align: right;">
|
|
59
|
+
<th></th>
|
|
60
|
+
<th>obs_num</th>
|
|
61
|
+
<th>observation</th>
|
|
62
|
+
<th>prior_ensemble_mean</th>
|
|
63
|
+
<th>prior_ensemble_spread</th>
|
|
64
|
+
<th>prior_ensemble_member_1</th>
|
|
65
|
+
<th>prior_ensemble_member_2</th>
|
|
66
|
+
<th>prior_ensemble_member_3</th>
|
|
67
|
+
<th>prior_ensemble_member_4</th>
|
|
68
|
+
<th>prior_ensemble_member_5</th>
|
|
69
|
+
<th>prior_ensemble_member_6</th>
|
|
70
|
+
<th>...</th>
|
|
71
|
+
<th>latitude</th>
|
|
72
|
+
<th>vertical</th>
|
|
73
|
+
<th>vert_unit</th>
|
|
74
|
+
<th>type</th>
|
|
75
|
+
<th>seconds</th>
|
|
76
|
+
<th>days</th>
|
|
77
|
+
<th>time</th>
|
|
78
|
+
<th>obs_err_var</th>
|
|
79
|
+
<th>bias</th>
|
|
80
|
+
<th>sq_err</th>
|
|
81
|
+
</tr>
|
|
82
|
+
</thead>
|
|
83
|
+
<tbody>
|
|
84
|
+
<tr>
|
|
85
|
+
<th>0</th>
|
|
86
|
+
<td>1</td>
|
|
87
|
+
<td>230.16</td>
|
|
88
|
+
<td>231.310652</td>
|
|
89
|
+
<td>0.405191</td>
|
|
90
|
+
<td>231.304725</td>
|
|
91
|
+
<td>231.562874</td>
|
|
92
|
+
<td>231.333915</td>
|
|
93
|
+
<td>231.297690</td>
|
|
94
|
+
<td>232.081416</td>
|
|
95
|
+
<td>231.051063</td>
|
|
96
|
+
<td>...</td>
|
|
97
|
+
<td>0.012188</td>
|
|
98
|
+
<td>23950.0</td>
|
|
99
|
+
<td>pressure (Pa)</td>
|
|
100
|
+
<td>ACARS_TEMPERATURE</td>
|
|
101
|
+
<td>75603</td>
|
|
102
|
+
<td>153005</td>
|
|
103
|
+
<td>2019-12-01 21:00:03</td>
|
|
104
|
+
<td>1.00</td>
|
|
105
|
+
<td>1.150652</td>
|
|
106
|
+
<td>1.324001</td>
|
|
107
|
+
</tr>
|
|
108
|
+
<tr>
|
|
109
|
+
<th>1</th>
|
|
110
|
+
<td>2</td>
|
|
111
|
+
<td>18.40</td>
|
|
112
|
+
<td>15.720527</td>
|
|
113
|
+
<td>0.630827</td>
|
|
114
|
+
<td>14.217207</td>
|
|
115
|
+
<td>15.558196</td>
|
|
116
|
+
<td>15.805599</td>
|
|
117
|
+
<td>16.594644</td>
|
|
118
|
+
<td>14.877743</td>
|
|
119
|
+
<td>16.334438</td>
|
|
120
|
+
<td>...</td>
|
|
121
|
+
<td>0.012188</td>
|
|
122
|
+
<td>23950.0</td>
|
|
123
|
+
<td>pressure (Pa)</td>
|
|
124
|
+
<td>ACARS_U_WIND_COMPONENT</td>
|
|
125
|
+
<td>75603</td>
|
|
126
|
+
<td>153005</td>
|
|
127
|
+
<td>2019-12-01 21:00:03</td>
|
|
128
|
+
<td>6.25</td>
|
|
129
|
+
<td>-2.679473</td>
|
|
130
|
+
<td>7.179578</td>
|
|
131
|
+
</tr>
|
|
132
|
+
<tr>
|
|
133
|
+
<th>2</th>
|
|
134
|
+
<td>3</td>
|
|
135
|
+
<td>1.60</td>
|
|
136
|
+
<td>-4.932073</td>
|
|
137
|
+
<td>0.825899</td>
|
|
138
|
+
<td>-5.270562</td>
|
|
139
|
+
<td>-5.955998</td>
|
|
140
|
+
<td>-4.209766</td>
|
|
141
|
+
<td>-5.105016</td>
|
|
142
|
+
<td>-4.669405</td>
|
|
143
|
+
<td>-4.365305</td>
|
|
144
|
+
<td>...</td>
|
|
145
|
+
<td>0.012188</td>
|
|
146
|
+
<td>23950.0</td>
|
|
147
|
+
<td>pressure (Pa)</td>
|
|
148
|
+
<td>ACARS_V_WIND_COMPONENT</td>
|
|
149
|
+
<td>75603</td>
|
|
150
|
+
<td>153005</td>
|
|
151
|
+
<td>2019-12-01 21:00:03</td>
|
|
152
|
+
<td>6.25</td>
|
|
153
|
+
<td>-6.532073</td>
|
|
154
|
+
<td>42.667980</td>
|
|
155
|
+
</tr>
|
|
156
|
+
<tr>
|
|
157
|
+
<th>3</th>
|
|
158
|
+
<td>4</td>
|
|
159
|
+
<td>264.16</td>
|
|
160
|
+
<td>264.060532</td>
|
|
161
|
+
<td>0.035584</td>
|
|
162
|
+
<td>264.107192</td>
|
|
163
|
+
<td>264.097270</td>
|
|
164
|
+
<td>264.073212</td>
|
|
165
|
+
<td>264.047718</td>
|
|
166
|
+
<td>264.074140</td>
|
|
167
|
+
<td>264.019895</td>
|
|
168
|
+
<td>...</td>
|
|
169
|
+
<td>0.010389</td>
|
|
170
|
+
<td>56260.0</td>
|
|
171
|
+
<td>pressure (Pa)</td>
|
|
172
|
+
<td>ACARS_TEMPERATURE</td>
|
|
173
|
+
<td>75603</td>
|
|
174
|
+
<td>153005</td>
|
|
175
|
+
<td>2019-12-01 21:00:03</td>
|
|
176
|
+
<td>1.00</td>
|
|
177
|
+
<td>-0.099468</td>
|
|
178
|
+
<td>0.009894</td>
|
|
179
|
+
</tr>
|
|
180
|
+
<tr>
|
|
181
|
+
<th>4</th>
|
|
182
|
+
<td>5</td>
|
|
183
|
+
<td>11.60</td>
|
|
184
|
+
<td>10.134115</td>
|
|
185
|
+
<td>0.063183</td>
|
|
186
|
+
<td>10.067956</td>
|
|
187
|
+
<td>10.078798</td>
|
|
188
|
+
<td>10.120263</td>
|
|
189
|
+
<td>10.084885</td>
|
|
190
|
+
<td>10.135112</td>
|
|
191
|
+
<td>10.140610</td>
|
|
192
|
+
<td>...</td>
|
|
193
|
+
<td>0.010389</td>
|
|
194
|
+
<td>56260.0</td>
|
|
195
|
+
<td>pressure (Pa)</td>
|
|
196
|
+
<td>ACARS_U_WIND_COMPONENT</td>
|
|
197
|
+
<td>75603</td>
|
|
198
|
+
<td>153005</td>
|
|
199
|
+
<td>2019-12-01 21:00:03</td>
|
|
200
|
+
<td>6.25</td>
|
|
201
|
+
<td>-1.465885</td>
|
|
202
|
+
<td>2.148818</td>
|
|
203
|
+
</tr>
|
|
204
|
+
</tbody>
|
|
205
|
+
</table>
|
|
206
|
+
<p>5 rows × 97 columns</p>
|
|
207
|
+
</div>
|
|
208
|
+
|
|
209
|
+
|
|
210
|
+
Find the numeber of assimilated (used) observations vs. possible observations by type
|
|
211
|
+
|
|
212
|
+
```python
|
|
213
|
+
obsq.possible_vs_used(obs_seq.df)
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
<table border="1" class="dataframe">
|
|
217
|
+
<thead>
|
|
218
|
+
<tr style="text-align: right;">
|
|
219
|
+
<th></th>
|
|
220
|
+
<th>type</th>
|
|
221
|
+
<th>possible</th>
|
|
222
|
+
<th>used</th>
|
|
223
|
+
</tr>
|
|
224
|
+
</thead>
|
|
225
|
+
<tbody>
|
|
226
|
+
<tr>
|
|
227
|
+
<th>0</th>
|
|
228
|
+
<td>ACARS_TEMPERATURE</td>
|
|
229
|
+
<td>175429</td>
|
|
230
|
+
<td>128040</td>
|
|
231
|
+
</tr>
|
|
232
|
+
<tr>
|
|
233
|
+
<th>1</th>
|
|
234
|
+
<td>ACARS_U_WIND_COMPONENT</td>
|
|
235
|
+
<td>176120</td>
|
|
236
|
+
<td>126946</td>
|
|
237
|
+
</tr>
|
|
238
|
+
<tr>
|
|
239
|
+
<th>2</th>
|
|
240
|
+
<td>ACARS_V_WIND_COMPONENT</td>
|
|
241
|
+
<td>176120</td>
|
|
242
|
+
<td>127834</td>
|
|
243
|
+
</tr>
|
|
244
|
+
<tr>
|
|
245
|
+
<th>3</th>
|
|
246
|
+
<td>AIRCRAFT_TEMPERATURE</td>
|
|
247
|
+
<td>21335</td>
|
|
248
|
+
<td>13663</td>
|
|
249
|
+
</tr>
|
|
250
|
+
<tr>
|
|
251
|
+
<th>4</th>
|
|
252
|
+
<td>AIRCRAFT_U_WIND_COMPONENT</td>
|
|
253
|
+
<td>21044</td>
|
|
254
|
+
<td>13694</td>
|
|
255
|
+
</tr>
|
|
256
|
+
<tr>
|
|
257
|
+
<th>5</th>
|
|
258
|
+
<td>AIRCRAFT_V_WIND_COMPONENT</td>
|
|
259
|
+
<td>21044</td>
|
|
260
|
+
<td>13642</td>
|
|
261
|
+
</tr>
|
|
262
|
+
<tr>
|
|
263
|
+
<th>6</th>
|
|
264
|
+
<td>AIRS_SPECIFIC_HUMIDITY</td>
|
|
265
|
+
<td>6781</td>
|
|
266
|
+
<td>0</td>
|
|
267
|
+
</tr>
|
|
268
|
+
<tr>
|
|
269
|
+
<th>7</th>
|
|
270
|
+
<td>AIRS_TEMPERATURE</td>
|
|
271
|
+
<td>19583</td>
|
|
272
|
+
<td>7901</td>
|
|
273
|
+
</tr>
|
|
274
|
+
<tr>
|
|
275
|
+
<th>8</th>
|
|
276
|
+
<td>GPSRO_REFRACTIVITY</td>
|
|
277
|
+
<td>81404</td>
|
|
278
|
+
<td>54626</td>
|
|
279
|
+
</tr>
|
|
280
|
+
<tr>
|
|
281
|
+
<th>9</th>
|
|
282
|
+
<td>LAND_SFC_ALTIMETER</td>
|
|
283
|
+
<td>21922</td>
|
|
284
|
+
<td>0</td>
|
|
285
|
+
</tr>
|
|
286
|
+
<tr>
|
|
287
|
+
<th>10</th>
|
|
288
|
+
<td>MARINE_SFC_ALTIMETER</td>
|
|
289
|
+
<td>9987</td>
|
|
290
|
+
<td>0</td>
|
|
291
|
+
</tr>
|
|
292
|
+
<tr>
|
|
293
|
+
<th>11</th>
|
|
294
|
+
<td>MARINE_SFC_SPECIFIC_HUMIDITY</td>
|
|
295
|
+
<td>4196</td>
|
|
296
|
+
<td>0</td>
|
|
297
|
+
</tr>
|
|
298
|
+
<tr>
|
|
299
|
+
<th>12</th>
|
|
300
|
+
<td>MARINE_SFC_TEMPERATURE</td>
|
|
301
|
+
<td>8646</td>
|
|
302
|
+
<td>0</td>
|
|
303
|
+
</tr>
|
|
304
|
+
<tr>
|
|
305
|
+
<th>13</th>
|
|
306
|
+
<td>MARINE_SFC_U_WIND_COMPONENT</td>
|
|
307
|
+
<td>8207</td>
|
|
308
|
+
<td>0</td>
|
|
309
|
+
</tr>
|
|
310
|
+
<tr>
|
|
311
|
+
<th>14</th>
|
|
312
|
+
<td>MARINE_SFC_V_WIND_COMPONENT</td>
|
|
313
|
+
<td>8207</td>
|
|
314
|
+
<td>0</td>
|
|
315
|
+
</tr>
|
|
316
|
+
<tr>
|
|
317
|
+
<th>15</th>
|
|
318
|
+
<td>RADIOSONDE_SPECIFIC_HUMIDITY</td>
|
|
319
|
+
<td>14272</td>
|
|
320
|
+
<td>0</td>
|
|
321
|
+
</tr>
|
|
322
|
+
<tr>
|
|
323
|
+
<th>16</th>
|
|
324
|
+
<td>RADIOSONDE_SURFACE_ALTIMETER</td>
|
|
325
|
+
<td>601</td>
|
|
326
|
+
<td>0</td>
|
|
327
|
+
</tr>
|
|
328
|
+
<tr>
|
|
329
|
+
<th>17</th>
|
|
330
|
+
<td>RADIOSONDE_TEMPERATURE</td>
|
|
331
|
+
<td>29275</td>
|
|
332
|
+
<td>22228</td>
|
|
333
|
+
</tr>
|
|
334
|
+
<tr>
|
|
335
|
+
<th>18</th>
|
|
336
|
+
<td>RADIOSONDE_U_WIND_COMPONENT</td>
|
|
337
|
+
<td>36214</td>
|
|
338
|
+
<td>27832</td>
|
|
339
|
+
</tr>
|
|
340
|
+
<tr>
|
|
341
|
+
<th>19</th>
|
|
342
|
+
<td>RADIOSONDE_V_WIND_COMPONENT</td>
|
|
343
|
+
<td>36214</td>
|
|
344
|
+
<td>27975</td>
|
|
345
|
+
</tr>
|
|
346
|
+
<tr>
|
|
347
|
+
<th>20</th>
|
|
348
|
+
<td>SAT_U_WIND_COMPONENT</td>
|
|
349
|
+
<td>107212</td>
|
|
350
|
+
<td>82507</td>
|
|
351
|
+
</tr>
|
|
352
|
+
<tr>
|
|
353
|
+
<th>21</th>
|
|
354
|
+
<td>SAT_V_WIND_COMPONENT</td>
|
|
355
|
+
<td>107212</td>
|
|
356
|
+
<td>82647</td>
|
|
357
|
+
</tr>
|
|
358
|
+
</tbody>
|
|
359
|
+
</table>
|
|
360
|
+
|
|
361
|
+
|
|
362
|
+
## Example plotting
|
|
363
|
+
|
|
364
|
+
### rank histogram
|
|
365
|
+
|
|
366
|
+
* Select only observations that were assimliated (QC === 0).
|
|
367
|
+
* plot the rank histogram
|
|
368
|
+
|
|
369
|
+
```python
|
|
370
|
+
df_qc0 = obsq.select_by_dart_qc(obs_seq.df, 0)
|
|
371
|
+
plots.plot_rank_histogram(df_qc0)
|
|
372
|
+
```
|
|
373
|
+

|
|
374
|
+
|
|
375
|
+
|
|
376
|
+
### plot profile of RMSE and Bias
|
|
377
|
+
|
|
378
|
+
* Chose levels
|
|
379
|
+
* Select only observations that were assimliated (QC === 0).
|
|
380
|
+
* plot the profiles
|
|
381
|
+
|
|
382
|
+
```python
|
|
383
|
+
hPalevels = [0.0, 100.0, 150.0, 200.0, 250.0, 300.0, 400.0, 500.0, 700, 850, 925, 1000]# float("inf")] # Pa?
|
|
384
|
+
plevels = [i * 100 for i in hPalevels]
|
|
385
|
+
|
|
386
|
+
df_qc0 = obsq.select_by_dart_qc(obs_seq.df, 0) # only qc 0
|
|
387
|
+
df_profile, figrmse, figbias = plots.plot_profile(df_qc0, plevels)
|
|
388
|
+
```
|
|
389
|
+
|
|
390
|
+

|
|
391
|
+
|
|
392
|
+

|
|
393
|
+
|
|
394
|
+
## Contributing
|
|
395
|
+
Contributions are welcome! If you have a feature request, bug report, or a suggestion, please open an issue on our GitHub repository.
|
|
396
|
+
|
|
397
|
+
## License
|
|
398
|
+
|
|
399
|
+
pyDARTdiags is released under the Apache License 2.0. For more details, see the LICENSE file in the root directory of this source tree or visit [Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0).
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
LICENSE
|
|
2
|
+
README.md
|
|
3
|
+
pyproject.toml
|
|
4
|
+
setup.py
|
|
5
|
+
src/pydartdiags/__init__.py
|
|
6
|
+
src/pydartdiags.egg-info/PKG-INFO
|
|
7
|
+
src/pydartdiags.egg-info/SOURCES.txt
|
|
8
|
+
src/pydartdiags.egg-info/dependency_links.txt
|
|
9
|
+
src/pydartdiags.egg-info/requires.txt
|
|
10
|
+
src/pydartdiags.egg-info/top_level.txt
|
|
11
|
+
src/pydartdiags/obs_sequence/__init__.py
|
|
12
|
+
src/pydartdiags/obs_sequence/obs_sequence.py
|
|
13
|
+
src/pydartdiags/plots/__init__.py
|
|
14
|
+
src/pydartdiags/plots/plots.py
|
|
15
|
+
tests/test_obs_sequence.py
|
|
16
|
+
tests/test_plots.py
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
pydartdiags
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import datetime as dt
|
|
2
|
+
|
|
3
|
+
from pydartdiags.obs_sequence import obs_sequence as obs_seq
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def test_convert_dart_time():
|
|
7
|
+
# Test case 1: Convert 0 seconds and 0 days
|
|
8
|
+
result = obs_seq.convert_dart_time(0, 0)
|
|
9
|
+
expected = dt.datetime(1601, 1, 1)
|
|
10
|
+
assert result == expected
|
|
11
|
+
|
|
12
|
+
# Test case 2: Convert 86400 seconds (1 day) and 0 days
|
|
13
|
+
result = obs_seq.convert_dart_time(86400, 0)
|
|
14
|
+
expected = dt.datetime(1601, 1, 2)
|
|
15
|
+
assert result == expected
|
|
16
|
+
|
|
17
|
+
# Test case 3: Convert 0 seconds and 1 day
|
|
18
|
+
result = obs_seq.convert_dart_time(0, 1)
|
|
19
|
+
expected = dt.datetime(1601, 1, 2)
|
|
20
|
+
assert result == expected
|
|
21
|
+
|
|
22
|
+
# Test case 4: Convert 3600 seconds (1 hour) and 1 day
|
|
23
|
+
result = obs_seq.convert_dart_time(2164, 151240)
|
|
24
|
+
expected = dt.datetime(2015, 1, 31, 0, 36, 4)
|
|
25
|
+
assert result == expected
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
if __name__ == '__main__':
|
|
29
|
+
pytest.main()
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import pandas as pd
|
|
2
|
+
import numpy as np
|
|
3
|
+
import pytest
|
|
4
|
+
from pydartdiags.plots import plots as plts
|
|
5
|
+
|
|
6
|
+
def test_calculate_rank():
|
|
7
|
+
# Example DataFrame setup
|
|
8
|
+
data = {
|
|
9
|
+
'observation': [2.5, 3.0, 4.5], # Actual observation values
|
|
10
|
+
'obs_err_var': [0.1, 0.2, 0.3], # Variance of the observation error
|
|
11
|
+
'prior_ensemble_member1': [2.3, 3.1, 4.6],
|
|
12
|
+
'prior_ensemble_member2': [2.4, 2.9, 4.4],
|
|
13
|
+
'prior_ensemble_member3': [2.5, 3.2, 4.5],
|
|
14
|
+
'type': ['A', 'B', 'A'] # Observation type
|
|
15
|
+
}
|
|
16
|
+
df = pd.DataFrame(data)
|
|
17
|
+
|
|
18
|
+
# Call the function
|
|
19
|
+
rank, ens_size, df_hist = plts.calculate_rank(df)
|
|
20
|
+
|
|
21
|
+
# Assertions to check if the function works as expected
|
|
22
|
+
assert ens_size == 3 # 3 ensemble members
|
|
23
|
+
assert 'rank' in df_hist.columns
|
|
24
|
+
assert 'obstype' in df_hist.columns
|
|
25
|
+
|
|
26
|
+
def test_mean_then_sqrt():
|
|
27
|
+
# Test with a list
|
|
28
|
+
data = [1, -4, 9.1, 16]
|
|
29
|
+
result = plts.mean_then_sqrt(data)
|
|
30
|
+
expected = np.sqrt(np.mean(data))
|
|
31
|
+
assert result == expected, f"Expected {expected}, but got {result}"
|
|
32
|
+
|
|
33
|
+
# Test with a numpy array
|
|
34
|
+
data = np.array([1, -4, 9.1, 16])
|
|
35
|
+
result = plts.mean_then_sqrt(data)
|
|
36
|
+
expected = np.sqrt(np.mean(data))
|
|
37
|
+
assert result == expected, f"Expected {expected}, but got {result}"
|
|
38
|
+
|
|
39
|
+
# Test with a pandas Series of positive numbers
|
|
40
|
+
data = pd.Series([1, -4, 9.1, 16])
|
|
41
|
+
result = plts.mean_then_sqrt(data)
|
|
42
|
+
expected = np.sqrt(np.mean(data))
|
|
43
|
+
assert result == expected, f"Expected {expected}, but got {result}"
|
|
44
|
+
|
|
45
|
+
# Test with non-numeric values
|
|
46
|
+
data = ['a', 'b', 'c']
|
|
47
|
+
with pytest.raises(TypeError):
|
|
48
|
+
plts.mean_then_sqrt(data)
|
|
49
|
+
|
|
50
|
+
# If you want to run the test directly from this script
|
|
51
|
+
if __name__ == "__main__":
|
|
52
|
+
test_calculate_rank()
|
pydartdiags-0.0.3b0/.gitignore
DELETED
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
acars_horizontal_wind:
|
|
2
|
-
description: ACARS-derived Horizontal wind speed
|
|
3
|
-
components:
|
|
4
|
-
- acars_u_wind_component
|
|
5
|
-
- acars_v_wind_component
|
|
6
|
-
|
|
7
|
-
sat_horizontal_wind:
|
|
8
|
-
description: Satellite-derived horizontal wind speed
|
|
9
|
-
components:
|
|
10
|
-
- sat_u_wind_component
|
|
11
|
-
- sat_v_wind_component
|
|
12
|
-
|
|
13
|
-
radiosonde_horizontal_wind:
|
|
14
|
-
description: Radiosonde-derived horizontal wind speed
|
|
15
|
-
components:
|
|
16
|
-
- radiosonde_u_wind_component
|
|
17
|
-
- radiosonde_v_wind_component
|
|
18
|
-
|
|
19
|
-
aircraft_horizontal_wind:
|
|
20
|
-
description: Aircraft-derived horizontal wind speed
|
|
21
|
-
components:
|
|
22
|
-
- aircraft_u_wind_component
|
|
23
|
-
- aircraft_v_wind_component
|
|
24
|
-
|
|
25
|
-
10_m_horizontal_wind:
|
|
26
|
-
description: 10 meter horizontal wind speed
|
|
27
|
-
components:
|
|
28
|
-
- 10m_u_wind_component
|
|
29
|
-
- 10m_v_wind_component
|
|
30
|
-
|
|
31
|
-
marine_sfc_horizontal_wind:
|
|
32
|
-
description: Marine surface horizontal wind speed
|
|
33
|
-
components:
|
|
34
|
-
- marine_sfc_u_wind_component
|
|
35
|
-
- marine_sfc_v_wind_component
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
import pandas as pd
|
|
2
|
-
import numpy as np
|
|
3
|
-
|
|
4
|
-
# Example DataFrame setup
|
|
5
|
-
data = {
|
|
6
|
-
'observation': [2.5, 3.0, 4.5], # Actual observation values
|
|
7
|
-
'obs_err_var': [0.1, 0.2, 0.3], # Variance of the observation error
|
|
8
|
-
'prior_ensemble_member1': [2.3, 3.1, 4.6],
|
|
9
|
-
'prior_ensemble_member2': [2.4, 2.9, 4.4],
|
|
10
|
-
'prior_ensemble_member3': [2.5, 3.2, 4.5]
|
|
11
|
-
}
|
|
12
|
-
df = pd.DataFrame(data)
|
|
13
|
-
|
|
14
|
-
# Call the function
|
|
15
|
-
rank, ens_size, _ = calculate_rank(df)
|
|
16
|
-
|
|
17
|
-
print("Rank:", rank)
|
|
18
|
-
print("Ensemble Size:", ens_size)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|