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 datetime as dt
import unittest
import unittest.mock as mock

import numpy as np
import pytest
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 = dt.datetime.strptime(self.start_time, "%Y-%m-%dT%H:%M:%S.%fZ") good_end = dt.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" with pytest.warns(UserWarning, match=r"No radiance adjustment supplied for channel"): test.get_dataset(ds_id, dict(filename_info, **{"file_key": "foo"})) assert test.start_time == good_start assert 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"})) assert test.start_time == good_start assert 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}"})) assert test.start_time == good_start assert 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" assert test.start_time == good_start assert 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}"})) assert test.start_time == good_start assert 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 pytest.warns(UserWarning, match=r"No radiance adjustment supplied for channel"): test.get_dataset(ds_id, dict(filename_info, **{"file_key": "foo"})) # 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"})) assert 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)