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

TestRayleigh.test_get_reflectance_no_rsr()   B

Complexity

Conditions 2

Size

Total Lines 32

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 0 Features 1
Metric Value
cc 2
dl 0
loc 32
rs 8.8571
c 2
b 0
f 1
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('pyspectral.rayleigh.HAVE_DASK', False)
252
    @patch('os.path.exists')
253
    @patch('pyspectral.utils.download_luts')
254
    @patch('pyspectral.rayleigh.get_reflectance_lut')
255
    def test_get_reflectance_no_rsr(self, get_reflectance_lut, download_luts, exists):
256
        """Test getting the reflectance correction, simulating that we have no RSR data"""
257
258
        rayl = TEST_RAYLEIGH_LUT
259
        wvl_coord = TEST_RAYLEIGH_WVL_COORD
260
        azid_coord = TEST_RAYLEIGH_AZID_COORD
261
        sunz_sec_coord = TEST_RAYLEIGH_SUNZ_COORD
262
        satz_sec_coord = TEST_RAYLEIGH_SATZ_COORD
263
264
        get_reflectance_lut.return_value = (rayl, wvl_coord, azid_coord,
265
                                            satz_sec_coord, sunz_sec_coord)
266
        download_luts.return_code = None
267
        exists.return_code = True
268
269
        with patch('pyspectral.rayleigh.RelativeSpectralResponse') as mymock:
270
            instance = mymock.return_value
271
            mymock.side_effect = IOError("No rsr data in pyspectral for this platform and sensor")
272
            instance.rsr = None
273
            instance.unit = '1e-6 m'
274
            instance.si_scale = 1e-6
275
            sun_zenith = np.array([50., 10.])
276
            sat_zenith = np.array([39., 16.])
277
            azidiff = np.array([170., 110.])
278
            blueband = np.array([29., 12.])
279
            ufo = rayleigh.Rayleigh('UFO', 'unknown')
280
281
            retv = ufo.get_reflectance(sun_zenith, sat_zenith, azidiff, 0.441, blueband)
282
            self.assertTrue(np.allclose(retv, TEST_RAYLEIGH_RESULT3))
283
284
    def tearDown(self):
285
        """Clean up"""
286
        pass
287
288
289
def suite():
290
    """The test suite for test_rayleigh.
291
    """
292
    loader = unittest.TestLoader()
293
    mysuite = unittest.TestSuite()
294
    mysuite.addTest(loader.loadTestsFromTestCase(TestRayleigh))
295
296
    return mysuite
297