Completed
Pull Request — develop (#12)
by Adam
52s
created

RelativeSpectralResponse._check_instrument()   A

Complexity

Conditions 2

Size

Total Lines 11

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 2
dl 0
loc 11
rs 9.4285
c 1
b 0
f 0
1
#!/usr/bin/env python
2
# -*- coding: utf-8 -*-
3
4
# Copyright (c) 2014-2017 Adam.Dybbroe
5
6
# Author(s):
7
8
#   Adam.Dybbroe <[email protected]>
9
#   Panu Lahtinen <[email protected]>
10
11
# This program is free software: you can redistribute it and/or modify
12
# it under the terms of the GNU General Public License as published by
13
# the Free Software Foundation, either version 3 of the License, or
14
# (at your option) any later version.
15
16
# This program is distributed in the hope that it will be useful,
17
# but WITHOUT ANY WARRANTY; without even the implied warranty of
18
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19
# GNU General Public License for more details.
20
21
# You should have received a copy of the GNU General Public License
22
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
23
24
"""Reading the spectral responses in the internal pyspectral hdf5 format"""
25
26
import os
27
import numpy as np
28
from glob import glob
29
from os.path import expanduser
30
31
import logging
32
LOG = logging.getLogger(__name__)
33
34
from pyspectral import get_config
35
36
WAVL = 'wavelength'
37
WAVN = 'wavenumber'
38
39
from pyspectral.utils import (INSTRUMENTS, download_rsr)
40
41
42
class RelativeSpectralResponse(object):
43
44
    """Container for the relative spectral response functions for various
45
    satellite imagers
46
    """
47
48
    def __init__(self, platform_name=None, instrument=None, **kwargs):
49
        self.platform_name = platform_name
50
        self.instrument = instrument
51
        self.filename = None
52
        if not self.instrument or not self.platform_name:
53
            if 'filename' in kwargs:
54
                self.filename = kwargs['filename']
55
            else:
56
                raise IOError(
57
                    "platform name and sensor or filename must be specified")
58
        else:
59
            self._check_instrument()
60
61
        self.rsr = {}
62
        self.description = "Unknown"
63
        self.band_names = None
64
        self.unit = '1e-6 m'
65
        self.si_scale = 1e-6  # How to scale the wavelengths to become SI unit
66
        self._wavespace = WAVL
67
68
        options = get_config()
69
        self.rsr_dir = options['rsr_dir']
70
        if 'download_from_internet' in options and options['download_from_internet'] == 'True':
71
            self.do_download = True
72
        else:
73
            self.do_download = False
74
75
        if not self.filename:
76
            self._get_filename()
77
78
        if not os.path.exists(self.filename) or not os.path.isfile(self.filename):
79
            errmsg = ('pyspectral RSR file does not exist! Filename = ' +
80
                      str(self.filename))
81
            if self.instrument and self.platform_name:
82
                fmatch = glob(
83
                    os.path.join(self.rsr_dir, '*{0}*{1}*.h5'.format(self.instrument,
84
                                                                     self.platform_name)))
85
                errmsg = (errmsg +
86
                          '\nFiles matching instrument and satellite platform' +
87
                          ': ' + str(fmatch))
88
89
            raise IOError(errmsg)
90
91
        LOG.debug('Filename: %s', str(self.filename))
92
        self.load()
93
94
    def _check_instrument(self):
95
        """Check and try correct instrument name if needed"""
96
97
        # Try fix instrument naming
98
        instr = INSTRUMENTS.get(self.platform_name, self.instrument)
99
        if instr != self.instrument:
100
            self.instrument = instr
101
            LOG.warning("Inconsistent instrument/satellite input - " +
102
                        "instrument set to %s", self.instrument)
103
104
        self.instrument = self.instrument.replace('/', '')
105
106
    def _get_filename(self):
107
        """Get the rsr filname from platform and instrument names, and download if not
108
           available
109
        """
110
111
        self.filename = expanduser(
112
            os.path.join(self.rsr_dir, 'rsr_{0}_{1}.h5'.format(self.instrument,
113
                                                               self.platform_name)))
114
115
        LOG.debug('Filename: %s', str(self.filename))
116
117
        if not os.path.exists(self.filename) or not os.path.isfile(self.filename):
118
            # Try download from the internet!
119
            LOG.warning("No rsr file %s on disk", self.filename)
120
            if self.do_download:
121
                LOG.info("Will download from internet...")
122
                download_rsr()
123
124
    def load(self):
125
        """Read the internally formatet hdf5 relative spectral response data"""
126
        import h5py
127
128
        no_detectors_message = False
129
        with h5py.File(self.filename, 'r') as h5f:
130
            self.band_names = h5f.attrs['band_names'].tolist()
131
            self.description = h5f.attrs['description']
132
            if not self.platform_name:
133
                self.platform_name = h5f.attrs['platform_name']
134
            if not self.instrument:
135
                try:
136
                    self.instrument = h5f.attrs['sensor']
137
                except KeyError:
138
                    LOG.warning("No sensor name specified in HDF5 file")
139
                    self.instrument = INSTRUMENTS.get(self.platform_name)
140
141
            for bandname in self.band_names:
142
                self.rsr[bandname] = {}
143
                try:
144
                    num_of_det = h5f[bandname].attrs['number_of_detectors']
145
                except KeyError:
146
                    if not no_detectors_message:
147
                        LOG.debug("No detectors found - assume only one...")
148
                    num_of_det = 1
149
                    no_detectors_message = True
150
151
                for i in range(1, num_of_det + 1):
152
                    dname = 'det-{0:d}'.format(i)
153
                    self.rsr[bandname][dname] = {}
154
                    try:
155
                        resp = h5f[bandname][dname]['response'][:]
156
                    except KeyError:
157
                        resp = h5f[bandname]['response'][:]
158
159
                    self.rsr[bandname][dname]['response'] = resp
160
161
                    try:
162
                        wvl = (h5f[bandname][dname]['wavelength'][:] *
163
                               h5f[bandname][dname][
164
                                   'wavelength'].attrs['scale'])
165
                    except KeyError:
166
                        wvl = (h5f[bandname]['wavelength'][:] *
167
                               h5f[bandname]['wavelength'].attrs['scale'])
168
169
                    # The wavelength is given in micro meters!
170
                    self.rsr[bandname][dname]['wavelength'] = wvl * 1e6
171
172
                    try:
173
                        central_wvl = h5f[bandname][
174
                            dname].attrs['central_wavelength']
175
                    except KeyError:
176
                        central_wvl = h5f[bandname].attrs['central_wavelength']
177
178
                    self.rsr[bandname][dname][
179
                        'central_wavelength'] = central_wvl
180
181
    def integral(self, bandname):
182
        """Calculate the integral of the spectral response function for each
183
        detector.
184
        """
185
        intg = {}
186
        for det in self.rsr[bandname].keys():
187
            wvl = self.rsr[bandname][det]['wavelength']
188
            resp = self.rsr[bandname][det]['response']
189
            intg[det] = np.trapz(resp, wvl)
190
        return intg
191
192
    def convert(self):
193
        """Convert spectral response functions from wavelength to wavenumber"""
194
195
        from pyspectral.utils import convert2wavenumber
196
        if self._wavespace == WAVL:
197
            rsr, info = convert2wavenumber(self.rsr)
198
            for band in rsr.keys():
199
                for det in rsr[band].keys():
200
                    self.rsr[band][det]['wavenumber'] = rsr[
201
                        band][det]['wavenumber']
202
                    self.rsr[band][det]['response'] = rsr[
203
                        band][det]['response']
204
                    self.unit = info['unit']
205
                    self.si_scale = info['si_scale']
206
            self._wavespace = WAVN
207
        else:
208
            raise NotImplementedError("Conversion from wavenumber to " +
209
                                      "wavelength not supported yet")
210
211
212
def main():
213
    """Main"""
214
    modis = RelativeSpectralResponse('EOS-Terra', 'modis')
215
    del(modis)
216
217
if __name__ == "__main__":
218
    main()
219