diff --git a/satpy/composites/viirs.py b/satpy/composites/viirs.py index 3409ff1154..249a9a0cd5 100644 --- a/satpy/composites/viirs.py +++ b/satpy/composites/viirs.py @@ -268,7 +268,7 @@ def _saturation_correction(self, dnb_data, unit_factor, min_val, max_val)) / dnb_data.size LOG.debug("Dynamic DNB saturation percentage: %f", saturation_pct) while saturation_pct > 0.005: - max_val *= 1.1 * unit_factor + max_val *= 1.1 saturation_pct = float(np.count_nonzero( dnb_data > max_val)) / dnb_data.size LOG.debug("Dynamic DNB saturation percentage: %f", diff --git a/satpy/tests/compositor_tests/test_viirs.py b/satpy/tests/compositor_tests/test_viirs.py index 885279918c..820bd40d38 100644 --- a/satpy/tests/compositor_tests/test_viirs.py +++ b/satpy/tests/compositor_tests/test_viirs.py @@ -17,11 +17,15 @@ # satpy. If not, see . """Tests for VIIRS compositors.""" -import unittest +import dask.array as da +import numpy as np +import pytest +import xarray as xr +from pyresample.geometry import AreaDefinition -class TestVIIRSComposites(unittest.TestCase): - """Test VIIRS-specific composites.""" +class TestVIIRSComposites: + """Test various VIIRS-specific composites.""" def test_load_composite_yaml(self): """Test loading the yaml for this sensor.""" @@ -30,11 +34,6 @@ def test_load_composite_yaml(self): def test_histogram_dnb(self): """Test the 'histogram_dnb' compositor.""" - import dask.array as da - import numpy as np - import xarray as xr - from pyresample.geometry import AreaDefinition - from satpy.composites.viirs import HistogramDNB rows = 5 cols = 10 @@ -64,22 +63,16 @@ def test_histogram_dnb(self): dims=('y', 'x'), attrs={'name': 'solar_zenith_angle', 'area': area}) res = comp((c01, c02)) - self.assertIsInstance(res, xr.DataArray) - self.assertIsInstance(res.data, da.Array) - self.assertEqual(res.attrs['name'], 'histogram_dnb') - self.assertEqual(res.attrs['standard_name'], - 'equalized_radiance') + assert isinstance(res, xr.DataArray) + assert isinstance(res.data, da.Array) + assert res.attrs['name'] == 'histogram_dnb' + assert res.attrs['standard_name'] == 'equalized_radiance' data = res.compute() unique_values = np.unique(data) np.testing.assert_allclose(unique_values, [0.5994, 0.7992, 0.999], rtol=1e-3) def test_adaptive_dnb(self): """Test the 'adaptive_dnb' compositor.""" - import dask.array as da - import numpy as np - import xarray as xr - from pyresample.geometry import AreaDefinition - from satpy.composites.viirs import AdaptiveDNB rows = 5 cols = 10 @@ -108,22 +101,16 @@ def test_adaptive_dnb(self): dims=('y', 'x'), attrs={'name': 'solar_zenith_angle', 'area': area}) res = comp((c01, c02)) - self.assertIsInstance(res, xr.DataArray) - self.assertIsInstance(res.data, da.Array) - self.assertEqual(res.attrs['name'], 'adaptive_dnb') - self.assertEqual(res.attrs['standard_name'], - 'equalized_radiance') + assert isinstance(res, xr.DataArray) + assert isinstance(res.data, da.Array) + assert res.attrs['name'] == 'adaptive_dnb' + assert res.attrs['standard_name'] == 'equalized_radiance' data = res.compute() np.testing.assert_allclose(data.data, 0.999, rtol=1e-4) - def test_erf_dnb(self): - """Test the 'dynamic_dnb' or ERF DNB compositor.""" - import dask.array as da - import numpy as np - import xarray as xr - from pyresample.geometry import AreaDefinition - - from satpy.composites.viirs import ERFDNB + def test_hncc_dnb(self): + """Test the 'hncc_dnb' compositor.""" + from satpy.composites.viirs import NCCZinke rows = 5 cols = 10 area = AreaDefinition( @@ -133,11 +120,10 @@ def test_erf_dnb(self): cols, rows, (-20037508.34, -10018754.17, 20037508.34, 10018754.17)) - comp = ERFDNB('dynamic_dnb', prerequisites=('dnb',), - standard_name='toa_outgoing_radiance_per_' - 'unit_wavelength') + comp = NCCZinke('hncc_dnb', prerequisites=('dnb',), + standard_name='toa_outgoing_radiance_per_' + 'unit_wavelength') dnb = np.zeros((rows, cols)) + 0.25 - dnb[2, :cols // 2] = np.nan dnb[3, :] += 0.25 dnb[4:, :] += 0.5 dnb = da.from_array(dnb, chunks=25) @@ -162,28 +148,22 @@ def test_erf_dnb(self): dims=('y',), attrs={'name': 'moon_illumination_fraction', 'area': area}) res = comp((c01, c02, c03, mif)) - self.assertIsInstance(res, xr.DataArray) - self.assertIsInstance(res.data, da.Array) - self.assertEqual(res.attrs['name'], 'dynamic_dnb') - self.assertEqual(res.attrs['standard_name'], - 'equalized_radiance') + assert isinstance(res, xr.DataArray) + assert isinstance(res.data, da.Array) + assert res.attrs['name'] == 'hncc_dnb' + assert res.attrs['standard_name'] == 'ncc_radiance' data = res.compute() unique = np.unique(data) - assert np.isnan(unique).any() - nonnan_unique = unique[~np.isnan(unique)] np.testing.assert_allclose( - nonnan_unique, - [0.00000000e+00, 1.00446703e-01, 1.64116082e-01, 2.09233451e-01, - 1.43916324e+02, 2.03528498e+02, 2.49270516e+02]) - - def test_hncc_dnb(self): - """Test the 'hncc_dnb' compositor.""" - import dask.array as da - import numpy as np - import xarray as xr - from pyresample.geometry import AreaDefinition + unique, [3.48479712e-04, 6.96955799e-04, 1.04543189e-03, 4.75394738e-03, + 9.50784532e-03, 1.42617433e-02, 1.50001560e+03, 3.00001560e+03, + 4.50001560e+03]) - from satpy.composites.viirs import NCCZinke + @pytest.mark.parametrize("dnb_units", ["W m-2 sr-1", "W cm-2 sr-1"]) + @pytest.mark.parametrize("saturation_correction", [False, True]) + def test_erf_dnb(self, dnb_units, saturation_correction): + """Test the 'dynamic_dnb' or ERF DNB compositor.""" + from satpy.composites.viirs import ERFDNB rows = 5 cols = 10 area = AreaDefinition( @@ -193,16 +173,20 @@ def test_hncc_dnb(self): cols, rows, (-20037508.34, -10018754.17, 20037508.34, 10018754.17)) - comp = NCCZinke('hncc_dnb', prerequisites=('dnb',), - standard_name='toa_outgoing_radiance_per_' - 'unit_wavelength') + comp = ERFDNB('dynamic_dnb', prerequisites=('dnb',), + saturation_correction=saturation_correction, + standard_name='toa_outgoing_radiance_per_' + 'unit_wavelength') dnb = np.zeros((rows, cols)) + 0.25 + dnb[2, :cols // 2] = np.nan dnb[3, :] += 0.25 dnb[4:, :] += 0.5 + if dnb_units == "W cm-2 sr-1": + dnb /= 10000.0 dnb = da.from_array(dnb, chunks=25) c01 = xr.DataArray(dnb, dims=('y', 'x'), - attrs={'name': 'DNB', 'area': area}) + attrs={'name': 'DNB', 'area': area, 'units': dnb_units}) sza = np.zeros((rows, cols)) + 70.0 sza[:, 3] += 20.0 sza[:, 4:] += 45.0 @@ -221,14 +205,20 @@ def test_hncc_dnb(self): dims=('y',), attrs={'name': 'moon_illumination_fraction', 'area': area}) res = comp((c01, c02, c03, mif)) - self.assertIsInstance(res, xr.DataArray) - self.assertIsInstance(res.data, da.Array) - self.assertEqual(res.attrs['name'], 'hncc_dnb') - self.assertEqual(res.attrs['standard_name'], - 'ncc_radiance') + assert isinstance(res, xr.DataArray) + assert isinstance(res.data, da.Array) + assert res.attrs['name'] == 'dynamic_dnb' + assert res.attrs['standard_name'] == 'equalized_radiance' data = res.compute() unique = np.unique(data) - np.testing.assert_allclose( - unique, [3.48479712e-04, 6.96955799e-04, 1.04543189e-03, 4.75394738e-03, - 9.50784532e-03, 1.42617433e-02, 1.50001560e+03, 3.00001560e+03, - 4.50001560e+03]) + assert np.isnan(unique).any() + nonnan_unique = unique[~np.isnan(unique)] + if saturation_correction: + exp_unique = [0.000000e+00, 3.978305e-04, 6.500003e-04, + 8.286927e-04, 5.628335e-01, 7.959671e-01, + 9.748567e-01] + else: + exp_unique = [0.00000000e+00, 1.00446703e-01, 1.64116082e-01, + 2.09233451e-01, 1.43916324e+02, 2.03528498e+02, + 2.49270516e+02] + np.testing.assert_allclose(nonnan_unique, exp_unique)