Source code for satpy.tests.reader_tests.test_slstr_l1b

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# Copyright (c) 2018 Satpy developers
#
# This file is part of satpy.
#
# satpy is free software: you can redistribute it and/or modify it under the
# terms of the GNU General Public License as published by the Free Software
# Foundation, either version 3 of the License, or (at your option) any later
# version.
#
# satpy is distributed in the hope that it will be useful, but WITHOUT ANY
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
# A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License along with
# satpy.  If not, see <http://www.gnu.org/licenses/>.
"""Module for testing the satpy.readers.nc_slstr module."""
import unittest
import unittest.mock as mock
import warnings
from datetime import datetime

import numpy as np
import xarray as xr

from satpy.dataset.dataid import DataID, ModifierTuple, WavelengthRange
from satpy.readers.slstr_l1b import NCSLSTR1B, NCSLSTRAngles, NCSLSTRFlag, NCSLSTRGeo

local_id_keys_config = {'name': {
    'required': True,
},
    'wavelength': {
        'type': WavelengthRange,
    },
    'resolution': None,
    'calibration': {
        'enum': [
            'reflectance',
            'brightness_temperature',
            'radiance',
            'counts'
        ]
    },
    'stripe': {
        'enum': [
            'a',
            'b',
            'c',
            'i',
            'f',
        ]
    },
    'view': {
        'enum': [
            'nadir',
            'oblique',
        ]
    },
    'modifiers': {
        'required': True,
        'default': ModifierTuple(),
        'type': ModifierTuple,
    },
}


