obsarray 1.0.2__tar.gz → 1.0.3__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.
- {obsarray-1.0.2/obsarray.egg-info → obsarray-1.0.3}/PKG-INFO +1 -1
- {obsarray-1.0.2 → obsarray-1.0.3}/obsarray/__init__.py +1 -0
- {obsarray-1.0.2 → obsarray-1.0.3}/obsarray/_version.py +3 -3
- {obsarray-1.0.2 → obsarray-1.0.3}/obsarray/flag_accessor.py +6 -6
- {obsarray-1.0.2 → obsarray-1.0.3}/obsarray/templater/dataset_util.py +1 -1
- {obsarray-1.0.2 → obsarray-1.0.3}/obsarray/test/test_unc_accessor.py +86 -24
- obsarray-1.0.3/obsarray/test/test_utils.py +169 -0
- {obsarray-1.0.2 → obsarray-1.0.3}/obsarray/unc_accessor.py +99 -4
- obsarray-1.0.3/obsarray/utils.py +66 -0
- {obsarray-1.0.2 → obsarray-1.0.3/obsarray.egg-info}/PKG-INFO +1 -1
- {obsarray-1.0.2 → obsarray-1.0.3}/obsarray.egg-info/SOURCES.txt +2 -1
- {obsarray-1.0.2 → obsarray-1.0.3}/versioneer.py +183 -126
- obsarray-1.0.2/obsarray/utils.py +0 -31
- {obsarray-1.0.2 → obsarray-1.0.3}/LICENSE +0 -0
- {obsarray-1.0.2 → obsarray-1.0.3}/MANIFEST.in +0 -0
- {obsarray-1.0.2 → obsarray-1.0.3}/README.md +0 -0
- {obsarray-1.0.2 → obsarray-1.0.3}/docs/conf.py +0 -0
- {obsarray-1.0.2 → obsarray-1.0.3}/notebook/test_register_err_corr_form.py +0 -0
- {obsarray-1.0.2 → obsarray-1.0.3}/obsarray/err_corr.py +0 -0
- {obsarray-1.0.2 → obsarray-1.0.3}/obsarray/templater/__init__.py +0 -0
- {obsarray-1.0.2 → obsarray-1.0.3}/obsarray/templater/dstemplater.py +0 -0
- {obsarray-1.0.2 → obsarray-1.0.3}/obsarray/templater/dswriter.py +0 -0
- {obsarray-1.0.2 → obsarray-1.0.3}/obsarray/templater/template_util.py +0 -0
- {obsarray-1.0.2 → obsarray-1.0.3}/obsarray/templater/tests/__init__.py +0 -0
- {obsarray-1.0.2 → obsarray-1.0.3}/obsarray/templater/tests/test_dataset_util.py +0 -0
- {obsarray-1.0.2 → obsarray-1.0.3}/obsarray/templater/tests/test_dswriter.py +0 -0
- {obsarray-1.0.2 → obsarray-1.0.3}/obsarray/templater/tests/test_template_util.py +0 -0
- {obsarray-1.0.2 → obsarray-1.0.3}/obsarray/test/__init__.py +0 -0
- {obsarray-1.0.2 → obsarray-1.0.3}/obsarray/test/test_err_corr_forms.py +0 -0
- {obsarray-1.0.2 → obsarray-1.0.3}/obsarray/test/test_flag_accessor.py +0 -0
- {obsarray-1.0.2 → obsarray-1.0.3}/obsarray.egg-info/dependency_links.txt +0 -0
- {obsarray-1.0.2 → obsarray-1.0.3}/obsarray.egg-info/requires.txt +0 -0
- {obsarray-1.0.2 → obsarray-1.0.3}/obsarray.egg-info/top_level.txt +0 -0
- {obsarray-1.0.2 → obsarray-1.0.3}/pyproject.toml +0 -0
- {obsarray-1.0.2 → obsarray-1.0.3}/setup.cfg +0 -0
- {obsarray-1.0.2 → obsarray-1.0.3}/setup.py +0 -0
|
@@ -9,6 +9,7 @@ from obsarray.err_corr import err_corr_forms
|
|
|
9
9
|
from obsarray.templater.template_util import create_ds
|
|
10
10
|
from obsarray.templater.dstemplater import DSTemplater
|
|
11
11
|
from obsarray.templater.dswriter import DSWriter
|
|
12
|
+
from obsarray.utils import append_names
|
|
12
13
|
|
|
13
14
|
__version__ = get_versions()["version"]
|
|
14
15
|
del get_versions
|
|
@@ -8,11 +8,11 @@ import json
|
|
|
8
8
|
|
|
9
9
|
version_json = '''
|
|
10
10
|
{
|
|
11
|
-
"date": "2025-
|
|
11
|
+
"date": "2025-06-22T11:46:36+0200",
|
|
12
12
|
"dirty": false,
|
|
13
13
|
"error": null,
|
|
14
|
-
"full-revisionid": "
|
|
15
|
-
"version": "1.0.
|
|
14
|
+
"full-revisionid": "48598121962220e8e42df0515693a450e732585c",
|
|
15
|
+
"version": "1.0.3"
|
|
16
16
|
}
|
|
17
17
|
''' # END VERSION_JSON
|
|
18
18
|
|
|
@@ -194,12 +194,12 @@ class FlagVariable:
|
|
|
194
194
|
)
|
|
195
195
|
|
|
196
196
|
if flag_meaning not in flag_meanings:
|
|
197
|
-
self._obj[
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
197
|
+
self._obj[
|
|
198
|
+
self._flag_var_name
|
|
199
|
+
].attrs = DatasetUtil.add_flag_meaning_to_attrs(
|
|
200
|
+
self._obj[self._flag_var_name].attrs,
|
|
201
|
+
flag_meaning,
|
|
202
|
+
self._obj[self._flag_var_name].dtype,
|
|
203
203
|
)
|
|
204
204
|
|
|
205
205
|
self[flag_meaning][:] = flag_value
|
|
@@ -507,7 +507,7 @@ class DatasetUtil:
|
|
|
507
507
|
ds[flag_meaning] = DatasetUtil.create_variable(
|
|
508
508
|
list(da.shape), bool, dim_names=list(da.dims)
|
|
509
509
|
)
|
|
510
|
-
ds[flag_meaning] = (da & flag_mask).astype(bool)
|
|
510
|
+
ds[flag_meaning] = (da.astype(int) & flag_mask).astype(bool)
|
|
511
511
|
|
|
512
512
|
return ds
|
|
513
513
|
|
|
@@ -34,7 +34,7 @@ def compare_err_corr_form(self, form, exp_form):
|
|
|
34
34
|
self.assertCountEqual(form._unc_var_name, exp_form._unc_var_name)
|
|
35
35
|
|
|
36
36
|
|
|
37
|
-
def create_ds():
|
|
37
|
+
def create_ds(var_suffix="", dim_suffix="", coord_dim_suffix_extra=""):
|
|
38
38
|
np.random.seed(0)
|
|
39
39
|
temperature = 15 + 8 * np.random.randn(2, 2, 3)
|
|
40
40
|
u_r_temperature = temperature * 0.02
|
|
@@ -47,42 +47,59 @@ def create_ds():
|
|
|
47
47
|
reference_time = pd.Timestamp("2014-09-05")
|
|
48
48
|
|
|
49
49
|
ds = xr.Dataset(
|
|
50
|
-
data_vars=
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
50
|
+
data_vars={
|
|
51
|
+
"temperature"
|
|
52
|
+
+ var_suffix: (
|
|
53
|
+
[
|
|
54
|
+
"x" + dim_suffix,
|
|
55
|
+
"y" + dim_suffix,
|
|
56
|
+
"time" + dim_suffix + coord_dim_suffix_extra,
|
|
57
|
+
],
|
|
58
|
+
temperature,
|
|
59
|
+
{"units": "K"},
|
|
60
|
+
),
|
|
61
|
+
},
|
|
62
|
+
coords={
|
|
63
|
+
"lon" + var_suffix: (["x" + dim_suffix, "y" + dim_suffix], lon),
|
|
64
|
+
"lat" + var_suffix: (["x" + dim_suffix, "y" + dim_suffix], lat),
|
|
65
|
+
"time" + var_suffix: ("time" + dim_suffix + coord_dim_suffix_extra, time),
|
|
66
|
+
"reference_time": reference_time,
|
|
67
|
+
},
|
|
59
68
|
attrs=dict(description="Weather related data."),
|
|
60
69
|
)
|
|
61
70
|
|
|
62
|
-
ds.unc["temperature"]["u_ran_temperature"] = (
|
|
63
|
-
[
|
|
71
|
+
ds.unc["temperature" + var_suffix]["u_ran_temperature" + var_suffix] = (
|
|
72
|
+
[
|
|
73
|
+
"x" + dim_suffix,
|
|
74
|
+
"y" + dim_suffix,
|
|
75
|
+
"time" + dim_suffix + coord_dim_suffix_extra,
|
|
76
|
+
],
|
|
64
77
|
temperature * 0.05,
|
|
65
78
|
{"units": "K", "pdf_shape": "gaussian"},
|
|
66
79
|
)
|
|
67
80
|
|
|
68
|
-
ds.unc["temperature"]["u_sys_temperature"] = (
|
|
69
|
-
[
|
|
81
|
+
ds.unc["temperature" + var_suffix]["u_sys_temperature" + var_suffix] = (
|
|
82
|
+
[
|
|
83
|
+
"x" + dim_suffix,
|
|
84
|
+
"y" + dim_suffix,
|
|
85
|
+
"time" + dim_suffix + coord_dim_suffix_extra,
|
|
86
|
+
],
|
|
70
87
|
temperature * 0.03,
|
|
71
88
|
{
|
|
72
89
|
"units": "K",
|
|
73
90
|
"err_corr": [
|
|
74
91
|
{
|
|
75
|
-
"dim": "x",
|
|
92
|
+
"dim": "x" + dim_suffix,
|
|
76
93
|
"form": "systematic",
|
|
77
94
|
"params": [],
|
|
78
95
|
},
|
|
79
96
|
{
|
|
80
|
-
"dim": "y",
|
|
97
|
+
"dim": "y" + dim_suffix,
|
|
81
98
|
"form": "systematic",
|
|
82
99
|
"params": [],
|
|
83
100
|
},
|
|
84
101
|
{
|
|
85
|
-
"dim": "time",
|
|
102
|
+
"dim": "time" + dim_suffix + coord_dim_suffix_extra,
|
|
86
103
|
"form": "systematic",
|
|
87
104
|
"params": [],
|
|
88
105
|
},
|
|
@@ -91,19 +108,26 @@ def create_ds():
|
|
|
91
108
|
},
|
|
92
109
|
)
|
|
93
110
|
|
|
94
|
-
ds.unc["temperature"]["u_str_temperature"] = (
|
|
95
|
-
[
|
|
111
|
+
ds.unc["temperature" + var_suffix]["u_str_temperature" + var_suffix] = (
|
|
112
|
+
[
|
|
113
|
+
"x" + dim_suffix,
|
|
114
|
+
"y" + dim_suffix,
|
|
115
|
+
"time" + dim_suffix + coord_dim_suffix_extra,
|
|
116
|
+
],
|
|
96
117
|
temperature * 0.1,
|
|
97
118
|
{
|
|
98
119
|
"units": "K",
|
|
99
120
|
"err_corr": [
|
|
100
121
|
{
|
|
101
|
-
"dim": [
|
|
122
|
+
"dim": [
|
|
123
|
+
"x" + dim_suffix,
|
|
124
|
+
"time" + dim_suffix + coord_dim_suffix_extra,
|
|
125
|
+
],
|
|
102
126
|
"form": "err_corr_matrix",
|
|
103
|
-
"params": ["err_corr_str_temperature"],
|
|
127
|
+
"params": ["err_corr_str_temperature" + var_suffix],
|
|
104
128
|
},
|
|
105
129
|
{
|
|
106
|
-
"dim": "y",
|
|
130
|
+
"dim": "y" + dim_suffix,
|
|
107
131
|
"form": "systematic",
|
|
108
132
|
"params": [],
|
|
109
133
|
},
|
|
@@ -112,8 +136,8 @@ def create_ds():
|
|
|
112
136
|
},
|
|
113
137
|
)
|
|
114
138
|
|
|
115
|
-
ds["err_corr_str_temperature"] = (
|
|
116
|
-
["x.time", "x.time"],
|
|
139
|
+
ds["err_corr_str_temperature" + var_suffix] = (
|
|
140
|
+
["x.time" + dim_suffix, "x.time" + dim_suffix],
|
|
117
141
|
np.ones(
|
|
118
142
|
(
|
|
119
143
|
temperature.shape[0] * temperature.shape[2],
|
|
@@ -740,6 +764,44 @@ class TestUncertainty(unittest.TestCase):
|
|
|
740
764
|
exp_ecm = xr.DataArray(np.ones((12, 12)), dims=["x.y.time", "x.y.time"])
|
|
741
765
|
xr.testing.assert_equal(ecm, exp_ecm)
|
|
742
766
|
|
|
767
|
+
def test_rename_vars(self):
|
|
768
|
+
var_suffix = "_test"
|
|
769
|
+
input_ds = create_ds()
|
|
770
|
+
|
|
771
|
+
ds = input_ds.unc.rename(
|
|
772
|
+
{
|
|
773
|
+
"temperature": "temperature" + var_suffix,
|
|
774
|
+
"lon": "lon" + var_suffix,
|
|
775
|
+
"lat": "lat" + var_suffix,
|
|
776
|
+
"time": "time" + var_suffix,
|
|
777
|
+
"u_ran_temperature": "u_ran_temperature" + var_suffix,
|
|
778
|
+
"u_str_temperature": "u_str_temperature" + var_suffix,
|
|
779
|
+
"u_sys_temperature": "u_sys_temperature" + var_suffix,
|
|
780
|
+
"err_corr_str_temperature": "err_corr_str_temperature" + var_suffix,
|
|
781
|
+
}
|
|
782
|
+
)
|
|
783
|
+
|
|
784
|
+
exp_ds = create_ds(var_suffix=var_suffix, coord_dim_suffix_extra=var_suffix)
|
|
785
|
+
|
|
786
|
+
xr.testing.assert_identical(ds, exp_ds)
|
|
787
|
+
|
|
788
|
+
def test_rename_dims(self):
|
|
789
|
+
dim_suffix = "_test"
|
|
790
|
+
input_ds = create_ds()
|
|
791
|
+
|
|
792
|
+
ds = input_ds.unc.rename_dims(
|
|
793
|
+
{
|
|
794
|
+
"x": "x" + dim_suffix,
|
|
795
|
+
"y": "y" + dim_suffix,
|
|
796
|
+
"time": "time" + dim_suffix,
|
|
797
|
+
"x.time": "x.time_test",
|
|
798
|
+
}
|
|
799
|
+
)
|
|
800
|
+
|
|
801
|
+
exp_ds = create_ds(dim_suffix=dim_suffix)
|
|
802
|
+
|
|
803
|
+
xr.testing.assert_identical(ds, exp_ds)
|
|
804
|
+
|
|
743
805
|
|
|
744
806
|
if __name__ == "__main__":
|
|
745
807
|
unittest.main()
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
"""test_utils - tests for obsarray.utils"""
|
|
2
|
+
|
|
3
|
+
import unittest
|
|
4
|
+
import numpy as np
|
|
5
|
+
from obsarray import append_names, create_ds
|
|
6
|
+
import xarray as xr
|
|
7
|
+
|
|
8
|
+
__author__ = "Sam Hunt <sam.hunt@npl.co.uk>"
|
|
9
|
+
__all__ = []
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def create_test_ds(suffix):
|
|
13
|
+
# define ds variables
|
|
14
|
+
template = {
|
|
15
|
+
"temperature"
|
|
16
|
+
+ suffix: {
|
|
17
|
+
"dtype": np.float32,
|
|
18
|
+
"dim": ["x" + suffix, "y" + suffix, "time" + suffix],
|
|
19
|
+
"attributes": {
|
|
20
|
+
"units": "K",
|
|
21
|
+
"unc_comps": [
|
|
22
|
+
"u_ran_temperature" + suffix,
|
|
23
|
+
"u_sys_temperature" + suffix,
|
|
24
|
+
],
|
|
25
|
+
},
|
|
26
|
+
},
|
|
27
|
+
"u_ran_temperature"
|
|
28
|
+
+ suffix: {
|
|
29
|
+
"dtype": np.float32,
|
|
30
|
+
"dim": ["x" + suffix, "y" + suffix, "time" + suffix],
|
|
31
|
+
"attributes": {
|
|
32
|
+
"units": "K",
|
|
33
|
+
"err_corr": [
|
|
34
|
+
{"dim": "x" + suffix, "form": "random", "params": [], "units": []},
|
|
35
|
+
{"dim": "y" + suffix, "form": "random", "params": [], "units": []},
|
|
36
|
+
{
|
|
37
|
+
"dim": "time" + suffix,
|
|
38
|
+
"form": "random",
|
|
39
|
+
"params": [],
|
|
40
|
+
"units": [],
|
|
41
|
+
},
|
|
42
|
+
],
|
|
43
|
+
},
|
|
44
|
+
},
|
|
45
|
+
"u_sys_temperature"
|
|
46
|
+
+ suffix: {
|
|
47
|
+
"dtype": np.float32,
|
|
48
|
+
"dim": ["x" + suffix, "y" + suffix, "time" + suffix],
|
|
49
|
+
"attributes": {
|
|
50
|
+
"units": "K",
|
|
51
|
+
"err_corr": [
|
|
52
|
+
{
|
|
53
|
+
"dim": "x" + suffix,
|
|
54
|
+
"form": "systematic",
|
|
55
|
+
"params": [],
|
|
56
|
+
"units": [],
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
"dim": "y" + suffix,
|
|
60
|
+
"form": "systematic",
|
|
61
|
+
"params": [],
|
|
62
|
+
"units": [],
|
|
63
|
+
},
|
|
64
|
+
{
|
|
65
|
+
"dim": "time" + suffix,
|
|
66
|
+
"form": "systematic",
|
|
67
|
+
"params": [],
|
|
68
|
+
"units": [],
|
|
69
|
+
},
|
|
70
|
+
],
|
|
71
|
+
},
|
|
72
|
+
},
|
|
73
|
+
"pressure"
|
|
74
|
+
+ suffix: {
|
|
75
|
+
"dtype": np.float32,
|
|
76
|
+
"dim": ["x" + suffix, "y" + suffix, "time" + suffix],
|
|
77
|
+
"attributes": {"units": "Pa", "unc_comps": ["u_str_pressure" + suffix]},
|
|
78
|
+
},
|
|
79
|
+
"u_str_pressure"
|
|
80
|
+
+ suffix: {
|
|
81
|
+
"dtype": np.float32,
|
|
82
|
+
"dim": ["x" + suffix, "y" + suffix, "time" + suffix],
|
|
83
|
+
"attributes": {
|
|
84
|
+
"units": "Pa",
|
|
85
|
+
"err_corr": [
|
|
86
|
+
{"dim": "x" + suffix, "form": "random", "params": [], "units": []},
|
|
87
|
+
{
|
|
88
|
+
"dim": "y" + suffix,
|
|
89
|
+
"form": "err_corr_matrix",
|
|
90
|
+
"params": "err_corr_str_pressure_y",
|
|
91
|
+
"units": [],
|
|
92
|
+
},
|
|
93
|
+
{
|
|
94
|
+
"dim": "time" + suffix,
|
|
95
|
+
"form": "systematic",
|
|
96
|
+
"params": [],
|
|
97
|
+
"units": [],
|
|
98
|
+
},
|
|
99
|
+
],
|
|
100
|
+
},
|
|
101
|
+
},
|
|
102
|
+
"err_corr_str_pressure_y"
|
|
103
|
+
+ suffix: {
|
|
104
|
+
"dtype": np.float32,
|
|
105
|
+
"dim": ["y" + suffix, "y" + suffix],
|
|
106
|
+
"attributes": {"units": ""},
|
|
107
|
+
},
|
|
108
|
+
"n_moles"
|
|
109
|
+
+ suffix: {
|
|
110
|
+
"dtype": np.float32,
|
|
111
|
+
"dim": ["x" + suffix, "y" + suffix, "time" + suffix],
|
|
112
|
+
"attributes": {"units": "", "unc_comps": ["u_ran_n_moles" + suffix]},
|
|
113
|
+
},
|
|
114
|
+
"u_ran_n_moles"
|
|
115
|
+
+ suffix: {
|
|
116
|
+
"dtype": np.float32,
|
|
117
|
+
"dim": ["x" + suffix, "y" + suffix, "time" + suffix],
|
|
118
|
+
"attributes": {
|
|
119
|
+
"units": "",
|
|
120
|
+
"err_corr": [
|
|
121
|
+
{"dim": "x" + suffix, "form": "random", "params": [], "units": []},
|
|
122
|
+
{"dim": "y" + suffix, "form": "random", "params": [], "units": []},
|
|
123
|
+
{
|
|
124
|
+
"dim": "time" + suffix,
|
|
125
|
+
"form": "random",
|
|
126
|
+
"params": [],
|
|
127
|
+
"units": [],
|
|
128
|
+
},
|
|
129
|
+
],
|
|
130
|
+
},
|
|
131
|
+
},
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
# define dim_size_dict to specify size of arrays
|
|
135
|
+
dim_sizes = {"x" + suffix: 20, "y" + suffix: 30, "time" + suffix: 6}
|
|
136
|
+
|
|
137
|
+
# create dataset template
|
|
138
|
+
ds = create_ds(template, dim_sizes)
|
|
139
|
+
|
|
140
|
+
# populate with example data
|
|
141
|
+
ds["temperature" + suffix].values = 293 * np.ones((20, 30, 6))
|
|
142
|
+
ds["u_ran_temperature" + suffix].values = 1 * np.ones((20, 30, 6))
|
|
143
|
+
ds["u_sys_temperature" + suffix].values = 0.4 * np.ones((20, 30, 6))
|
|
144
|
+
ds["pressure" + suffix].values = 10**5 * np.ones((20, 30, 6))
|
|
145
|
+
ds["u_str_pressure" + suffix].values = 10 * np.ones((20, 30, 6))
|
|
146
|
+
ds["err_corr_str_pressure_y" + suffix].values = 0.5 * np.ones(
|
|
147
|
+
(30, 30)
|
|
148
|
+
) + 0.5 * np.eye(30)
|
|
149
|
+
ds["n_moles" + suffix].values = 40 * np.ones((20, 30, 6))
|
|
150
|
+
ds["u_ran_n_moles" + suffix].values = 1 * np.ones((20, 30, 6))
|
|
151
|
+
|
|
152
|
+
ds.attrs["attr" + suffix] = "val"
|
|
153
|
+
|
|
154
|
+
return ds
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
class TestAppendNames(unittest.TestCase):
|
|
158
|
+
def test_append_names(self):
|
|
159
|
+
|
|
160
|
+
input_ds = create_test_ds(suffix="")
|
|
161
|
+
ds = append_names(input_ds, "_test")
|
|
162
|
+
|
|
163
|
+
exp_ds = create_test_ds(suffix="_test")
|
|
164
|
+
|
|
165
|
+
xr.testing.assert_identical(ds, exp_ds)
|
|
166
|
+
|
|
167
|
+
|
|
168
|
+
if __name__ == "__main__":
|
|
169
|
+
unittest.main()
|
|
@@ -9,6 +9,7 @@ from obsarray.templater.template_util import create_var
|
|
|
9
9
|
from obsarray.templater.dataset_util import DatasetUtil
|
|
10
10
|
from obsarray.err_corr import err_corr_forms, BaseErrCorrForm
|
|
11
11
|
from obsarray.utils import empty_err_corr_matrix
|
|
12
|
+
from xarray.core.types import T_Dataset
|
|
12
13
|
|
|
13
14
|
|
|
14
15
|
__author__ = "Sam Hunt <sam.hunt@npl.co.uk>"
|
|
@@ -308,12 +309,24 @@ class Uncertainty:
|
|
|
308
309
|
]
|
|
309
310
|
):
|
|
310
311
|
if dim_err_corr[1].form in ["random", "systematic"]:
|
|
311
|
-
|
|
312
|
+
if isinstance(dim_err_corr[0], List):
|
|
313
|
+
for dim in dim_err_corr[0]:
|
|
314
|
+
err_corr_dict[dim] = dim_err_corr[1].form
|
|
315
|
+
|
|
316
|
+
else:
|
|
317
|
+
err_corr_dict[dim_err_corr[0]] = dim_err_corr[1].form
|
|
312
318
|
|
|
313
319
|
elif dim_err_corr[1].form == "err_corr_matrix":
|
|
314
|
-
|
|
315
|
-
dim_err_corr[
|
|
316
|
-
|
|
320
|
+
if isinstance(dim_err_corr[0], List):
|
|
321
|
+
for dim in dim_err_corr[0]:
|
|
322
|
+
err_corr_dict[dim] = self._obj[
|
|
323
|
+
dim_err_corr[1].params[0]
|
|
324
|
+
].values
|
|
325
|
+
|
|
326
|
+
else:
|
|
327
|
+
err_corr_dict[dim_err_corr[0]] = self._obj[
|
|
328
|
+
dim_err_corr[1].params[0]
|
|
329
|
+
].values
|
|
317
330
|
|
|
318
331
|
else:
|
|
319
332
|
raise NotImplementedError(
|
|
@@ -894,6 +907,88 @@ class UncAccessor(object):
|
|
|
894
907
|
del self._obj[unc_var]
|
|
895
908
|
self._obj[obs_var].attrs["unc_comps"].remove(unc_var)
|
|
896
909
|
|
|
910
|
+
def rename(self, vars_dict: dict[str, str]) -> T_Dataset:
|
|
911
|
+
"""
|
|
912
|
+
Returns a new dataset with renamed variables - safely handling `unc_vars` and related metadata
|
|
913
|
+
|
|
914
|
+
:param vars_dict: Dictionary whose keys are current variable names and whose values are the desired names. The desired names must not be the name of an existing dimension or Variable in the Dataset.
|
|
915
|
+
:returns: Dataset with renamed variables
|
|
916
|
+
"""
|
|
917
|
+
|
|
918
|
+
# handle case that xarray.Dataset.rename renames the dimension associated with a renamed coordinate dimension
|
|
919
|
+
coord_dim_dict = {
|
|
920
|
+
str(dim): vars_dict[dim]
|
|
921
|
+
for dim in self._obj.dims
|
|
922
|
+
if (dim in self._obj.coords) and (dim in vars_dict.keys())
|
|
923
|
+
}
|
|
924
|
+
ds = self.rename_dims(coord_dim_dict)
|
|
925
|
+
|
|
926
|
+
# update metadata where unc_var err corr param to be renamed
|
|
927
|
+
unc_var_paths = []
|
|
928
|
+
for obs_var in ds.unc.obs_vars:
|
|
929
|
+
for unc_var in ds.unc[obs_var]:
|
|
930
|
+
unc_var_paths.append((obs_var, unc_var._unc_var_name))
|
|
931
|
+
|
|
932
|
+
for unc_var_path in unc_var_paths:
|
|
933
|
+
unc_var_i = unc_var_path[1]
|
|
934
|
+
|
|
935
|
+
for attr in ds[unc_var_i].attrs.keys():
|
|
936
|
+
if (attr[:9] == "err_corr_") and (attr[-7:] == "_params"):
|
|
937
|
+
for i, param in enumerate(ds[unc_var_i].attrs[attr]):
|
|
938
|
+
if param in vars_dict.keys():
|
|
939
|
+
ds[unc_var_i].attrs[attr][i] = vars_dict[param]
|
|
940
|
+
|
|
941
|
+
# safely update unc_vars
|
|
942
|
+
for unc_var_path in unc_var_paths:
|
|
943
|
+
obs_var_i = unc_var_path[0]
|
|
944
|
+
unc_var_i = unc_var_path[1]
|
|
945
|
+
if unc_var_i in vars_dict:
|
|
946
|
+
ds = ds.unc[obs_var_i][unc_var_i].rename(vars_dict[unc_var_i])
|
|
947
|
+
|
|
948
|
+
# update remaining variable names
|
|
949
|
+
non_unc_var_names = list(
|
|
950
|
+
filter(lambda x: x not in self.unc_vars.keys(), self._obj.variables.keys())
|
|
951
|
+
)
|
|
952
|
+
var_dict_no_unc = {
|
|
953
|
+
n: vars_dict[n] for n in non_unc_var_names if n in vars_dict.keys()
|
|
954
|
+
}
|
|
955
|
+
ds = ds.rename(var_dict_no_unc)
|
|
956
|
+
|
|
957
|
+
return ds
|
|
958
|
+
|
|
959
|
+
def rename_dims(self, dims_dict: dict[str, str]) -> T_Dataset:
|
|
960
|
+
"""
|
|
961
|
+
Returns a new dataset with renamed dimensions - safely handling `unc_vars` related metadata
|
|
962
|
+
|
|
963
|
+
:param dims_dict: Dictionary whose keys are current dimension names and whose values are the desired names. The desired names must not be the name of an existing dimension or Variable in the Dataset.
|
|
964
|
+
:returns: Dataset with renamed dimensions
|
|
965
|
+
"""
|
|
966
|
+
|
|
967
|
+
# update dimension names
|
|
968
|
+
obj = self._obj.rename_dims(dims_dict)
|
|
969
|
+
|
|
970
|
+
# update uncertainty metadata related to variable names
|
|
971
|
+
unc_var_names = []
|
|
972
|
+
for obs_var in obj.unc.obs_vars:
|
|
973
|
+
for unc_var in obj.unc[obs_var]:
|
|
974
|
+
unc_var_names.append(unc_var._unc_var_name)
|
|
975
|
+
|
|
976
|
+
for unc_var_name in unc_var_names:
|
|
977
|
+
for attr in obj[unc_var_name].attrs.keys():
|
|
978
|
+
if (attr[:9] == "err_corr_") and (attr[-4:] == "_dim"):
|
|
979
|
+
if isinstance(obj[unc_var_name].attrs[attr], str):
|
|
980
|
+
if obj[unc_var_name].attrs[attr] in dims_dict:
|
|
981
|
+
obj[unc_var_name].attrs[attr] = dims_dict[
|
|
982
|
+
obj[unc_var_name].attrs[attr]
|
|
983
|
+
]
|
|
984
|
+
|
|
985
|
+
if isinstance(obj[unc_var_name].attrs[attr], list):
|
|
986
|
+
for i, attr_i in enumerate(obj[unc_var_name].attrs[attr]):
|
|
987
|
+
if attr_i in dims_dict:
|
|
988
|
+
obj[unc_var_name].attrs[attr][i] = dims_dict[attr_i]
|
|
989
|
+
|
|
990
|
+
return obj
|
|
991
|
+
|
|
897
992
|
|
|
898
993
|
if __name__ == "__main__":
|
|
899
994
|
pass
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
"""utils - utilities for obsarray"""
|
|
2
|
+
|
|
3
|
+
import numpy as np
|
|
4
|
+
import xarray as xr
|
|
5
|
+
from xarray.core.types import T_Dataset
|
|
6
|
+
|
|
7
|
+
__author__ = "Sam Hunt <sam.hunt@npl.co.uk>"
|
|
8
|
+
__all__ = ["empty_err_corr_matrix", "append_names"]
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def empty_err_corr_matrix(obs_var: xr.DataArray):
|
|
12
|
+
"""
|
|
13
|
+
Returns diagonal error correlation matrix for observation variable
|
|
14
|
+
|
|
15
|
+
:param obs_var: uncertainty variable
|
|
16
|
+
:return: diagonal error correlation matrix
|
|
17
|
+
"""
|
|
18
|
+
|
|
19
|
+
dim_names = [dim for dim in obs_var.dims]
|
|
20
|
+
dim_lens = [len(obs_var[dim]) for dim in dim_names]
|
|
21
|
+
|
|
22
|
+
n_elems = int(np.prod(dim_lens))
|
|
23
|
+
erc_dim_name = ".".join(dim_names)
|
|
24
|
+
|
|
25
|
+
err_corr_matrix = xr.DataArray(np.eye(n_elems), dims=[erc_dim_name, erc_dim_name])
|
|
26
|
+
|
|
27
|
+
return err_corr_matrix
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def append_names(
|
|
31
|
+
ds: T_Dataset,
|
|
32
|
+
suffix: str,
|
|
33
|
+
skip_vars: bool = False,
|
|
34
|
+
skip_dims: bool = False,
|
|
35
|
+
skip_attrs: bool = False,
|
|
36
|
+
) -> T_Dataset:
|
|
37
|
+
"""
|
|
38
|
+
Appends a suffix to the names of dataset variables, dimensions, and attributes - safely handling `unc_vars` and associated metadata
|
|
39
|
+
|
|
40
|
+
:param ds: xarray dataset
|
|
41
|
+
:param suffix: suffix to append to dataset variable, dimension, and attribute names
|
|
42
|
+
:param skip_vars: (default: `False`) switch to skip applying suffix to variable names
|
|
43
|
+
:param skip_dims: (default: `False`) switch to skip applying suffix to dimension names
|
|
44
|
+
:param skip_attrs: (default: `False`) switch to skip applying suffix to variable names
|
|
45
|
+
:returns: ds with suffix appended to names of variables, dimensions, attributes
|
|
46
|
+
"""
|
|
47
|
+
|
|
48
|
+
# update variable names
|
|
49
|
+
if not skip_vars:
|
|
50
|
+
var_rename = {var_name: var_name + suffix for var_name in ds.variables.keys()}
|
|
51
|
+
ds = ds.unc.rename(var_rename)
|
|
52
|
+
|
|
53
|
+
# update dimension names
|
|
54
|
+
if not skip_dims:
|
|
55
|
+
dim_rename = {dim_name: dim_name + suffix for dim_name in ds.dims.keys()}
|
|
56
|
+
ds = ds.unc.rename_dims(dim_rename)
|
|
57
|
+
|
|
58
|
+
# update attribute names
|
|
59
|
+
if not skip_attrs:
|
|
60
|
+
ds.attrs = {key + suffix: value for key, value in ds.attrs.items()}
|
|
61
|
+
|
|
62
|
+
return ds
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
if __name__ == "__main__":
|
|
66
|
+
pass
|