obsarray 1.0.2__py3-none-any.whl
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.
- docs/conf.py +181 -0
- notebook/test_register_err_corr_form.py +45 -0
- obsarray/__init__.py +14 -0
- obsarray/_version.py +21 -0
- obsarray/err_corr.py +298 -0
- obsarray/flag_accessor.py +442 -0
- obsarray/templater/__init__.py +0 -0
- obsarray/templater/dataset_util.py +659 -0
- obsarray/templater/dstemplater.py +133 -0
- obsarray/templater/dswriter.py +113 -0
- obsarray/templater/template_util.py +257 -0
- obsarray/templater/tests/__init__.py +0 -0
- obsarray/templater/tests/test_dataset_util.py +488 -0
- obsarray/templater/tests/test_dswriter.py +31 -0
- obsarray/templater/tests/test_template_util.py +334 -0
- obsarray/test/__init__.py +0 -0
- obsarray/test/test_err_corr_forms.py +251 -0
- obsarray/test/test_flag_accessor.py +373 -0
- obsarray/test/test_unc_accessor.py +745 -0
- obsarray/unc_accessor.py +899 -0
- obsarray/utils.py +31 -0
- obsarray-1.0.2.dist-info/METADATA +57 -0
- obsarray-1.0.2.dist-info/RECORD +26 -0
- obsarray-1.0.2.dist-info/WHEEL +5 -0
- obsarray-1.0.2.dist-info/licenses/LICENSE +165 -0
- obsarray-1.0.2.dist-info/top_level.txt +3 -0
|
@@ -0,0 +1,373 @@
|
|
|
1
|
+
"""test_flag_accessor - tests for obsarray.flag_accessor"""
|
|
2
|
+
|
|
3
|
+
from copy import deepcopy
|
|
4
|
+
import xarray as xr
|
|
5
|
+
import pandas as pd
|
|
6
|
+
import numpy as np
|
|
7
|
+
import unittest
|
|
8
|
+
from unittest.mock import patch
|
|
9
|
+
from obsarray.templater.template_util import create_var
|
|
10
|
+
import obsarray
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
__author__ = "Sam Hunt <sam.hunt@npl.co.uk>"
|
|
14
|
+
__all__ = []
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def create_ds():
|
|
18
|
+
np.random.seed(0)
|
|
19
|
+
temperature = 15 + 8 * np.random.randn(2, 2, 3)
|
|
20
|
+
lon = [[-99.83, -99.32], [-99.79, -99.23]]
|
|
21
|
+
lat = [[42.25, 42.21], [42.63, 42.59]]
|
|
22
|
+
time = pd.date_range("2014-09-06", periods=3)
|
|
23
|
+
reference_time = pd.Timestamp("2014-09-05")
|
|
24
|
+
|
|
25
|
+
ds = xr.Dataset(
|
|
26
|
+
data_vars=dict(
|
|
27
|
+
temperature=(["x", "y", "time"], temperature, {"units": "K"}),
|
|
28
|
+
precipitation=(["x", "y", "time"], temperature, {"units": "K"}),
|
|
29
|
+
),
|
|
30
|
+
coords=dict(
|
|
31
|
+
lon=(["x", "y"], lon),
|
|
32
|
+
lat=(["x", "y"], lat),
|
|
33
|
+
time=time,
|
|
34
|
+
reference_time=reference_time,
|
|
35
|
+
),
|
|
36
|
+
attrs=dict(description="Weather related data."),
|
|
37
|
+
)
|
|
38
|
+
|
|
39
|
+
ds["temperature_flags"] = create_var(
|
|
40
|
+
"temperature_flags",
|
|
41
|
+
{
|
|
42
|
+
"dtype": "flag",
|
|
43
|
+
"dim": ["x", "y", "time"],
|
|
44
|
+
"attributes": {
|
|
45
|
+
"flag_meanings": ["bad_data", "dubious_data"],
|
|
46
|
+
"applicable_vars": ["temperature"],
|
|
47
|
+
},
|
|
48
|
+
},
|
|
49
|
+
{"x": 2, "y": 2, "time": 3},
|
|
50
|
+
)
|
|
51
|
+
|
|
52
|
+
ds["general_flags"] = create_var(
|
|
53
|
+
"general_flags",
|
|
54
|
+
{
|
|
55
|
+
"dtype": "flag",
|
|
56
|
+
"dim": ["x", "y", "time"],
|
|
57
|
+
"attributes": {"flag_meanings": []},
|
|
58
|
+
},
|
|
59
|
+
{"x": 2, "y": 2, "time": 3},
|
|
60
|
+
)
|
|
61
|
+
|
|
62
|
+
ds["time_flags"] = create_var(
|
|
63
|
+
"time_flags",
|
|
64
|
+
{
|
|
65
|
+
"dtype": "flag",
|
|
66
|
+
"dim": ["time"],
|
|
67
|
+
"attributes": {"flag_meanings": ["dubious", "invalid"]},
|
|
68
|
+
},
|
|
69
|
+
{"time": 3},
|
|
70
|
+
)
|
|
71
|
+
|
|
72
|
+
return ds
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
class TestFlagAccessor(unittest.TestCase):
|
|
76
|
+
def setUp(self):
|
|
77
|
+
self.ds = create_ds()
|
|
78
|
+
|
|
79
|
+
def test___getitem__(self):
|
|
80
|
+
self.assertIsInstance(
|
|
81
|
+
self.ds.flag["general_flag"], obsarray.flag_accessor.FlagVariable
|
|
82
|
+
)
|
|
83
|
+
self.assertEqual(self.ds.flag["general_flag"]._flag_var_name, "general_flag")
|
|
84
|
+
|
|
85
|
+
def test___len__(self):
|
|
86
|
+
self.assertEqual(len(self.ds.flag), 3)
|
|
87
|
+
|
|
88
|
+
def test___iter__(self):
|
|
89
|
+
|
|
90
|
+
var_names = []
|
|
91
|
+
for flag in self.ds.flag:
|
|
92
|
+
self.assertIsInstance(flag, obsarray.flag_accessor.FlagVariable)
|
|
93
|
+
var_names.append(flag._flag_var_name)
|
|
94
|
+
|
|
95
|
+
self.assertCountEqual(
|
|
96
|
+
var_names, ["temperature_flags", "general_flags", "time_flags"]
|
|
97
|
+
)
|
|
98
|
+
|
|
99
|
+
def test_keys(self):
|
|
100
|
+
self.assertCountEqual(
|
|
101
|
+
self.ds.flag.keys(), ["temperature_flags", "general_flags", "time_flags"]
|
|
102
|
+
)
|
|
103
|
+
|
|
104
|
+
def test__is_data_var_true(self):
|
|
105
|
+
self.assertTrue(self.ds.flag._is_data_var("temperature"))
|
|
106
|
+
|
|
107
|
+
def test__is_data_var_false(self):
|
|
108
|
+
self.assertFalse(self.ds.flag._is_data_var("temperature_flags"))
|
|
109
|
+
|
|
110
|
+
def test_data_vars(self):
|
|
111
|
+
data_vars = self.ds.flag.data_vars
|
|
112
|
+
self.assertEqual(type(data_vars), xr.core.dataset.DataVariables)
|
|
113
|
+
self.assertCountEqual(
|
|
114
|
+
list(data_vars.variables), ["temperature", "precipitation"]
|
|
115
|
+
)
|
|
116
|
+
|
|
117
|
+
def test_flag_vars(self):
|
|
118
|
+
flag_vars = self.ds.flag.flag_vars
|
|
119
|
+
self.assertEqual(type(flag_vars), xr.core.dataset.DataVariables)
|
|
120
|
+
self.assertCountEqual(
|
|
121
|
+
list(flag_vars.variables),
|
|
122
|
+
["temperature_flags", "general_flags", "time_flags"],
|
|
123
|
+
)
|
|
124
|
+
|
|
125
|
+
def test__is_flag_var_true(self):
|
|
126
|
+
self.assertTrue(self.ds.flag._is_flag_var("temperature_flags"))
|
|
127
|
+
|
|
128
|
+
def test__is_flag_var_false(self):
|
|
129
|
+
self.assertFalse(self.ds.flag._is_flag_var("temperature"))
|
|
130
|
+
|
|
131
|
+
def test___setitem___DataArray(self):
|
|
132
|
+
new_flag = xr.DataArray(
|
|
133
|
+
np.zeros(self.ds.precipitation.shape),
|
|
134
|
+
dims=["x", "y", "time"],
|
|
135
|
+
attrs={"flag_meanings": "test"},
|
|
136
|
+
)
|
|
137
|
+
|
|
138
|
+
self.ds.flag["new_flag"] = new_flag
|
|
139
|
+
|
|
140
|
+
self.assertEqual(self.ds.new_flag.attrs["flag_meanings"], "test")
|
|
141
|
+
self.assertEqual(self.ds.new_flag.attrs["flag_masks"], "1")
|
|
142
|
+
|
|
143
|
+
np.testing.assert_array_equal(new_flag.values, self.ds.new_flag.values)
|
|
144
|
+
|
|
145
|
+
def test___setitem___DataArray_nomeanings(self):
|
|
146
|
+
new_flag = xr.DataArray(
|
|
147
|
+
np.zeros(self.ds.precipitation.shape), dims=["x", "y", "time"], attrs={}
|
|
148
|
+
)
|
|
149
|
+
|
|
150
|
+
self.ds.flag["new_flag"] = new_flag
|
|
151
|
+
|
|
152
|
+
self.assertEqual(self.ds.new_flag.attrs["flag_meanings"], "")
|
|
153
|
+
self.assertEqual(self.ds.new_flag.attrs["flag_masks"], "")
|
|
154
|
+
|
|
155
|
+
np.testing.assert_array_equal(new_flag.values, self.ds.new_flag.values)
|
|
156
|
+
|
|
157
|
+
@patch("obsarray.flag_accessor.create_var")
|
|
158
|
+
def test___setitem___tuple(self, mock):
|
|
159
|
+
|
|
160
|
+
flag_def = (
|
|
161
|
+
["x", "y", "time"],
|
|
162
|
+
{"flag_meanings": ["flag1", "flag2", "flag3"]},
|
|
163
|
+
)
|
|
164
|
+
self.ds.flag["new_flag"] = flag_def
|
|
165
|
+
|
|
166
|
+
mock.assert_called_once_with(
|
|
167
|
+
"new_flag",
|
|
168
|
+
{
|
|
169
|
+
"dtype": "flag",
|
|
170
|
+
"dim": ["x", "y", "time"],
|
|
171
|
+
"attributes": {"flag_meanings": ["flag1", "flag2", "flag3"]},
|
|
172
|
+
},
|
|
173
|
+
{"x": 2, "y": 2, "time": 3},
|
|
174
|
+
)
|
|
175
|
+
|
|
176
|
+
self.assertTrue(("new_flag" in self.ds))
|
|
177
|
+
|
|
178
|
+
|
|
179
|
+
class TestFlagVariable(unittest.TestCase):
|
|
180
|
+
def setUp(self):
|
|
181
|
+
self.ds = create_ds()
|
|
182
|
+
|
|
183
|
+
def test___getitem__(self):
|
|
184
|
+
self.assertIsInstance(
|
|
185
|
+
self.ds.flag["temperature_flags"]["bad_data"],
|
|
186
|
+
obsarray.flag_accessor.Flag,
|
|
187
|
+
)
|
|
188
|
+
self.assertEqual(
|
|
189
|
+
self.ds.flag["temperature_flags"]["bad_data"]._flag_var_name,
|
|
190
|
+
"temperature_flags",
|
|
191
|
+
)
|
|
192
|
+
self.assertEqual(
|
|
193
|
+
self.ds.flag["temperature_flags"]["bad_data"]._flag_meaning,
|
|
194
|
+
"bad_data",
|
|
195
|
+
)
|
|
196
|
+
|
|
197
|
+
@patch("obsarray.flag_accessor.Flag.__setitem__")
|
|
198
|
+
@patch("obsarray.flag_accessor.DatasetUtil.add_flag_meaning_to_attrs")
|
|
199
|
+
def test___setitem___existing_mask(self, mdu, mf):
|
|
200
|
+
self.ds.flag["temperature_flags"]["bad_data"] = True
|
|
201
|
+
mdu.assert_not_called()
|
|
202
|
+
mf.assert_called_with(slice(None, None, None), True)
|
|
203
|
+
|
|
204
|
+
@patch("obsarray.flag_accessor.Flag.__setitem__")
|
|
205
|
+
@patch("obsarray.flag_accessor.DatasetUtil.add_flag_meaning_to_attrs")
|
|
206
|
+
def test___setitem___new_mask_1d(self, mdu, mf):
|
|
207
|
+
original_attrs = deepcopy(self.ds["time_flags"].attrs)
|
|
208
|
+
|
|
209
|
+
self.ds.flag["time_flags"]["test_flag"] = True
|
|
210
|
+
|
|
211
|
+
mdu.assert_called_once_with(
|
|
212
|
+
original_attrs, "test_flag", self.ds["time_flags"].dtype
|
|
213
|
+
)
|
|
214
|
+
|
|
215
|
+
self.assertDictEqual(self.ds["time_flags"].attrs, {})
|
|
216
|
+
|
|
217
|
+
mf.assert_called_with(slice(None, None, None), True)
|
|
218
|
+
|
|
219
|
+
@patch("obsarray.flag_accessor.Flag.__setitem__")
|
|
220
|
+
@patch("obsarray.flag_accessor.DatasetUtil.add_flag_meaning_to_attrs")
|
|
221
|
+
def test___setitem___new_mask(self, mdu, mf):
|
|
222
|
+
original_attrs = deepcopy(self.ds["temperature_flags"].attrs)
|
|
223
|
+
|
|
224
|
+
self.ds.flag["temperature_flags"]["test_flag"] = True
|
|
225
|
+
|
|
226
|
+
mdu.assert_called_once_with(
|
|
227
|
+
original_attrs, "test_flag", self.ds["temperature_flags"].dtype
|
|
228
|
+
)
|
|
229
|
+
|
|
230
|
+
self.assertDictEqual(self.ds["temperature_flags"].attrs, {})
|
|
231
|
+
|
|
232
|
+
mf.assert_called_with(slice(None, None, None), True)
|
|
233
|
+
|
|
234
|
+
@patch("obsarray.flag_accessor.Flag.__setitem__")
|
|
235
|
+
@patch("obsarray.flag_accessor.DatasetUtil.add_flag_meaning_to_attrs")
|
|
236
|
+
def test___setitem___new_mask(self, mdu, mf):
|
|
237
|
+
|
|
238
|
+
original_attrs = deepcopy(self.ds["temperature_flags"].attrs)
|
|
239
|
+
|
|
240
|
+
self.ds.flag["temperature_flags"]["test_flag"] = True
|
|
241
|
+
|
|
242
|
+
mdu.assert_called_once_with(
|
|
243
|
+
original_attrs, "test_flag", self.ds["temperature_flags"].dtype
|
|
244
|
+
)
|
|
245
|
+
|
|
246
|
+
self.assertDictEqual(self.ds["temperature_flags"].attrs, {})
|
|
247
|
+
|
|
248
|
+
mf.assert_called_with(slice(None, None, None), True)
|
|
249
|
+
|
|
250
|
+
@patch("obsarray.flag_accessor.Flag.__setitem__")
|
|
251
|
+
@patch("obsarray.flag_accessor.DatasetUtil.rm_flag_meaning_from_attrs")
|
|
252
|
+
def test___delitem__(self, mdu, mf):
|
|
253
|
+
original_attrs = deepcopy(self.ds["temperature_flags"].attrs)
|
|
254
|
+
|
|
255
|
+
del self.ds.flag["temperature_flags"]["dubious_data"]
|
|
256
|
+
|
|
257
|
+
mdu.assert_called_once_with(original_attrs, "dubious_data")
|
|
258
|
+
|
|
259
|
+
self.assertDictEqual(self.ds["temperature_flags"].attrs, {})
|
|
260
|
+
|
|
261
|
+
mf.assert_called_with(slice(None, None, None), False)
|
|
262
|
+
|
|
263
|
+
def test___len__(self):
|
|
264
|
+
self.assertEqual(len(self.ds.flag["temperature_flags"]), 2)
|
|
265
|
+
|
|
266
|
+
def test___iter__(self):
|
|
267
|
+
|
|
268
|
+
var_names = []
|
|
269
|
+
for flag in self.ds.flag["temperature_flags"]:
|
|
270
|
+
self.assertIsInstance(flag, obsarray.flag_accessor.Flag)
|
|
271
|
+
var_names.append(flag._flag_meaning)
|
|
272
|
+
|
|
273
|
+
self.assertCountEqual(var_names, ["bad_data", "dubious_data"])
|
|
274
|
+
|
|
275
|
+
def test_keys(self):
|
|
276
|
+
self.assertCountEqual(
|
|
277
|
+
self.ds.flag["temperature_flags"].keys(),
|
|
278
|
+
["bad_data", "dubious_data"],
|
|
279
|
+
)
|
|
280
|
+
|
|
281
|
+
|
|
282
|
+
class TestFlag(unittest.TestCase):
|
|
283
|
+
def setUp(self):
|
|
284
|
+
self.ds = create_ds()
|
|
285
|
+
|
|
286
|
+
@patch("obsarray.flag_accessor.Flag._expand_sli", return_value="slice")
|
|
287
|
+
def test___getitem__(self, m):
|
|
288
|
+
self.assertEqual(
|
|
289
|
+
self.ds.flag["temperature_flags"]["bad_data"]["in_slice"]._sli, "slice"
|
|
290
|
+
)
|
|
291
|
+
|
|
292
|
+
m.assert_called_with("in_slice")
|
|
293
|
+
|
|
294
|
+
def test_expand_slice_1d_full(self):
|
|
295
|
+
sli = self.ds.flag["time_flags"]["dubious"]._expand_sli((1))
|
|
296
|
+
self.assertEqual((1,), sli)
|
|
297
|
+
|
|
298
|
+
def test_expand_slice_1d_None(self):
|
|
299
|
+
sli = self.ds.flag["time_flags"]["dubious"]._expand_sli()
|
|
300
|
+
self.assertEqual((slice(None),), sli)
|
|
301
|
+
|
|
302
|
+
def test_expand_slice_full(self):
|
|
303
|
+
sli = self.ds.flag["temperature_flags"]["bad_data"]._expand_sli((1, 1, 1))
|
|
304
|
+
self.assertEqual((1, 1, 1), sli)
|
|
305
|
+
|
|
306
|
+
def test_expand_slice_None(self):
|
|
307
|
+
sli = self.ds.flag["temperature_flags"]["bad_data"]._expand_sli()
|
|
308
|
+
self.assertEqual((slice(None), slice(None), slice(None)), sli)
|
|
309
|
+
|
|
310
|
+
def test_expand_slice_first(self):
|
|
311
|
+
sli = self.ds.flag["temperature_flags"]["bad_data"]._expand_sli((0,))
|
|
312
|
+
self.assertEqual((0, slice(None), slice(None)), sli)
|
|
313
|
+
|
|
314
|
+
def test__setitem___1element_False2True(self):
|
|
315
|
+
self.ds["temperature_flags"].values[:] = 0
|
|
316
|
+
|
|
317
|
+
self.ds.flag["temperature_flags"]["bad_data"][0, 0, 0] = True
|
|
318
|
+
|
|
319
|
+
exp_flags = np.array([[[1, 0, 0], [0, 0, 0]], [[0, 0, 0], [0, 0, 0]]])
|
|
320
|
+
|
|
321
|
+
np.testing.assert_array_equal(self.ds["temperature_flags"].values, exp_flags)
|
|
322
|
+
|
|
323
|
+
def test__setitem___False2True(self):
|
|
324
|
+
self.ds.flag["temperature_flags"]["bad_data"][:, 0, :] = True
|
|
325
|
+
|
|
326
|
+
exp_flags = np.array([[[1, 1, 1], [0, 0, 0]], [[1, 1, 1], [0, 0, 0]]])
|
|
327
|
+
|
|
328
|
+
np.testing.assert_array_equal(self.ds["temperature_flags"].values, exp_flags)
|
|
329
|
+
|
|
330
|
+
def test__setitem___True2False(self):
|
|
331
|
+
|
|
332
|
+
self.ds["temperature_flags"].values[:] = 1
|
|
333
|
+
|
|
334
|
+
self.ds.flag["temperature_flags"]["bad_data"][:, 1, :] = False
|
|
335
|
+
|
|
336
|
+
exp_flags = np.array([[[1, 1, 1], [0, 0, 0]], [[1, 1, 1], [0, 0, 0]]])
|
|
337
|
+
|
|
338
|
+
np.testing.assert_array_equal(self.ds["temperature_flags"].values, exp_flags)
|
|
339
|
+
|
|
340
|
+
def test__setitem___array(self):
|
|
341
|
+
self.ds["temperature_flags"].values[:] = np.array(
|
|
342
|
+
[[[1, 1, 1], [0, 0, 0]], [[1, 1, 1], [0, 0, 0]]]
|
|
343
|
+
)
|
|
344
|
+
|
|
345
|
+
self.ds.flag["temperature_flags"]["bad_data"][:, :, 0] = np.array(
|
|
346
|
+
[[False, True], [False, True]]
|
|
347
|
+
)
|
|
348
|
+
|
|
349
|
+
exp_flags = np.array([[[0, 1, 1], [1, 0, 0]], [[0, 1, 1], [1, 0, 0]]])
|
|
350
|
+
|
|
351
|
+
np.testing.assert_array_equal(self.ds["temperature_flags"].values, exp_flags)
|
|
352
|
+
|
|
353
|
+
def test__setitem___array_not_bool(self):
|
|
354
|
+
self.assertRaises(
|
|
355
|
+
TypeError,
|
|
356
|
+
self.ds.flag["temperature_flags"]["bad_data"],
|
|
357
|
+
slice(None, None, 0),
|
|
358
|
+
np.array([[0.0, 1.0], [0.0, 1.0]]),
|
|
359
|
+
)
|
|
360
|
+
|
|
361
|
+
def test_value(self):
|
|
362
|
+
self.ds["temperature_flags"].values[:] = np.array(
|
|
363
|
+
[[[1, 1, 1], [0, 0, 0]], [[1, 1, 1], [0, 0, 0]]]
|
|
364
|
+
)
|
|
365
|
+
|
|
366
|
+
mask = self.ds.flag["temperature_flags"]["bad_data"][:, :, 0].value
|
|
367
|
+
exp_mask = np.array([[True, False], [True, False]])
|
|
368
|
+
|
|
369
|
+
np.testing.assert_array_equal(mask, exp_mask)
|
|
370
|
+
|
|
371
|
+
|
|
372
|
+
if __name__ == "__main__":
|
|
373
|
+
unittest.main()
|