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

TestRayleigh.test_get_reflectance_numpy_dask()   B

Complexity

Conditions 1

Size

Total Lines 41

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
c 1
b 0
f 0
dl 0
loc 41
rs 8.8571
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
        rayl = da.from_array(TEST_RAYLEIGH_LUT, chunks=(10, 10, 10, 10))
220
        wvl_coord = da.from_array(TEST_RAYLEIGH_WVL_COORD,
221
                                  chunks=(100,)).persist()
222
        azid_coord = da.from_array(TEST_RAYLEIGH_AZID_COORD, chunks=(1000,))
223
        sunz_sec_coord = da.from_array(TEST_RAYLEIGH_SUNZ_COORD,
224
                                       chunks=(1000,))
225
        satz_sec_coord = da.from_array(TEST_RAYLEIGH_SATZ_COORD,
226
                                       chunks=(1000,))
227
228
        get_reflectance_lut.return_value = (rayl, wvl_coord, azid_coord,
229
                                            satz_sec_coord, sunz_sec_coord)
230
        download_luts.return_code = None
231
        exists.return_code = True
232
        get_rsr_version.return_code = RSR_DATA_VERSION
233
        get_effective_wvl.return_value = self.cwvl
234
235
        sun_zenith = da.from_array(np.array([67., 32.]), chunks=2)
236
        sat_zenith = da.from_array(np.array([45., 18.]), chunks=2)
237
        azidiff = da.from_array(np.array([150., 110.]), chunks=2)
238
        blueband = da.from_array(np.array([14., 5.]), chunks=2)
239
        retv = self.viirs_rayleigh.get_reflectance(sun_zenith, sat_zenith, azidiff, 'M2', blueband)
240
        self.assertTrue(np.allclose(retv, TEST_RAYLEIGH_RESULT1))
241
        self.assertIsInstance(retv, da.Array)
242
243
        sun_zenith = da.from_array(np.array([60., 20.]), chunks=2)
244
        sat_zenith = da.from_array(np.array([49., 26.]), chunks=2)
245
        azidiff = da.from_array(np.array([140., 130.]), chunks=2)
246
        blueband = da.from_array(np.array([12., 8.]), chunks=2)
247
        retv = self.viirs_rayleigh.get_reflectance(sun_zenith, sat_zenith, azidiff, 'M2', blueband)
248
        self.assertTrue(np.allclose(retv, TEST_RAYLEIGH_RESULT2))
249
        self.assertIsInstance(retv, da.Array)
250
251
    @patch('os.path.exists')
252
    @patch('pyspectral.utils.download_luts')
253
    @patch('pyspectral.rayleigh.get_reflectance_lut')
254
    @patch('pyspectral.rsr_reader.RelativeSpectralResponse.'
255
           '_get_rsr_data_version')
256
    @patch('pyspectral.rayleigh.Rayleigh.get_effective_wavelength')
257
    def test_get_reflectance_numpy_dask(self, get_effective_wvl,
258
                                        get_rsr_version, get_reflectance_lut,
259
                                        download_luts, exists):
260
        """Test getting the reflectance correction with dask inputs"""
261
        rayl = da.from_array(TEST_RAYLEIGH_LUT, chunks=(10, 10, 10, 10))
262
        wvl_coord = da.from_array(TEST_RAYLEIGH_WVL_COORD,
263
                                  chunks=(100,)).persist()
264
        azid_coord = da.from_array(TEST_RAYLEIGH_AZID_COORD, chunks=(1000,))
265
        sunz_sec_coord = da.from_array(TEST_RAYLEIGH_SUNZ_COORD,
266
                                       chunks=(1000,))
267
        satz_sec_coord = da.from_array(TEST_RAYLEIGH_SATZ_COORD,
268
                                       chunks=(1000,))
269
270
        get_reflectance_lut.return_value = (rayl, wvl_coord, azid_coord,
271
                                            satz_sec_coord, sunz_sec_coord)
272
        download_luts.return_code = None
273
        exists.return_code = True
274
        get_rsr_version.return_code = RSR_DATA_VERSION
275
        get_effective_wvl.return_value = self.cwvl
276
277
        sun_zenith = np.array([67., 32.])
278
        sat_zenith = np.array([45., 18.])
279
        azidiff = np.array([150., 110.])
280
        blueband = np.array([14., 5.])
281
        retv = self.viirs_rayleigh.get_reflectance(sun_zenith, sat_zenith, azidiff, 'M2', blueband)
282
        self.assertTrue(np.allclose(retv, TEST_RAYLEIGH_RESULT1))
283
        self.assertIsInstance(retv, np.ndarray)
284
285
        sun_zenith = np.array([60., 20.])
286
        sat_zenith = np.array([49., 26.])
287
        azidiff = np.array([140., 130.])
288
        blueband = np.array([12., 8.])
289
        retv = self.viirs_rayleigh.get_reflectance(sun_zenith, sat_zenith, azidiff, 'M2', blueband)
290
        self.assertTrue(np.allclose(retv, TEST_RAYLEIGH_RESULT2))
291
        self.assertIsInstance(retv, np.ndarray)
292
293
    @patch('pyspectral.rayleigh.HAVE_DASK', False)
294
    @patch('os.path.exists')
295
    @patch('pyspectral.utils.download_luts')
296
    @patch('pyspectral.rayleigh.get_reflectance_lut')
297
    def test_get_reflectance_no_rsr(self, get_reflectance_lut, download_luts, exists):
298
        """Test getting the reflectance correction, simulating that we have no RSR data"""
299
300
        rayl = TEST_RAYLEIGH_LUT
301
        wvl_coord = TEST_RAYLEIGH_WVL_COORD
302
        azid_coord = TEST_RAYLEIGH_AZID_COORD
303
        sunz_sec_coord = TEST_RAYLEIGH_SUNZ_COORD
304
        satz_sec_coord = TEST_RAYLEIGH_SATZ_COORD
305
306
        get_reflectance_lut.return_value = (rayl, wvl_coord, azid_coord,
307
                                            satz_sec_coord, sunz_sec_coord)
308
        download_luts.return_code = None
309
        exists.return_code = True
310
311
        with patch('pyspectral.rayleigh.RelativeSpectralResponse') as mymock:
312
            instance = mymock.return_value
313
            mymock.side_effect = IOError("No rsr data in pyspectral for this platform and sensor")
314
            instance.rsr = None
315
            instance.unit = '1e-6 m'
316
            instance.si_scale = 1e-6
317
            sun_zenith = np.array([50., 10.])
318
            sat_zenith = np.array([39., 16.])
319
            azidiff = np.array([170., 110.])
320
            blueband = np.array([29., 12.])
321
            ufo = rayleigh.Rayleigh('UFO', 'unknown')
322
323
            retv = ufo.get_reflectance(sun_zenith, sat_zenith, azidiff, 0.441, blueband)
324
            self.assertTrue(np.allclose(retv, TEST_RAYLEIGH_RESULT3))
325
326
    def tearDown(self):
327
        """Clean up"""
328
        pass
329
330
331
def suite():
332
    """The test suite for test_rayleigh.
333
    """
334
    loader = unittest.TestLoader()
335
    mysuite = unittest.TestSuite()
336
    mysuite.addTest(loader.loadTestsFromTestCase(TestRayleigh))
337
338
    return mysuite
339