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.
@@ -0,0 +1,745 @@
1
+ """test_unc_accessor - tests for obsarray.unc_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
+ import unittest.mock as mock
9
+ from unittest.mock import patch
10
+ import obsarray
11
+
12
+
13
+ __author__ = "Sam Hunt <sam.hunt@npl.co.uk>"
14
+ __all__ = []
15
+
16
+
17
+ simple_ds = xr.Dataset(
18
+ {"a": (["x", "y"], np.full((2, 2), 3)), "b": (["x", "y"], np.full((2, 2), 4))}
19
+ ).data_vars
20
+
21
+
22
+ def simple_build_matrix(sli):
23
+ return np.eye(12)
24
+
25
+
26
+ mock_err_corr_form = mock.MagicMock()
27
+ mock_err_corr_form.return_value.build_matrix = simple_build_matrix
28
+
29
+
30
+ def compare_err_corr_form(self, form, exp_form):
31
+ self.assertEqual(form.form, exp_form.form)
32
+ self.assertCountEqual(form.params, exp_form.params)
33
+ self.assertCountEqual(form.units, exp_form.units)
34
+ self.assertCountEqual(form._unc_var_name, exp_form._unc_var_name)
35
+
36
+
37
+ def create_ds():
38
+ np.random.seed(0)
39
+ temperature = 15 + 8 * np.random.randn(2, 2, 3)
40
+ u_r_temperature = temperature * 0.02
41
+ u_s_temperature = temperature * 0.01
42
+ precipiation = 15 + 8 * np.random.randn(2, 2, 3)
43
+ u_r_precipiation = temperature * 0.02
44
+ lon = [[-99.83, -99.32], [-99.79, -99.23]]
45
+ lat = [[42.25, 42.21], [42.63, 42.59]]
46
+ time = pd.date_range("2014-09-06", periods=3)
47
+ reference_time = pd.Timestamp("2014-09-05")
48
+
49
+ ds = xr.Dataset(
50
+ data_vars=dict(
51
+ temperature=(["x", "y", "time"], temperature, {"units": "K"}),
52
+ ),
53
+ coords=dict(
54
+ lon=(["x", "y"], lon),
55
+ lat=(["x", "y"], lat),
56
+ time=time,
57
+ reference_time=reference_time,
58
+ ),
59
+ attrs=dict(description="Weather related data."),
60
+ )
61
+
62
+ ds.unc["temperature"]["u_ran_temperature"] = (
63
+ ["x", "y", "time"],
64
+ temperature * 0.05,
65
+ {"units": "K", "pdf_shape": "gaussian"},
66
+ )
67
+
68
+ ds.unc["temperature"]["u_sys_temperature"] = (
69
+ ["x", "y", "time"],
70
+ temperature * 0.03,
71
+ {
72
+ "units": "K",
73
+ "err_corr": [
74
+ {
75
+ "dim": "x",
76
+ "form": "systematic",
77
+ "params": [],
78
+ },
79
+ {
80
+ "dim": "y",
81
+ "form": "systematic",
82
+ "params": [],
83
+ },
84
+ {
85
+ "dim": "time",
86
+ "form": "systematic",
87
+ "params": [],
88
+ },
89
+ ],
90
+ "pdf_shape": "gaussian",
91
+ },
92
+ )
93
+
94
+ ds.unc["temperature"]["u_str_temperature"] = (
95
+ ["x", "y", "time"],
96
+ temperature * 0.1,
97
+ {
98
+ "units": "K",
99
+ "err_corr": [
100
+ {
101
+ "dim": ["x", "time"],
102
+ "form": "err_corr_matrix",
103
+ "params": ["err_corr_str_temperature"],
104
+ },
105
+ {
106
+ "dim": "y",
107
+ "form": "systematic",
108
+ "params": [],
109
+ },
110
+ ],
111
+ "pdf_shape": "gaussian",
112
+ },
113
+ )
114
+
115
+ ds["err_corr_str_temperature"] = (
116
+ ["x.time", "x.time"],
117
+ np.ones(
118
+ (
119
+ temperature.shape[0] * temperature.shape[2],
120
+ temperature.shape[0] * temperature.shape[2],
121
+ )
122
+ ),
123
+ )
124
+
125
+ return ds
126
+
127
+
128
+ class TestUncAccessor(unittest.TestCase):
129
+ def setUp(self):
130
+ np.random.seed(0)
131
+ temperature = 15 + 8 * np.random.randn(2, 2, 3)
132
+ u_r_temperature = temperature * 0.02
133
+ u_s_temperature = temperature * 0.01
134
+ precipiation = 15 + 8 * np.random.randn(2, 2, 3)
135
+ u_r_precipiation = temperature * 0.02
136
+ lon = [[-99.83, -99.32], [-99.79, -99.23]]
137
+ lat = [[42.25, 42.21], [42.63, 42.59]]
138
+ time = pd.date_range("2014-09-06", periods=3)
139
+ reference_time = pd.Timestamp("2014-09-05")
140
+
141
+ self.ds = xr.Dataset(
142
+ data_vars=dict(
143
+ temperature=(["x", "y", "time"], temperature),
144
+ u_r_temperature=(
145
+ ["x", "y", "time"],
146
+ u_r_temperature,
147
+ {
148
+ "err_corr_1_dim": "x",
149
+ "err_corr_1_form": "random",
150
+ "err_corr_1_params": [],
151
+ "err_corr_1_units": [],
152
+ "err_corr_2_dim": "y",
153
+ "err_corr_2_form": "random",
154
+ "err_corr_2_params": [],
155
+ "err_corr_2_units": [],
156
+ "err_corr_3_dim": "time",
157
+ "err_corr_3_form": "random",
158
+ "err_corr_3_params": [],
159
+ "err_corr_3_units": [],
160
+ },
161
+ ),
162
+ u_s_temperature=(
163
+ ["x", "y", "time"],
164
+ u_s_temperature,
165
+ {
166
+ "err_corr_1_dim": "x",
167
+ "err_corr_1_form": "systematic",
168
+ "err_corr_1_params": [],
169
+ "err_corr_1_units": [],
170
+ "err_corr_2_dim": "y",
171
+ "err_corr_2_form": "systematic",
172
+ "err_corr_2_params": [],
173
+ "err_corr_2_units": [],
174
+ "err_corr_3_dim": "time",
175
+ "err_corr_3_form": "systematic",
176
+ "err_corr_3_params": [],
177
+ "err_corr_3_units": [],
178
+ },
179
+ ),
180
+ precipitation=(["x", "y", "time"], precipiation),
181
+ u_r_precipitation=(["x", "y", "time"], u_r_precipiation),
182
+ ),
183
+ coords=dict(
184
+ lon=(["x", "y"], lon),
185
+ lat=(["x", "y"], lat),
186
+ time=time,
187
+ reference_time=reference_time,
188
+ ),
189
+ attrs=dict(description="Weather related data."),
190
+ )
191
+
192
+ self.ds.temperature.attrs["unc_comps"] = ["u_r_temperature", "u_s_temperature"]
193
+ self.ds.precipitation.attrs["unc_comps"] = ["u_r_precipitation"]
194
+
195
+ def test___getitem__(self):
196
+ self.assertIsInstance(
197
+ self.ds.unc["temperature"], obsarray.unc_accessor.VariableUncertainty
198
+ )
199
+ self.assertEqual(self.ds.unc["temperature"]._var_name, "temperature")
200
+
201
+ def test___len__(self):
202
+ self.assertEqual(len(self.ds.unc), 2)
203
+
204
+ def test___iter__(self):
205
+
206
+ var_names = []
207
+ for unc in self.ds.unc:
208
+ self.assertIsInstance(unc, obsarray.unc_accessor.VariableUncertainty)
209
+ var_names.append(unc._var_name)
210
+
211
+ self.assertCountEqual(var_names, ["temperature", "precipitation"])
212
+
213
+ def test_keys(self):
214
+ self.assertCountEqual(self.ds.unc.keys(), ["temperature", "precipitation"])
215
+
216
+ def test__var_unc_var_names(self):
217
+ self.assertCountEqual(
218
+ self.ds.unc._var_unc_var_names("temperature"),
219
+ ["u_r_temperature", "u_s_temperature"],
220
+ )
221
+
222
+ def test__var_unc_var_names_none(self):
223
+ self.assertCountEqual(self.ds.unc._var_unc_var_names("u_r_temperature"), [])
224
+
225
+ def test__var_unc_var_names_random(self):
226
+ self.assertCountEqual(
227
+ self.ds.unc._var_unc_var_names("temperature", "random"),
228
+ ["u_r_temperature"],
229
+ )
230
+
231
+ def test__var_unc_var_names_structured(self):
232
+ self.assertCountEqual(
233
+ self.ds.unc._var_unc_var_names("temperature", "structured"),
234
+ [],
235
+ )
236
+
237
+ def test__var_unc_var_names_systematic(self):
238
+ self.assertCountEqual(
239
+ self.ds.unc._var_unc_var_names("temperature", "systematic"),
240
+ ["u_s_temperature"],
241
+ )
242
+
243
+ def test__is_obs_var_true(self):
244
+ self.assertTrue(self.ds.unc._is_obs_var("temperature"))
245
+
246
+ def test__is_obs_var_false(self):
247
+ self.assertFalse(self.ds.unc._is_obs_var("u_r_temperature"))
248
+
249
+ def test_obs_vars(self):
250
+ obs_vars = self.ds.unc.obs_vars
251
+ self.assertEqual(type(obs_vars), xr.core.dataset.DataVariables)
252
+ self.assertCountEqual(
253
+ list(obs_vars.variables), ["temperature", "precipitation"]
254
+ )
255
+
256
+ def test_unc_vars(self):
257
+ unc_vars = self.ds.unc.unc_vars
258
+ self.assertEqual(type(unc_vars), xr.core.dataset.DataVariables)
259
+ self.assertCountEqual(
260
+ list(unc_vars.variables),
261
+ ["u_r_temperature", "u_s_temperature", "u_r_precipitation"],
262
+ )
263
+
264
+ def test__is_unc_var_true(self):
265
+ self.assertTrue(self.ds.unc._is_unc_var("u_r_temperature"))
266
+
267
+ def test__is_unc_var_false(self):
268
+ self.assertFalse(self.ds.unc._is_unc_var("temperature"))
269
+
270
+ def test__var_unc_vars(self):
271
+ unc_vars = self.ds.unc._var_unc_vars("temperature")
272
+ self.assertEqual(type(unc_vars), xr.core.dataset.DataVariables)
273
+ self.assertCountEqual(
274
+ list(unc_vars.variables), ["u_r_temperature", "u_s_temperature"]
275
+ )
276
+
277
+ def test__var_unc_vars_none(self):
278
+ self.assertIsNone(self.ds.unc._var_unc_vars("u_r_temperature"))
279
+
280
+ def test__add_unc_var_DataArray(self):
281
+ u_s_precipitation = xr.DataArray(
282
+ self.ds.precipitation.values, dims=["x", "y", "time"]
283
+ )
284
+ self.ds.unc._add_unc_var(
285
+ "precipitation", "u_s_precipitation", u_s_precipitation
286
+ )
287
+ self.assertTrue(
288
+ "u_s_precipitation" in self.ds.unc._var_unc_var_names("precipitation")
289
+ )
290
+
291
+ np.testing.assert_array_equal(
292
+ u_s_precipitation.values, self.ds.u_s_precipitation.values
293
+ )
294
+
295
+ @patch("obsarray.unc_accessor.create_var")
296
+ def test__add_unc_var_tuple(self, mock):
297
+
298
+ unc_def = (
299
+ ["x", "y", "time"],
300
+ self.ds.precipitation.values,
301
+ {"err_corr": []},
302
+ )
303
+ self.ds.unc._add_unc_var("precipitation", "u_s_precipitation", unc_def)
304
+ self.assertTrue(
305
+ "u_s_precipitation" in self.ds.unc._var_unc_var_names("precipitation")
306
+ )
307
+
308
+ mock.assert_called_once_with(
309
+ "u_s_precipitation",
310
+ {
311
+ "dtype": np.float64,
312
+ "dim": ["x", "y", "time"],
313
+ "attributes": {"err_corr": []},
314
+ },
315
+ {"x": 2, "y": 2, "time": 3},
316
+ )
317
+
318
+ self.assertTrue(("u_s_precipitation" in self.ds))
319
+
320
+ @patch("obsarray.unc_accessor.create_var")
321
+ def test__add_unc_var_tuple_no_err_corr(self, mock):
322
+ unc_def = (["x", "y", "time"], self.ds.precipitation.values, {})
323
+ self.ds.unc._add_unc_var("precipitation", "u_s_precipitation", unc_def)
324
+ self.assertTrue(
325
+ "u_s_precipitation" in self.ds.unc._var_unc_var_names("precipitation")
326
+ )
327
+
328
+ mock.assert_called_once_with(
329
+ "u_s_precipitation",
330
+ {
331
+ "dtype": np.float64,
332
+ "dim": ["x", "y", "time"],
333
+ "attributes": {"err_corr": []},
334
+ },
335
+ {"x": 2, "y": 2, "time": 3},
336
+ )
337
+
338
+ self.assertTrue(("u_s_precipitation" in self.ds))
339
+
340
+ @patch("obsarray.unc_accessor.create_var")
341
+ def test__add_unc_var_tuple_no_attrs(self, mock):
342
+ unc_def = (["x", "y", "time"], self.ds.precipitation.values)
343
+ self.ds.unc._add_unc_var("precipitation", "u_s_precipitation", unc_def)
344
+ self.assertTrue(
345
+ "u_s_precipitation" in self.ds.unc._var_unc_var_names("precipitation")
346
+ )
347
+
348
+ mock.assert_called_once_with(
349
+ "u_s_precipitation",
350
+ {
351
+ "dtype": np.float64,
352
+ "dim": ["x", "y", "time"],
353
+ "attributes": {"err_corr": []},
354
+ },
355
+ {"x": 2, "y": 2, "time": 3},
356
+ )
357
+
358
+ self.assertTrue(("u_s_precipitation" in self.ds))
359
+
360
+ def test__remove_unc_var(self):
361
+ self.ds.unc._remove_unc_var("temperature", "u_s_temperature")
362
+
363
+ self.assertTrue("u_s_temperature" not in self.ds)
364
+ self.assertTrue(
365
+ "u_s_temperature" not in self.ds["precipitation"].attrs["unc_comps"]
366
+ )
367
+
368
+
369
+ class TestVariableUncertainty(unittest.TestCase):
370
+ def setUp(self):
371
+ self.ds = create_ds()
372
+
373
+ def test___getitem__(self):
374
+ self.assertIsInstance(
375
+ self.ds.unc["temperature"]["u_ran_temperature"],
376
+ obsarray.unc_accessor.Uncertainty,
377
+ )
378
+ self.assertEqual(
379
+ self.ds.unc["temperature"]["u_ran_temperature"]._unc_var_name,
380
+ "u_ran_temperature",
381
+ )
382
+
383
+ def test___len__(self):
384
+ self.assertEqual(len(self.ds.unc["temperature"]), 3)
385
+
386
+ def test___iter__(self):
387
+
388
+ var_names = []
389
+ for unc in self.ds.unc["temperature"]:
390
+ self.assertIsInstance(unc, obsarray.unc_accessor.Uncertainty)
391
+ var_names.append(unc._unc_var_name)
392
+
393
+ self.assertCountEqual(
394
+ var_names, ["u_ran_temperature", "u_sys_temperature", "u_str_temperature"]
395
+ )
396
+
397
+ def test_keys(self):
398
+ self.assertCountEqual(
399
+ self.ds.unc["temperature"].keys(),
400
+ ["u_ran_temperature", "u_sys_temperature", "u_str_temperature"],
401
+ )
402
+
403
+ @patch("obsarray.unc_accessor.UncAccessor._var_unc_vars")
404
+ def test_comps(self, mock_method):
405
+ comps = self.ds.unc["temperature"][:, :, 0].comps
406
+ mock_method.assert_called_once_with(
407
+ "temperature", (slice(None), slice(None), 0)
408
+ )
409
+
410
+ self.assertEqual(comps, mock_method.return_value)
411
+
412
+ @patch("obsarray.unc_accessor.UncAccessor._var_unc_vars")
413
+ def test_random_comps(self, mock_method):
414
+ comps = self.ds.unc["temperature"][:, :, 0].random_comps
415
+ mock_method.assert_called_once_with(
416
+ "temperature", (slice(None), slice(None), 0), unc_type="random"
417
+ )
418
+
419
+ self.assertEqual(comps, mock_method.return_value)
420
+
421
+ @patch("obsarray.unc_accessor.UncAccessor._var_unc_vars")
422
+ def test_structured_comps(self, mock_method):
423
+ comps = self.ds.unc["temperature"][:, :, 0].structured_comps
424
+ mock_method.assert_called_once_with(
425
+ "temperature", (slice(None), slice(None), 0), unc_type="structured"
426
+ )
427
+
428
+ self.assertEqual(comps, mock_method.return_value)
429
+
430
+ @patch("obsarray.unc_accessor.UncAccessor._var_unc_vars")
431
+ def test_systematic_comps(self, mock_method):
432
+ comps = self.ds.unc["temperature"][:, :, 0].systematic_comps
433
+ mock_method.assert_called_once_with(
434
+ "temperature", (slice(None), slice(None), 0), unc_type="systematic"
435
+ )
436
+
437
+ self.assertEqual(comps, mock_method.return_value)
438
+
439
+ def test__quadsum_unc(self):
440
+
441
+ self.ds["u_ran_temperature"].values[:] = 3.0
442
+ self.ds["u_str_temperature"].values[:] = (
443
+ 4.0 / self.ds["temperature"].values * 100.0
444
+ )
445
+ self.ds["u_str_temperature"].attrs["units"] = "%"
446
+
447
+ u_tot = self.ds.unc["temperature"][:, :, 0]._quadsum_unc(
448
+ ["u_ran_temperature", "u_str_temperature"]
449
+ )
450
+ exp_u_tot = deepcopy(self.ds["temperature"])
451
+ exp_u_tot.values[:] = 5.0
452
+
453
+ xr.testing.assert_allclose(u_tot, exp_u_tot[:, :, 0])
454
+
455
+ def test__quadsum_unc_None(self):
456
+ self.assertIsNone(self.ds.unc["temperature"]._quadsum_unc([]))
457
+
458
+ @patch("obsarray.unc_accessor.VariableUncertainty._quadsum_unc")
459
+ def test_total_unc(self, mock):
460
+ self.ds.unc["temperature"][:, :, 0].total_unc()
461
+ mock.assert_called_once()
462
+ self.assertCountEqual(
463
+ mock.mock_calls[0][1][0],
464
+ ["u_ran_temperature", "u_str_temperature", "u_sys_temperature"],
465
+ )
466
+
467
+ @patch("obsarray.unc_accessor.VariableUncertainty._quadsum_unc")
468
+ def test_random_unc(self, mock):
469
+ self.ds.unc["temperature"][:, :, 0].random_unc()
470
+ mock.assert_called_once_with(["u_ran_temperature"])
471
+
472
+ @patch("obsarray.unc_accessor.VariableUncertainty._quadsum_unc")
473
+ def test_structured_unc(self, mock):
474
+ self.ds.unc["temperature"][:, :, 0].structured_unc()
475
+ mock.assert_called_once_with(["u_str_temperature"])
476
+
477
+ @patch("obsarray.unc_accessor.VariableUncertainty._quadsum_unc")
478
+ def test_systematic_unc(self, mock):
479
+ self.ds.unc["temperature"][:, :, 0].systematic_unc()
480
+ mock.assert_called_once_with(["u_sys_temperature"])
481
+
482
+ def test_total_err_corr_matrix(
483
+ self,
484
+ ):
485
+ tercm = self.ds.unc["temperature"].total_err_corr_matrix()
486
+ assert tercm.shape == (12, 12)
487
+ tercm = self.ds.unc["temperature"][:, :, 0].total_err_corr_matrix()
488
+ assert tercm.shape == (4, 4)
489
+ tercm = self.ds.unc["temperature"][:, 0, 0:2].total_err_corr_matrix()
490
+ assert tercm.shape == (4, 4)
491
+ tercm = self.ds.unc["temperature"][0, 0, :].total_err_corr_matrix()
492
+ assert tercm.shape == (3, 3)
493
+
494
+ def test_structured_err_corr_matrix(self):
495
+ pass
496
+
497
+ def test_total_err_cov_matrix(self):
498
+ pass
499
+
500
+ def test_structured_err_cov_matrix(self):
501
+ pass
502
+
503
+
504
+ class TestUncertainty(unittest.TestCase):
505
+ def setUp(self):
506
+ self.ds = create_ds()
507
+
508
+ @patch("obsarray.unc_accessor.Uncertainty._expand_sli", return_value="slice")
509
+ def test___getitem__(self, m):
510
+ self.assertEqual(
511
+ self.ds.unc["temperature"]["u_ran_temperature"]["in_slice"]._sli, "slice"
512
+ )
513
+
514
+ m.assert_called_with("in_slice")
515
+
516
+ def test_expand_slice_1d_full(self):
517
+ self.ds["new"] = (["time"], np.ones(3), {})
518
+ self.ds.unc["new"]["u_new"] = (["time"], np.ones(3), {})
519
+ sli = self.ds.unc["new"]["u_new"]._expand_sli((1))
520
+ self.assertEqual((1,), sli)
521
+
522
+ def test_expand_slice_1d_None(self):
523
+ self.ds["new"] = (["time"], np.ones(3), {})
524
+ self.ds.unc["new"]["u_new"] = (["time"], np.ones(3), {})
525
+ sli = self.ds.unc["new"]["u_new"]._expand_sli()
526
+ self.assertEqual((slice(None),), sli)
527
+
528
+ def test_expand_slice_full(self):
529
+ sli = self.ds.unc["temperature"]["u_ran_temperature"]._expand_sli((1, 1, 1))
530
+ self.assertEqual((1, 1, 1), sli)
531
+
532
+ def test_expand_slice_None(self):
533
+ sli = self.ds.unc["temperature"]["u_ran_temperature"]._expand_sli()
534
+ self.assertEqual((slice(None), slice(None), slice(None)), sli)
535
+
536
+ def test_expand_slice_first(self):
537
+ sli = self.ds.unc["temperature"]["u_ran_temperature"]._expand_sli((0,))
538
+ self.assertEqual((0, slice(None), slice(None)), sli)
539
+
540
+ def test_rename(self):
541
+ ds = self.ds.unc["temperature"]["u_ran_temperature"].rename("test")
542
+ self.assertTrue("test" in ds.keys())
543
+ self.assertTrue("u_ran_temperature" not in ds.keys())
544
+ self.assertCountEqual(
545
+ ds["temperature"].attrs["unc_comps"],
546
+ ["test", "u_str_temperature", "u_sys_temperature"],
547
+ )
548
+
549
+ def test_err_corr(self):
550
+
551
+ expected_err_corr = [
552
+ (
553
+ "y",
554
+ obsarray.err_corr.RandomCorrelation(
555
+ self.ds, "u_ran_temperature", ["y"], [], []
556
+ ),
557
+ ),
558
+ (
559
+ "time",
560
+ obsarray.err_corr.RandomCorrelation(
561
+ self.ds, "u_ran_temperature", ["time"], [], []
562
+ ),
563
+ ),
564
+ (
565
+ "x",
566
+ obsarray.err_corr.RandomCorrelation(
567
+ self.ds, "u_ran_temperature", "x", [], []
568
+ ),
569
+ ),
570
+ ]
571
+
572
+ err_corr = self.ds.unc["temperature"]["u_ran_temperature"].err_corr
573
+
574
+ for dim_tp, exp_dim_tp in zip(sorted(err_corr), sorted(expected_err_corr)):
575
+ self.assertEqual(dim_tp[0], exp_dim_tp[0])
576
+ compare_err_corr_form(self, dim_tp[1], exp_dim_tp[1])
577
+
578
+ def test_err_corr_slice(self):
579
+
580
+ expected_err_corr = [
581
+ (
582
+ "y",
583
+ obsarray.err_corr.RandomCorrelation(
584
+ self.ds, "u_ran_temperature", ["y"], [], []
585
+ ),
586
+ ),
587
+ (
588
+ "time",
589
+ obsarray.err_corr.RandomCorrelation(
590
+ self.ds, "u_ran_temperature", ["time"], [], []
591
+ ),
592
+ ),
593
+ ]
594
+
595
+ err_corr = self.ds.unc["temperature"]["u_ran_temperature"][0, :, :].err_corr
596
+
597
+ for dim_tp, exp_dim_tp in zip(sorted(err_corr), sorted(expected_err_corr)):
598
+ self.assertEqual(dim_tp[0], exp_dim_tp[0])
599
+ compare_err_corr_form(self, dim_tp[1], exp_dim_tp[1])
600
+
601
+ def test_units_K(self):
602
+
603
+ self.assertEqual(self.ds.unc["temperature"]["u_ran_temperature"].units, "K")
604
+
605
+ def test_units_None(self):
606
+
607
+ self.ds["u_str_temperature"].attrs.pop("units")
608
+
609
+ self.assertIsNone(
610
+ self.ds.unc["temperature"]["u_str_temperature"].units,
611
+ )
612
+
613
+ def test_var_units_K(self):
614
+
615
+ self.assertEqual(self.ds.unc["temperature"]["u_ran_temperature"].var_units, "K")
616
+
617
+ def test_var_units_None(self):
618
+
619
+ self.ds["temperature"].attrs.pop("units")
620
+
621
+ self.assertIsNone(
622
+ self.ds.unc["temperature"]["u_ran_temperature"].var_units,
623
+ )
624
+
625
+ def test_value(self):
626
+
627
+ xr.testing.assert_equal(
628
+ self.ds["u_ran_temperature"],
629
+ self.ds.unc["temperature"]["u_ran_temperature"].value,
630
+ )
631
+
632
+ def test_value_slice(self):
633
+
634
+ xr.testing.assert_equal(
635
+ self.ds["u_ran_temperature"][:, 0, :],
636
+ self.ds.unc["temperature"]["u_ran_temperature"][:, 0, :].value,
637
+ )
638
+
639
+ def test_var_value(self):
640
+
641
+ xr.testing.assert_equal(
642
+ self.ds["temperature"],
643
+ self.ds.unc["temperature"]["u_ran_temperature"].var_value,
644
+ )
645
+
646
+ def test_var_value_slice(self):
647
+
648
+ xr.testing.assert_equal(
649
+ self.ds["temperature"][:, 0, :],
650
+ self.ds.unc["temperature"]["u_ran_temperature"][:, 0, :].var_value,
651
+ )
652
+
653
+ def test_abs_value_percentage(self):
654
+ self.ds["u_str_temperature"].attrs["units"] = "%"
655
+ self.ds["u_str_temperature"].values[:] = 10.0
656
+
657
+ exp_da = deepcopy(self.ds["u_str_temperature"])
658
+ exp_da.values = self.ds["temperature"] / 10.0
659
+
660
+ xr.testing.assert_allclose(
661
+ exp_da,
662
+ self.ds.unc["temperature"]["u_str_temperature"].abs_value,
663
+ )
664
+
665
+ def test_abs_value_sameunits(self):
666
+
667
+ xr.testing.assert_equal(
668
+ self.ds.unc["temperature"]["u_str_temperature"].value,
669
+ self.ds.unc["temperature"]["u_str_temperature"].abs_value,
670
+ )
671
+
672
+ def test_abs_value_diffunits(self):
673
+
674
+ self.ds["u_str_temperature"].attrs["units"] = "mK"
675
+
676
+ def unitcall(ds):
677
+ ds.unc["temperature"]["u_str_temperature"].abs_value
678
+
679
+ self.assertRaises(ValueError, unitcall, self.ds)
680
+
681
+ def test_abs_value_uncnounits(self):
682
+
683
+ del self.ds["u_str_temperature"].attrs["units"]
684
+
685
+ xr.testing.assert_equal(
686
+ self.ds.unc["temperature"]["u_str_temperature"].value,
687
+ self.ds.unc["temperature"]["u_str_temperature"].abs_value,
688
+ )
689
+
690
+ def test_pdf_shape(self):
691
+ self.assertEqual(
692
+ self.ds.unc["temperature"]["u_ran_temperature"].pdf_shape, "gaussian"
693
+ )
694
+
695
+ def test_is_random_true(self):
696
+
697
+ self.assertTrue(self.ds.unc["temperature"]["u_ran_temperature"].is_random)
698
+
699
+ def test_is_random_false(self):
700
+
701
+ self.assertFalse(self.ds.unc["temperature"]["u_sys_temperature"].is_random)
702
+
703
+ def test_is_structured_true(self):
704
+
705
+ self.assertTrue(self.ds.unc["temperature"]["u_str_temperature"].is_structured)
706
+
707
+ def test_is_structured_false_ran(self):
708
+
709
+ self.assertFalse(self.ds.unc["temperature"]["u_ran_temperature"].is_structured)
710
+
711
+ def test_is_structured_false_sys(self):
712
+
713
+ self.assertFalse(self.ds.unc["temperature"]["u_sys_temperature"].is_structured)
714
+
715
+ def test_is_systematic_true(self):
716
+
717
+ self.assertTrue(self.ds.unc["temperature"]["u_sys_temperature"].is_systematic)
718
+
719
+ def test_is_systematic_false(self):
720
+
721
+ self.assertFalse(self.ds.unc["temperature"]["u_ran_temperature"].is_systematic)
722
+
723
+ @patch("obsarray.unc_accessor.err_corr_forms", {"random": mock_err_corr_form})
724
+ def test_err_corr_matrix_3dvar(self):
725
+ erc = self.ds.unc["temperature"]["u_ran_temperature"].err_corr_matrix()
726
+
727
+ exp_erc = xr.DataArray(np.eye(12), dims=["x.y.time", "x.y.time"])
728
+ xr.testing.assert_equal(erc, exp_erc)
729
+
730
+ @patch("obsarray.unc_accessor.Uncertainty.value")
731
+ @patch("obsarray.unc_accessor.Uncertainty.err_corr_matrix")
732
+ @patch("obsarray.unc_accessor.convert_corr_to_cov", return_value=np.ones((12, 12)))
733
+ def test_err_cov_matrix(self, mock_cr2cv, mock_ecrm, mock_value):
734
+ ecm = self.ds.unc["temperature"]["u_ran_temperature"].err_cov_matrix()
735
+
736
+ mock_cr2cv.assert_called_once_with(
737
+ mock_ecrm.return_value.values, mock_value.values
738
+ )
739
+
740
+ exp_ecm = xr.DataArray(np.ones((12, 12)), dims=["x.y.time", "x.y.time"])
741
+ xr.testing.assert_equal(ecm, exp_ecm)
742
+
743
+
744
+ if __name__ == "__main__":
745
+ unittest.main()