[docs] class TestSLSTRL1B(unittest.TestCase): """Common setup for SLSTR_L1B tests."""
[docs] @mock.patch('satpy.readers.slstr_l1b.xr') def setUp(self, xr_): """Create a fake dataset using the given radiance data.""" self.base_data = np.array(([1., 2., 3.], [4., 5., 6.])) self.det_data = np.array(([0, 1, 1], [0, 1, 0])) self.start_time = "2020-05-10T12:01:15.585Z" self.end_time = "2020-05-10T12:06:18.012Z" self.rad = xr.DataArray( self.base_data, dims=('columns', 'rows'), attrs={'scale_factor': 1.0, 'add_offset': 0.0, '_FillValue': -32768, 'units': 'mW.m-2.sr-1.nm-1', } ) det = xr.DataArray( self.base_data, dims=('columns', 'rows'), attrs={'scale_factor': 1.0, 'add_offset': 0.0, '_FillValue': 255, } ) self.fake_dataset = xr.Dataset( data_vars={ 'S5_radiance_an': self.rad, 'S9_BT_ao': self.rad, 'foo_radiance_an': self.rad, 'S5_solar_irradiances': self.rad, 'geometry_tn': self.rad, 'latitude_an': self.rad, 'x_tx': self.rad, 'y_tx': self.rad, 'x_in': self.rad, 'y_in': self.rad, 'x_an': self.rad, 'y_an': self.rad, 'flags_an': self.rad, 'detector_an': det, }, attrs={ "start_time": self.start_time, "stop_time": self.end_time, }, )
[docs] def make_dataid(**items): """Make a data id.""" return DataID(local_id_keys_config, **items)
[docs] class TestSLSTRReader(TestSLSTRL1B): """Test various nc_slstr file handlers."""
[docs] class FakeSpl: """Fake return function for SPL interpolation."""
[docs] @staticmethod def ev(foo_x, foo_y): """Fake function to return interpolated data.""" return np.zeros((3, 2))
[docs] @mock.patch('satpy.readers.slstr_l1b.xr') @mock.patch('scipy.interpolate.RectBivariateSpline') def test_instantiate(self, bvs_, xr_): """Test initialization of file handlers.""" bvs_.return_value = self.FakeSpl xr_.open_dataset.return_value = self.fake_dataset good_start = datetime.strptime(self.start_time, '%Y-%m-%dT%H:%M:%S.%fZ') good_end = datetime.strptime(self.end_time, '%Y-%m-%dT%H:%M:%S.%fZ') ds_id = make_dataid(name='foo', calibration='radiance', stripe='a', view='nadir') ds_id_500 = make_dataid(name='foo', calibration='radiance', stripe='a', view='nadir', resolution=500) filename_info = {'mission_id': 'S3A', 'dataset_name': 'foo', 'start_time': 0, 'end_time': 0, 'stripe': 'a', 'view': 'n'} test = NCSLSTR1B('somedir/S1_radiance_an.nc', filename_info, 'c') assert test.view == 'nadir' assert test.stripe == 'a' test.get_dataset(ds_id, dict(filename_info, **{'file_key': 'foo'})) self.assertEqual(test.start_time, good_start) self.assertEqual(test.end_time, good_end) xr_.open_dataset.assert_called() xr_.open_dataset.reset_mock() filename_info = {'mission_id': 'S3A', 'dataset_name': 'foo', 'start_time': 0, 'end_time': 0, 'stripe': 'c', 'view': 'o'} test = NCSLSTR1B('somedir/S1_radiance_co.nc', filename_info, 'c') assert test.view == 'oblique' assert test.stripe == 'c' test.get_dataset(ds_id, dict(filename_info, **{'file_key': 'foo'})) self.assertEqual(test.start_time, good_start) self.assertEqual(test.end_time, good_end) xr_.open_dataset.assert_called() xr_.open_dataset.reset_mock() filename_info = {'mission_id': 'S3A', 'dataset_name': 'foo', 'start_time': 0, 'end_time': 0, 'stripe': 'a', 'view': 'n'} test = NCSLSTRGeo('somedir/geometry_an.nc', filename_info, 'c') test.get_dataset(ds_id, dict(filename_info, **{'file_key': 'latitude_{stripe:1s}{view:1s}'})) self.assertEqual(test.start_time, good_start) self.assertEqual(test.end_time, good_end) xr_.open_dataset.assert_called() xr_.open_dataset.reset_mock() test = NCSLSTRFlag('somedir/S1_radiance_an.nc', filename_info, 'c') test.get_dataset(ds_id, dict(filename_info, **{'file_key': 'flags_{stripe:1s}{view:1s}'})) assert test.view == 'nadir' assert test.stripe == 'a' self.assertEqual(test.start_time, good_start) self.assertEqual(test.end_time, good_end) xr_.open_dataset.assert_called() xr_.open_dataset.reset_mock() test = NCSLSTRAngles('somedir/S1_radiance_an.nc', filename_info, 'c') test.get_dataset(ds_id, dict(filename_info, **{'file_key': 'geometry_t{view:1s}'})) self.assertEqual(test.start_time, good_start) self.assertEqual(test.end_time, good_end) xr_.open_dataset.assert_called() xr_.open_dataset.reset_mock() test.get_dataset(ds_id_500, dict(filename_info, **{'file_key': 'geometry_t{view:1s}'}))
[docs] class TestSLSTRCalibration(TestSLSTRL1B): """Test the implementation of the calibration factors."""
[docs] @mock.patch('satpy.readers.slstr_l1b.xr') def test_radiance_calibration(self, xr_): """Test radiance calibration steps.""" from satpy.readers.slstr_l1b import CHANCALIB_FACTORS xr_.open_dataset.return_value = self.fake_dataset ds_id = make_dataid(name='foo', calibration='radiance', stripe='a', view='nadir') filename_info = {'mission_id': 'S3A', 'dataset_name': 'foo', 'start_time': 0, 'end_time': 0, 'stripe': 'a', 'view': 'n'} test = NCSLSTR1B('somedir/S1_radiance_co.nc', filename_info, 'c') # Check warning is raised if we don't have calibration with warnings.catch_warnings(record=True) as w: test.get_dataset(ds_id, dict(filename_info, **{'file_key': 'foo'})) assert issubclass(w[-1].category, UserWarning) # Check user calibration is used correctly test = NCSLSTR1B('somedir/S1_radiance_co.nc', filename_info, 'c', user_calibration={'foo_nadir': 0.4}) data = test.get_dataset(ds_id, dict(filename_info, **{'file_key': 'foo'})) np.testing.assert_allclose(data.values, self.base_data * 0.4) # Check internal calibration is used correctly ds_id = make_dataid(name='S5', calibration='radiance', stripe='a', view='nadir') filename_info['dataset_name'] = 'S5' test = NCSLSTR1B('somedir/S1_radiance_an.nc', filename_info, 'c') data = test.get_dataset(ds_id, dict(filename_info, **{'file_key': 'S5'})) np.testing.assert_allclose(data.values, self.base_data * CHANCALIB_FACTORS['S5_nadir'])
[docs] @mock.patch('satpy.readers.slstr_l1b.xr') @mock.patch('satpy.readers.slstr_l1b.da') def test_reflectance_calibration(self, da_, xr_): """Test reflectance calibration.""" xr_.open_dataset.return_value = self.fake_dataset da_.map_blocks.return_value = self.rad / 100. filename_info = {'mission_id': 'S3A', 'dataset_name': 'S5', 'start_time': 0, 'end_time': 0, 'stripe': 'a', 'view': 'n'} ds_id = make_dataid(name='S5', calibration='reflectance', stripe='a', view='nadir') test = NCSLSTR1B('somedir/S1_radiance_an.nc', filename_info, 'c') data = test.get_dataset(ds_id, dict(filename_info, **{'file_key': 'S5'})) self.assertEqual(data.units, '%') np.testing.assert_allclose(data.values, self.rad * np.pi)
[docs] def test_cal_rad(self): """Test the radiance to reflectance converter.""" rad = np.array([10., 20., 30., 40., 50., 60., 70.]) didx = np.array([1, 2., 1., 3., 2., 2., 0.]) solflux = np.array([100., 200., 300., 400.]) good_rad = np.array([1. / 20., 1. / 15., 3. / 20., 1. / 10., 1. / 6., 2. / 10., 7. / 10.]) out_rad = NCSLSTR1B._cal_rad(rad, didx, solflux) np.testing.assert_allclose(out_rad, good_rad)