Completed
Pull Request — develop (#33)
by
unknown
27s
created

TestRayleigh.tearDown()   A

Complexity

Conditions 1

Size

Total Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
c 0
b 0
f 0
dl 0
loc 3
rs 10
1
#!/usr/bin/env python
2
# -*- coding: utf-8 -*-
3
4
# Copyright (c) 2016, 2017, 2018 Adam.Dybbroe
5
6
# Author(s):
7
8
#   Adam.Dybbroe <[email protected]>
9
10
# This program is free software: you can redistribute it and/or modify
11
# it under the terms of the GNU General Public License as published by
12
# the Free Software Foundation, either version 3 of the License, or
13
# (at your option) any later version.
14
15
# This program is distributed in the hope that it will be useful,
16
# but WITHOUT ANY WARRANTY; without even the implied warranty of
17
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18
# GNU General Public License for more details.
19
20
# You should have received a copy of the GNU General Public License
21
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
22
23
"""Unittest for the rayleigh correction utilities
24
"""
25
26
import os
27
import sys
28
from mock import patch
29
import numpy as np
30
import dask.array as da
31
from pyspectral import rayleigh
32
from pyspectral.rayleigh import BandFrequencyOutOfRange
33
from pyspectral.tests.data import (
34
    TEST_RAYLEIGH_LUT,
35
    TEST_RAYLEIGH_AZID_COORD,
36
    TEST_RAYLEIGH_SUNZ_COORD,
37
    TEST_RAYLEIGH_SATZ_COORD,
38
    TEST_RAYLEIGH_WVL_COORD)
39
from pyspectral.utils import RSR_DATA_VERSION
40
41
if sys.version_info < (2, 7):
42
    import unittest2 as unittest
43
else:
44
    import unittest
45
46
47
TEST_RAYLEIGH_RESULT1 = np.array([10.40727436,   8.69775471], dtype='float32')
48
TEST_RAYLEIGH_RESULT2 = np.array([9.71695252,  8.51415601], dtype='float32')
49
TEST_RAYLEIGH_RESULT3 = np.array([5.61532271,  8.69267476], dtype='float32')
50
51
52
# Mock some modules, so we don't need them for tests.
53
54
# sys.modules['pyresample'] = MagicMock()
55
56 View Code Duplication
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
57
class RelativeSpectralResponseTestData(object):
58
59
    """RSR test data"""
60
61
    def __init__(self):
62
        """Making a testdata set of relative spectral responses"""
63
64
        self.rsr = {}
65
        channel_names = ['ch12', 'ch13', 'ch10', 'ch11', 'ch16', 'ch14',
66
                         'ch15', 'ch1', 'ch2', 'ch3', 'ch4', 'ch5', 'ch6',
67
                         'ch7', 'ch8', 'ch9']
68
        wvl = [9.6372744012936646, 10.407492196078628, 7.3468642293967275,
69
               8.5926867614178715, 13.280724258676756, 11.239642285822033,
70
               12.380741429961382, 0.47063607733748003, 0.5099976405799187,
71
               0.63914891611559055, 0.85668832355426627, 1.6100814361999056,
72
               2.2568056299864101, 3.8853663735353847, 6.2428987228916233,
73
               6.9411756334211789]
74
        ch3_wvl = np.array([0.55518544, 0.56779468, 0.58099002, 0.59481323, 0.60931027,
75
                            0.62453163, 0.64053291, 0.65737575, 0.67512828, 0.69386619,
76
                            0.71367401])
77
        ch3_resp = np.array([2.61000005e-05, 1.07899999e-04, 3.26119992e-03,
78
                             2.90650606e-01, 9.02460396e-01, 9.60878074e-01,
79
                             9.97266889e-01, 9.94823873e-01, 7.18220174e-01,
80
                             8.31819978e-03, 9.34999989e-05])
81
82
        idx = 0
83
        for chname in channel_names:
84
            self.rsr[chname] = {'det-1': {}}
85
            self.rsr[chname]['det-1']['central_wavelength'] = wvl[idx]
86
            idx = idx + 1
87
88
        chname = 'ch3'
89
        self.rsr[chname]['det-1']['wavelength'] = ch3_wvl
90
        self.rsr[chname]['det-1']['response'] = ch3_resp
91
92
93
class TestRayleigh(unittest.TestCase):
94
95
    """Class for testing pyspectral.rayleigh"""
96
97
    def setUp(self):
98
        """Setup the test"""
99
100
        self.cwvl = 0.4440124
101
        self.rsr = RelativeSpectralResponseTestData()
102
        self._res1 = da.from_array(TEST_RAYLEIGH_RESULT1, chunks=2)
103
        self._res2 = da.from_array(TEST_RAYLEIGH_RESULT2, chunks=2)
104
        self._res3 = da.from_array(TEST_RAYLEIGH_RESULT3, chunks=2)
105
106
        # mymock:
107
        with patch('pyspectral.rayleigh.RelativeSpectralResponse') as mymock:
108
            instance = mymock.return_value
109
            instance.rsr = RelativeSpectralResponseTestData().rsr
110
            instance.unit = '1e-6 m'
111
            instance.si_scale = 1e-6
112
113
            self.viirs_rayleigh = rayleigh.Rayleigh('NOAA-20', 'viirs', atmosphere='midlatitude summer')
114
115
    def test_get_effective_wavelength(self):
116
        """Test getting the effective wavelength"""
117
118
        # mymock:
119
        with patch('pyspectral.rayleigh.RelativeSpectralResponse') as mymock:
120
            instance = mymock.return_value
121
            instance.rsr = RelativeSpectralResponseTestData().rsr
122
123
            this = rayleigh.Rayleigh('Himawari-8', 'ahi')
124
            with self.assertRaises(BandFrequencyOutOfRange):
125
                this.get_effective_wavelength(0.9)
126
127
            # Only ch3 (~0.63) testdata implemented yet...
128
            ewl = this.get_effective_wavelength(0.65)
129
            self.assertAlmostEqual(ewl, 0.6356167)
130
131
        # mymock:
132
        with patch('pyspectral.rayleigh.RelativeSpectralResponse') as mymock:
133
            instance = mymock.side_effect = IOError(
134
                'Fake that there is no spectral response file...')
135
136
            this = rayleigh.Rayleigh('Himawari-8', 'ahi')
137
            ewl = this.get_effective_wavelength(0.7)
138
            self.assertEqual(ewl, 0.7)
139
            ewl = this.get_effective_wavelength(0.9)
140
            self.assertEqual(ewl, 0.9)
141
            ewl = this.get_effective_wavelength(0.455)
142
            self.assertEqual(ewl, 0.455)
143
144
    @patch('os.path.exists')
145
    @patch('pyspectral.utils.download_luts')
146
    def test_rayleigh_init(self, download_luts, exists):
147
        """Test creating the Rayleigh object"""
148
149
        download_luts.return_code = None
150
        exists.return_code = True
151
152
        # mymock:
153
        with patch('pyspectral.rayleigh.RelativeSpectralResponse') as mymock:
154
            instance = mymock.return_value
155
            instance.rsr = RelativeSpectralResponseTestData().rsr
156
157
            with self.assertRaises(AttributeError):
158
                this = rayleigh.Rayleigh('Himawari-8', 'ahi', atmosphere='unknown')
159
160
            with self.assertRaises(AttributeError):
161
                this = rayleigh.Rayleigh('Himawari-8', 'ahi', aerosol_type='unknown')
162
163
            this = rayleigh.Rayleigh('Himawari-8', 'ahi', atmosphere='subarctic winter')
164
            self.assertTrue(os.path.basename(this.reflectance_lut_filename).endswith('subarctic_winter.h5'))
165
            self.assertTrue(this.sensor == 'ahi')
166
167
            this = rayleigh.Rayleigh('NOAA-19', 'avhrr/3', atmosphere='tropical')
168
            self.assertTrue(this.sensor == 'avhrr3')
169
170
    @patch('pyspectral.rayleigh.HAVE_DASK', False)
171
    @patch('os.path.exists')
172
    @patch('pyspectral.utils.download_luts')
173
    @patch('pyspectral.rayleigh.get_reflectance_lut')
174
    @patch('pyspectral.rsr_reader.RelativeSpectralResponse._get_rsr_data_version')
175
    @patch('pyspectral.rayleigh.Rayleigh.get_effective_wavelength')
176
    def test_get_reflectance(self, get_effective_wvl,
177
                             get_rsr_version, get_reflectance_lut, download_luts, exists):
178
        """Test getting the reflectance correction"""
179
180
        rayl = TEST_RAYLEIGH_LUT
181
        wvl_coord = TEST_RAYLEIGH_WVL_COORD
182
        azid_coord = TEST_RAYLEIGH_AZID_COORD
183
        sunz_sec_coord = TEST_RAYLEIGH_SUNZ_COORD
184
        satz_sec_coord = TEST_RAYLEIGH_SATZ_COORD
185
186
        get_reflectance_lut.return_value = (rayl, wvl_coord, azid_coord,
187
                                            satz_sec_coord, sunz_sec_coord)
188
        download_luts.return_code = None
189
        exists.return_code = True
190
        get_rsr_version.return_code = RSR_DATA_VERSION
191
        get_effective_wvl.return_value = self.cwvl
192
193
        sun_zenith = np.array([67., 32.])
194
        sat_zenith = np.array([45., 18.])
195
        azidiff = np.array([150., 110.])
196
        blueband = np.array([14., 5.])
197
        retv = self.viirs_rayleigh.get_reflectance(
198
            sun_zenith, sat_zenith, azidiff, 'M2', blueband)
199
        self.assertTrue(np.allclose(retv, TEST_RAYLEIGH_RESULT1))
200
201
        sun_zenith = np.array([60., 20.])
202
        sat_zenith = np.array([49., 26.])
203
        azidiff = np.array([140., 130.])
204
        blueband = np.array([12., 8.])
205
        retv = self.viirs_rayleigh.get_reflectance(
206
            sun_zenith, sat_zenith, azidiff, 'M2', blueband)
207
        self.assertTrue(np.allclose(retv, TEST_RAYLEIGH_RESULT2))
208
209
    @patch('os.path.exists')
210
    @patch('pyspectral.utils.download_luts')
211
    @patch('pyspectral.rayleigh.get_reflectance_lut')
212
    @patch('pyspectral.rsr_reader.RelativeSpectralResponse.'
213
           '_get_rsr_data_version')
214
    @patch('pyspectral.rayleigh.Rayleigh.get_effective_wavelength')
215
    def test_get_reflectance_dask(self, get_effective_wvl,
216
                                  get_rsr_version, get_reflectance_lut,
217
                                  download_luts, exists):
218
        """Test getting the reflectance correction with dask inputs"""
219
220
        import dask.array as da
221
        rayl = da.from_array(TEST_RAYLEIGH_LUT, chunks=(10, 10, 10, 10))
222
        wvl_coord = da.from_array(TEST_RAYLEIGH_WVL_COORD,
223
                                  chunks=(100,)).persist()
224
        azid_coord = da.from_array(TEST_RAYLEIGH_AZID_COORD, chunks=(1000,))
225
        sunz_sec_coord = da.from_array(TEST_RAYLEIGH_SUNZ_COORD,
226
                                       chunks=(1000,))
227
        satz_sec_coord = da.from_array(TEST_RAYLEIGH_SATZ_COORD,
228
                                       chunks=(1000,))
229
230
        get_reflectance_lut.return_value = (rayl, wvl_coord, azid_coord,
231
                                            satz_sec_coord, sunz_sec_coord)
232
        download_luts.return_code = None
233
        exists.return_code = True
234
        get_rsr_version.return_code = RSR_DATA_VERSION
235
        get_effective_wvl.return_value = self.cwvl
236
237
        sun_zenith = da.from_array(np.array([67., 32.]), chunks=2)
238
        sat_zenith = da.from_array(np.array([45., 18.]), chunks=2)
239
        azidiff = da.from_array(np.array([150., 110.]), chunks=2)
240
        blueband = da.from_array(np.array([14., 5.]), chunks=2)
241
        retv = self.viirs_rayleigh.get_reflectance(sun_zenith, sat_zenith, azidiff, 'M2', blueband)
242
        self.assertTrue(np.allclose(retv, TEST_RAYLEIGH_RESULT1))
243
        self.assertIsInstance(retv, da.Array)
244
245
        sun_zenith = da.from_array(np.array([60., 20.]), chunks=2)
246
        sat_zenith = da.from_array(np.array([49., 26.]), chunks=2)
247
        azidiff = da.from_array(np.array([140., 130.]), chunks=2)
248
        blueband = da.from_array(np.array([12., 8.]), chunks=2)
249
        retv = self.viirs_rayleigh.get_reflectance(sun_zenith, sat_zenith, azidiff, 'M2', blueband)
250
        self.assertTrue(np.allclose(retv, TEST_RAYLEIGH_RESULT2))
251
        self.assertIsInstance(retv, da.Array)
252
253
    @patch('pyspectral.rayleigh.HAVE_DASK', False)
254
    @patch('os.path.exists')
255
    @patch('pyspectral.utils.download_luts')
256
    @patch('pyspectral.rayleigh.get_reflectance_lut')
257
    def test_get_reflectance_no_rsr(self, get_reflectance_lut, download_luts, exists):
258
        """Test getting the reflectance correction, simulating that we have no RSR data"""
259
260
        rayl = TEST_RAYLEIGH_LUT
261
        wvl_coord = TEST_RAYLEIGH_WVL_COORD
262
        azid_coord = TEST_RAYLEIGH_AZID_COORD
263
        sunz_sec_coord = TEST_RAYLEIGH_SUNZ_COORD
264
        satz_sec_coord = TEST_RAYLEIGH_SATZ_COORD
265
266
        get_reflectance_lut.return_value = (rayl, wvl_coord, azid_coord,
267
                                            satz_sec_coord, sunz_sec_coord)
268
        download_luts.return_code = None
269
        exists.return_code = True
270
271
        with patch('pyspectral.rayleigh.RelativeSpectralResponse') as mymock:
272
            instance = mymock.return_value
273
            mymock.side_effect = IOError("No rsr data in pyspectral for this platform and sensor")
274
            instance.rsr = None
275
            instance.unit = '1e-6 m'
276
            instance.si_scale = 1e-6
277
            sun_zenith = np.array([50., 10.])
278
            sat_zenith = np.array([39., 16.])
279
            azidiff = np.array([170., 110.])
280
            blueband = np.array([29., 12.])
281
            ufo = rayleigh.Rayleigh('UFO', 'unknown')
282
283
            retv = ufo.get_reflectance(sun_zenith, sat_zenith, azidiff, 0.441, blueband)
284
            self.assertTrue(np.allclose(retv, TEST_RAYLEIGH_RESULT3))
285
286
    def tearDown(self):
287
        """Clean up"""
288
        pass
289
290
291
def suite():
292
    """The test suite for test_rayleigh.
293
    """
294
    loader = unittest.TestLoader()
295
    mysuite = unittest.TestSuite()
296
    mysuite.addTest(loader.loadTestsFromTestCase(TestRayleigh))
297
298
    return mysuite
299