1
|
|
|
# -*- coding: utf-8 -*- |
2
|
|
|
# vim:fileencoding=utf-8 |
3
|
|
|
# |
4
|
|
|
# Copyright (c) 2024 Stefan Bender |
5
|
|
|
# |
6
|
|
|
# This module is part of pyspaceweather. |
7
|
|
|
# pyspaceweather is free software: you can redistribute it or modify |
8
|
|
|
# it under the terms of the GNU General Public License as published |
9
|
|
|
# by the Free Software Foundation, version 2. |
10
|
|
|
# See accompanying COPYING.GPLv2 file or http://www.gnu.org/licenses/gpl-2.0.html. |
11
|
|
|
"""Space weather index read tests for GFZ formats |
12
|
|
|
|
13
|
|
|
Parsing tests for the GFZ file formats. |
14
|
|
|
""" |
15
|
|
|
import os |
16
|
|
|
|
17
|
|
|
import numpy as np |
18
|
|
|
import pandas as pd |
19
|
|
|
import requests |
20
|
|
|
|
21
|
|
|
import pytest |
22
|
|
|
|
23
|
|
|
from spaceweather import ( |
24
|
|
|
gfz_3h, gfz_daily, get_gfz_age, update_gfz, |
25
|
|
|
) |
26
|
|
|
from spaceweather.gfz import GFZ_URL_30D |
27
|
|
|
|
28
|
|
|
GFZ_PATH_ALL = os.path.join("tests", "Kp_ap_Ap_SN_F107_since_2024.txt") |
29
|
|
|
GFZ_PATH_30D = os.path.join("tests", "Kp_ap_Ap_SN_F107_nowcast.txt") |
30
|
|
|
|
31
|
|
|
|
32
|
|
|
@pytest.fixture(scope="module") |
33
|
|
|
def df_3h(): |
34
|
|
|
return gfz_3h(gfzpath_all=GFZ_PATH_ALL, gfzpath_30d=GFZ_PATH_30D) |
35
|
|
|
|
36
|
|
|
|
37
|
|
|
def test_age(): |
38
|
|
|
now = pd.Timestamp.utcnow() |
39
|
|
|
for p in [GFZ_PATH_ALL, GFZ_PATH_30D]: |
40
|
|
|
assert os.path.exists(p) |
41
|
|
|
fage0 = get_gfz_age(p) |
42
|
|
|
fage1 = now - get_gfz_age(p, relative=False) |
43
|
|
|
assert (fage0 > pd.Timedelta("3h")) == (fage1 > pd.Timedelta("3h")) |
44
|
|
|
assert (fage0 > pd.Timedelta("1d")) == (fage1 > pd.Timedelta("1d")) |
45
|
|
|
|
46
|
|
|
|
47
|
|
|
def _assert_age(p, age): |
48
|
|
|
assert os.path.exists(p) |
49
|
|
|
fage = get_gfz_age(p) |
50
|
|
|
assert fage < pd.Timedelta(age) |
51
|
|
|
|
52
|
|
|
|
53
|
|
|
def test_update(mocker): |
54
|
|
|
mocker.patch("requests.get") |
55
|
|
|
update_gfz(min_age="1d", gfzpath_all=GFZ_PATH_ALL, gfzpath_30d=GFZ_PATH_30D) |
56
|
|
|
requests.get.assert_called_with(GFZ_URL_30D, stream=True) |
57
|
|
|
|
58
|
|
|
|
59
|
|
|
def test_auto_update(mocker, tmpdir): |
60
|
|
|
# test with non-existent file |
61
|
|
|
mocker.patch("requests.get") |
62
|
|
|
tmpdir = str(tmpdir) |
63
|
|
|
update_gfz(gfzpath_30d=os.path.join(tmpdir, "foo.dat")) |
64
|
|
|
requests.get.assert_called_with(GFZ_URL_30D, stream=True) |
65
|
|
|
# Should update the last-5-year data |
66
|
|
|
gfz_daily(update=True, update_interval="1d") |
67
|
|
|
requests.get.assert_called_with(GFZ_URL_30D, stream=True) |
68
|
|
|
_assert_age(GFZ_PATH_30D, "10d") |
69
|
|
|
with pytest.warns(UserWarning): |
70
|
|
|
gfz_daily(update=False, update_interval="0h") |
71
|
|
|
|
72
|
|
|
|
73
|
|
|
def test_not_avail(mocker, tmpdir): |
74
|
|
|
# test with non-existent file |
75
|
|
|
mocker.patch("requests.get") |
76
|
|
|
tmpdir = str(tmpdir) |
77
|
|
|
tmpfile = os.path.join(tmpdir, "foo.dat") |
78
|
|
|
# daily |
79
|
|
|
with pytest.raises(IOError): |
80
|
|
|
with pytest.warns(UserWarning): |
81
|
|
|
gfz_daily(update=False, update_interval="0h", gfzpath_30d=tmpfile) |
82
|
|
|
# 3h data |
83
|
|
|
with pytest.raises(IOError): |
84
|
|
|
with pytest.warns(UserWarning): |
85
|
|
|
gfz_3h(update=False, update_interval="0h", gfzpath_30d=tmpfile) |
86
|
|
|
|
87
|
|
|
|
88
|
|
|
def test_daily(): |
89
|
|
|
df = gfz_daily(gfzpath_all=GFZ_PATH_ALL, gfzpath_30d=GFZ_PATH_30D) |
90
|
|
|
np.testing.assert_allclose( |
91
|
|
|
df.loc["2024-01-01"].values, |
92
|
|
|
np.array([ |
93
|
|
|
2.024e+03, 1.000e+00, 1.000e+00, |
94
|
|
|
3.36030e+04, 3.36035e+04, 2.596e+03, 2.500e+01, |
95
|
|
|
6.670e-01, 3.330e-01, 6.670e-01, 1.333e+00, |
96
|
|
|
2.000e+00, 3.000e+00, 3.333e+00, 4.000e+00, 1.5333e+01, |
97
|
|
|
3.000e+00, 2.000e+00, 3.000e+00, 5.000e+00, |
98
|
|
|
7.000e+00, 1.500e+01, 1.800e+01, 2.700e+01, 1.000e+01, |
99
|
|
|
5.400e+01, 1.357e+02, 1.312e+02, 1.000e+00, |
100
|
|
|
], dtype=np.float64), |
101
|
|
|
rtol=1e-6, |
102
|
|
|
) |
103
|
|
|
|
104
|
|
|
|
105
|
|
|
@pytest.mark.parametrize( |
106
|
|
|
"name, result", |
107
|
|
|
[ |
108
|
|
|
("Ap", [3, 2, 3, 5, 7, 15, 18, 27]), |
109
|
|
|
("Kp", [0.667, 0.333, 0.667, 1.333, 2.0, 3.0, 3.333, 4.0]), |
110
|
|
|
] |
111
|
|
|
) |
112
|
|
|
def test_3hourly_index(name, result, df_3h): |
113
|
|
|
df = df_3h |
114
|
|
|
np.testing.assert_allclose( |
115
|
|
|
df.loc[ |
116
|
|
|
pd.date_range( |
117
|
|
|
"2024-01-01 01:30", "2024-01-01 23:30", freq="3h" |
118
|
|
|
) |
119
|
|
|
][name].values, |
120
|
|
|
np.array(result, dtype=np.float64), |
121
|
|
|
rtol=1e-6, |
122
|
|
|
) |
123
|
|
|
|