From 29587e5e4bfec8329de12e46479ba4f59686737f Mon Sep 17 00:00:00 2001 From: Johan Strandgren Date: Wed, 20 May 2026 08:52:31 +0000 Subject: [PATCH 01/49] Refactor code for standard sunz angle correction and improve documentation and logging. --- satpy/modifiers/angles.py | 106 +++++++++++++++++++++++++----------- satpy/modifiers/geometry.py | 82 ++++++++++++++++++---------- 2 files changed, 127 insertions(+), 61 deletions(-) diff --git a/satpy/modifiers/angles.py b/satpy/modifiers/angles.py index 9ea6b008b0..a20147cb7c 100644 --- a/satpy/modifiers/angles.py +++ b/satpy/modifiers/angles.py @@ -20,6 +20,7 @@ import datetime as dt import hashlib +import logging import os import shutil import warnings @@ -41,6 +42,8 @@ PRGeometry: TypeAlias = SwathDefinition | AreaDefinition | StackedAreaDefinition +logger = logging.getLogger(__name__) + # Arbitrary time used when computing sensor angles that is passed to # pyorbital's get_observer_look function. # The difference is on the order of 1e-10 at most as time changes so we force @@ -533,54 +536,95 @@ def _get_sensor_angles_ndarray(lons, lats, start_time, sat_lon, sat_lat, sat_alt def sunzen_corr_cos(data: da.Array, cos_zen: da.Array, - limit: float = 88., + correction_limit: Optional[float] = 88., max_sza: Optional[float] = 95.) -> da.Array: - """Perform Sun zenith angle correction. + """Perform standard Sun zenith angle correction. + + The correction is based on the provided cosine of the solar zenith angle + (``cos_zen``) and the correction is applied by multiplying the input ``data`` + by the inverse of the ``cos_zen`` (``1/cos_zen``). + + Through different combinations of the ``correction_limit`` and ``max_sza`` + parameters, the correction can be capped or reduced at higher solar zenith angles. + See class definition of SunZenithCorrector for more details on how these parameters + can be used to tweak the correction. The typical historical use case is to avoid + over-correction at high solar zenith angles for improved (RGB) imagery, but not the + effective pathlength parameterization by Li and Shibata (2006) is recommended + when computing the reflectance for (RGB) imagery. This parameterization is availalbe + through the EffectiveSolarPathLengthCorrector class. - The correction is based on the provided cosine of the zenith - angle (``cos_zen``). The correction is limited - to ``limit`` degrees (default: 88.0 degrees). For larger zenith - angles, the correction is the same as at the ``limit`` if ``max_sza`` - is `None`. The default behavior is to gradually reduce the correction - past ``limit`` degrees up to ``max_sza`` where the correction becomes - 0. Both ``data`` and ``cos_zen`` should be 2D arrays of the same shape. + Both ``data`` and ``cos_zen`` should be 2D arrays of the same shape. """ return da.map_blocks(_sunzen_corr_cos_ndarray, - data, cos_zen, limit, max_sza, + data, cos_zen, correction_limit, max_sza, meta=np.array((), dtype=data.dtype), chunks=data.chunks) def _sunzen_corr_cos_ndarray(data: np.ndarray, cos_zen: np.ndarray, - limit: float, + correction_limit: Optional[float], max_sza: Optional[float]) -> np.ndarray: - # Convert the zenith angle limit to cosine of zenith angle - limit_rad = np.deg2rad(limit) - limit_cos = np.cos(limit_rad) - max_sza_rad = np.deg2rad(max_sza) if max_sza is not None else max_sza + sunz = np.rad2deg(np.arccos(cos_zen)) - # Cosine correction + # Start from standard cosine correction corr = (1. / cos_zen).astype(data.dtype, copy=False) - if max_sza is not None: - # gradually fall off for larger zenith angle - grad_factor = (np.arccos(cos_zen) - limit_rad) / (max_sza_rad - limit_rad) + + if correction_limit is not None: + corr_at_limit = 1. / np.cos(np.deg2rad(correction_limit)) + + if correction_limit is None and max_sza is None: + logger.debug("Apply the standard sun-zenith correction [1/cos(sunz)].") + # Nothing more to do, the standard correction is already applied above. + elif correction_limit is None and max_sza is not None: + logger.debug( + f"Apply the standard sun-zenith correction [1/cos(sunz)] but set correction (and reflectance) " + f"to 0 for angles larger than {max_sza} degrees." + ) + corr = np.where(sunz <= max_sza, corr, 0.).astype(data.dtype, copy=False) + elif correction_limit is not None and max_sza is None: + logger.debug( + f"Apply the standard sun-zenith correction [1/cos(sunz)] but cap the maximum correction " + f"for angles larger than {correction_limit} degrees." + ) + corr = np.where(sunz <= correction_limit, corr, corr_at_limit).astype(data.dtype, copy=False) + elif correction_limit is not None and max_sza is not None: + logger.debug( + f"Apply the standard sun-zenith correction [1/cos(sunz)] but gradually reduce the correction " + f"for angles larger than {correction_limit} degrees up to {max_sza} degrees where the " + f"correction (and reflectance) becomes 0." + ) + if max_sza <= correction_limit: + raise ValueError( + "max_sza should be larger than correction_limit for a gradual " + "reduction of the correction to work.") + reduction_factor = (sunz - correction_limit) / (max_sza - correction_limit) + # invert the factor so maximum correction is done at `limit` and falls off later with np.errstate(invalid="ignore"): # we expect space pixels to be invalid - grad_factor = 1. - np.log(grad_factor + 1) / np.log(2) - # make sure we don't make anything negative - grad_factor = grad_factor.clip(0.) - else: - # Use constant value (the limit) for larger zenith angles - grad_factor = 1. - corr = np.where( - cos_zen > limit_cos, - corr, - (grad_factor / limit_cos).astype(data.dtype, copy=False) - ) - # Force "night" pixels to 0 (where SZA is invalid) + reduction_factor = 1. - np.log(reduction_factor + 1) / np.log(2) + + corr_with_reduction = (corr_at_limit * reduction_factor).astype(data.dtype, copy=False) + + corr = np.where(sunz < correction_limit, corr, corr_with_reduction) + + if correction_limit is not None: + logger.warning( + "Capping or reducing the standard Sun zenith angle correction may lead to underesimated " + "reflectance values which is undesireble for scientific applications. To reduce the " + "overcorrection for (RGB) imagery the effective pathlength parameterization by Li and " + "Shibata (2006) is recommended over the standard correction. See " + "EffectiveSolarPathLengthCorrector for more details on this parameterization and how " + "to use it." + ) + + # Make sure we don't make anything negative + corr = corr.clip(0.) + + # Force "night" and space pixels to 0 (where SZA is invalid) corr[np.isnan(cos_zen)] = 0 + return data * corr diff --git a/satpy/modifiers/geometry.py b/satpy/modifiers/geometry.py index f2ae4a50c0..185d6485db 100644 --- a/satpy/modifiers/geometry.py +++ b/satpy/modifiers/geometry.py @@ -20,6 +20,7 @@ from __future__ import annotations import logging +from typing import Optional import numpy as np @@ -33,16 +34,8 @@ class SunZenithCorrectorBase(ModifierBase): """Base class for sun zenith correction modifiers.""" - def __init__(self, max_sza=95.0, **kwargs): # noqa: D417 - """Collect custom configuration values. - - Args: - max_sza (float): Maximum solar zenith angle in degrees that is - considered valid and correctable. Default 95.0. - - """ - self.max_sza = max_sza - self.max_sza_cos = np.cos(np.deg2rad(max_sza)) if max_sza is not None else None + def __init__(self, **kwargs): # noqa: D417 + """Collect custom configuration values.""" super(SunZenithCorrectorBase, self).__init__(**kwargs) def __call__(self, projectables, **info): @@ -53,14 +46,12 @@ def __call__(self, projectables, **info): logger.debug("Sun zenith correction already applied") return vis - logger.debug("Applying sun zen correction") + logger.debug("Applying Sun zenith angle correction") if not info.get("optional_datasets"): # we were not given SZA, generate cos(SZA) logger.debug("Computing sun zenith angles.") from .angles import get_cos_sza coszen = get_cos_sza(vis) - if self.max_sza is not None: - coszen = coszen.where(coszen >= self.max_sza_cos) else: # we were given the SZA, calculate the cos(SZA) coszen = np.cos(np.deg2rad(projectables[1])) @@ -75,46 +66,77 @@ def _apply_correction(self, proj, coszen): class SunZenithCorrector(SunZenithCorrectorBase): - """Standard sun zenith correction using ``1 / cos(sunz)``. + """Standard Sun zenith angle correction using ``1 / cos(sunz)``. - In addition to adjusting the provided reflectances by the cosine of the - solar zenith angle, this modifier forces all reflectances beyond a - solar zenith angle of ``max_sza`` to 0. It also gradually reduces the - amount of correction done between ``correction_limit`` and ``max_sza``. If - ``max_sza`` is ``None`` then a constant correction is applied to zenith - angles beyond ``correction_limit``. + Modes + ----- + The behavior of the correction depends on the combination of ``correction_limit`` and + ``max_sza``: - To set ``max_sza`` to ``None`` in a YAML configuration file use: + * ``correction_limit=None, max_sza=None``: + Apply pure ``1 / cos(sunz)`` correction everywhere. + + * ``correction_limit=None, max_sza=``: + Apply ``1 / cos(sunz)`` correction up to ``max_sza``. + Pixels with solar zenith angle > ``max_sza`` are set to 0. + + * ``correction_limit=, max_sza=None``: + Apply ``1 / cos(sunz)`` up to ``correction_limit``. + Beyond this limit, the correction is clamped to the value at + ``correction_limit`` (constant correction). + + * ``correction_limit=, max_sza=``: + Apply ``1 / cos(sunz)`` up to ``correction_limit``. + Between ``correction_limit`` and ``max_sza``, the correction is + gradually reduced to 0. + Pixels with solar zenith angle > ``max_sza`` are set to 0. + + Note that all corrections are undefined for ``cos(sunz) <= 0`` meaning that + the reflectance data are forced to zero. + + To configure this in a YAML configuration file setting e.g. ``max_sza`` to ``None`` use: .. code-block:: yaml sunz_corrected: modifier: !!python/name:satpy.modifiers.SunZenithCorrector + correction_limit: 88 max_sza: !!null optional_prerequisites: - solar_zenith_angle """ - def __init__(self, correction_limit=88., **kwargs): # noqa: D417 + def __init__( + self, + correction_limit: Optional[float] = 88.0, + max_sza: Optional[float] = 95.0, + **kwargs, + ): """Collect custom configuration values. Args: - correction_limit (float): Maximum solar zenith angle to apply the - correction in degrees. If ``max_sza`` is ``None``, pixels beyond this limit have a - constant correction applied. Otherwise, the correction is gradually reduced to 0 at - ``max_sza``. Default 88. - max_sza (float): Maximum solar zenith angle in degrees that is - considered valid and correctable. Default 95.0. + correction_limit: + Solar zenith angle in degrees where correction limiting + begins. + + max_sza: + Maximum valid angle in degrees for solar zenith angle correction. + + Pixels with solar zenith angles greater than + ``max_sza`` are set to 0. + + **kwargs: + Additional keyword arguments passed to the parent class. """ self.correction_limit = correction_limit + self.max_sza = max_sza super(SunZenithCorrector, self).__init__(**kwargs) def _apply_correction(self, proj, coszen): - logger.debug("Apply the standard sun-zenith correction [1/cos(sunz)]") res = proj.copy() - res.data = sunzen_corr_cos(proj.data, coszen.data, limit=self.correction_limit, max_sza=self.max_sza) + res.data = sunzen_corr_cos(proj.data, coszen.data, correction_limit=self.correction_limit, max_sza=self.max_sza) return res From f41db09e328f185e965b9063b58e24435d1eb77c Mon Sep 17 00:00:00 2001 From: Johan Strandgren Date: Wed, 20 May 2026 13:23:34 +0000 Subject: [PATCH 02/49] Move method for Li and Shibata sun zenith angle correction and remove ffunctionality to cap/reduce the correction. --- satpy/modifiers/angles.py | 21 ++++++++++++ satpy/modifiers/geometry.py | 67 +++++++++++++++++++++---------------- satpy/utils.py | 45 ------------------------- 3 files changed, 59 insertions(+), 74 deletions(-) diff --git a/satpy/modifiers/angles.py b/satpy/modifiers/angles.py index a20147cb7c..02c4694dfc 100644 --- a/satpy/modifiers/angles.py +++ b/satpy/modifiers/angles.py @@ -628,6 +628,27 @@ def _sunzen_corr_cos_ndarray(data: np.ndarray, return data * corr +def atmospheric_path_length_correction(data, cos_zen): + """Perform Sun zenith angle correction following the Li and Shibata parameterization. + + This function uses the correction method proposed by + Li and Shibata (2006): https://doi.org/10.1175/JAS3682.1 and is recommended for computing + the reflectance for (RGB) imagery to avoid over-correction at high solar zenith angles. It + shoudl not be used for quantitative/scientific applications for which the standard cosine + correction is more appropriate (see SunZenithCorrector for more details on how to use it). + + Both ``data`` and ``cos_zen`` should be 2D arrays of the same shape. + + """ + logger.debug("Apply the effective solar atmospheric path length correction method by Li and Shibata (2006)") + corr = 24.35 / (2. * cos_zen + np.sqrt(498.5225 * cos_zen**2 + 1)) + + # Force "night" and space pixels to 0 (where SZA is invalid) + corr = corr.where(cos_zen.notnull(), 0) + + return data * corr + + def sunzen_reduction(data: da.Array, sunz: da.Array, limit: float = 55., diff --git a/satpy/modifiers/geometry.py b/satpy/modifiers/geometry.py index 185d6485db..39dddb86f2 100644 --- a/satpy/modifiers/geometry.py +++ b/satpy/modifiers/geometry.py @@ -25,8 +25,7 @@ import numpy as np from satpy.modifiers import ModifierBase -from satpy.modifiers.angles import sunzen_corr_cos, sunzen_reduction -from satpy.utils import atmospheric_path_length_correction +from satpy.modifiers.angles import atmospheric_path_length_correction, sunzen_corr_cos, sunzen_reduction logger = logging.getLogger(__name__) @@ -141,48 +140,58 @@ def _apply_correction(self, proj, coszen): class EffectiveSolarPathLengthCorrector(SunZenithCorrectorBase): - """Special sun zenith correction with the method proposed by Li and Shibata. + """Special sun zenith angle correction using the parameterization proposed by Li and Shibata. (2006): https://doi.org/10.1175/JAS3682.1 - In addition to adjusting the provided reflectances by the cosine of the - solar zenith angle, this modifier forces all reflectances beyond a - solar zenith angle of `max_sza` to 0 to reduce noise in the final data. - It also gradually reduces the amount of correction done between - ``correction_limit`` and ``max_sza``. If ``max_sza`` is ``None`` then a - constant correction is applied to zenith angles beyond - ``correction_limit``. + This correction method is designed to reduce the over-correction of the standard + sun zenith angle correction at high solar zenith angles, which is especially + relevant for (RGB) imagery. - To set ``max_sza`` to ``None`` in a YAML configuration file use: - - .. code-block:: yaml - - effective_solar_pathlength_corrected: - modifier: !!python/name:satpy.modifiers.EffectiveSolarPathLengthCorrector - max_sza: !!null - optional_prerequisites: - - solar_zenith_angle + In previous versions of Satpy, this correction could be capped or reduced at higher + sun zenith angles by using the ``correction_limit`` and ``max_sza`` parameters. + This has been disabled for this correction since the parameterization also deals with + overcorrection at high solar zenith angles. If capping or reduction is still desireble + it can be achieved by using the SunZenithCorrector with the same ``correction_limit`` + and ``max_sza`` parameters. """ - def __init__(self, correction_limit=88., **kwargs): # noqa: D417 + def __init__( + self, + correction_limit: Optional[float] = None, + max_sza: Optional[float] = None, + **kwargs, + ): """Collect custom configuration values. Args: - correction_limit (float): Maximum solar zenith angle to apply the - correction in degrees. If ``max_sza`` is ``None``, pixels beyond this limit have a - constant correction applied. Otherwise, the correction is gradually reduced to 0 at - ``max_sza``. Default 88. - max_sza (float): Maximum solar zenith angle in degrees that is - considered valid and correctable. Default 95.0. + correction_limit: + Solar zenith angle in degrees where correction limiting + begins. Deprecated. + + max_sza: + Maximum valid angle in degrees for solar zenith angle correction. Deprecated. + + + **kwargs: + Additional keyword arguments passed to the parent class. """ - self.correction_limit = correction_limit + if correction_limit is not None or max_sza is not None: + raise UserWarning( + "The `correction_limit` and `max_sza` parameters are deprecated and not " + "used for the EffectiveSolarPathLengthCorrector since the parameterization " + "by Li and Shibata (2006) already accounts for overcorrection at high solar " + "zenith angles. If capping or reduction of the correction is still desireble " + "it can be achieved by using the SunZenithCorrector with the same " + "`correction_limit` and `max_sza` parameters." + ) + super(EffectiveSolarPathLengthCorrector, self).__init__(**kwargs) def _apply_correction(self, proj, coszen): - logger.debug("Apply the effective solar atmospheric path length correction method by Li and Shibata") - return atmospheric_path_length_correction(proj, coszen, limit=self.correction_limit, max_sza=self.max_sza) + return atmospheric_path_length_correction(proj, coszen) class SunZenithReducer(SunZenithCorrectorBase): diff --git a/satpy/utils.py b/satpy/utils.py index bdf9d77e4c..8d5a8e7ce7 100644 --- a/satpy/utils.py +++ b/satpy/utils.py @@ -271,51 +271,6 @@ def proj_units_to_meters(proj_str): return " ".join(new_parts) -def _get_sunz_corr_li_and_shibata(cos_zen): - return 24.35 / (2. * cos_zen + np.sqrt(498.5225 * cos_zen**2 + 1)) - - -def atmospheric_path_length_correction(data, cos_zen, limit=88., max_sza=95.): - """Perform Sun zenith angle correction. - - This function uses the correction method proposed by - Li and Shibata (2006): https://doi.org/10.1175/JAS3682.1 - - The correction is limited to ``limit`` degrees (default: 88.0 degrees). For - larger zenith angles, the correction is the same as at the ``limit`` if - ``max_sza`` is `None`. The default behavior is to gradually reduce the - correction past ``limit`` degrees up to ``max_sza`` where the correction - becomes 0. Both ``data`` and ``cos_zen`` should be 2D arrays of the same - shape. - - """ - # Convert the zenith angle limit to cosine of zenith angle - limit_rad = np.deg2rad(limit) - limit_cos = np.cos(limit_rad) - max_sza_rad = np.deg2rad(max_sza) if max_sza is not None else max_sza - - # Cosine correction - corr = _get_sunz_corr_li_and_shibata(cos_zen) - # Use constant value (the limit) for larger zenith angles - corr_lim = _get_sunz_corr_li_and_shibata(limit_cos) - - if max_sza is not None: - # gradually fall off for larger zenith angle - grad_factor = (np.arccos(cos_zen) - limit_rad) / (max_sza_rad - limit_rad) - # invert the factor so maximum correction is done at `limit` and falls off later - grad_factor = 1. - np.log(grad_factor + 1) / np.log(2) - # make sure we don't make anything negative - grad_factor = grad_factor.clip(0.) - else: - # Use constant value (the limit) for larger zenith angles - grad_factor = 1. - corr = corr.where(cos_zen > limit_cos, grad_factor * corr_lim) - # Force "night" pixels to 0 (where SZA is invalid) - corr = corr.where(cos_zen.notnull(), 0) - - return data * corr - - def get_satpos( data_arr: xr.DataArray, preference: Optional[str] = None, From 0cf0f7f743e8713e1d09dd742774e8ddc872bc18 Mon Sep 17 00:00:00 2001 From: Johan Strandgren Date: Wed, 20 May 2026 13:31:42 +0000 Subject: [PATCH 03/49] Also skip sunz correction if effective_solar_path_length_corrected has already been applied. --- satpy/modifiers/geometry.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/satpy/modifiers/geometry.py b/satpy/modifiers/geometry.py index 39dddb86f2..abc81efbac 100644 --- a/satpy/modifiers/geometry.py +++ b/satpy/modifiers/geometry.py @@ -41,9 +41,10 @@ def __call__(self, projectables, **info): """Generate the composite.""" projectables = self.match_data_arrays(list(projectables) + list(info.get("optional_datasets", []))) vis = projectables[0] - if vis.attrs.get("sunz_corrected"): - logger.debug("Sun zenith correction already applied") - return vis + for correction in ["sunz_corrected", "effective_solar_path_length_corrected"]: + if vis.attrs.get(correction): + logger.debug(f"Sun zenith correction '{correction}' already applied. Using data as is.") + return vis logger.debug("Applying Sun zenith angle correction") if not info.get("optional_datasets"): From 0219e057d43d46459a6a038ba856b86954a92c87 Mon Sep 17 00:00:00 2001 From: Johan Strandgren Date: Wed, 20 May 2026 13:55:45 +0000 Subject: [PATCH 04/49] Fix typo and also search for already applied sunz corrections in modifiers attribute. --- satpy/modifiers/geometry.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/satpy/modifiers/geometry.py b/satpy/modifiers/geometry.py index abc81efbac..3e0825a4cf 100644 --- a/satpy/modifiers/geometry.py +++ b/satpy/modifiers/geometry.py @@ -41,8 +41,8 @@ def __call__(self, projectables, **info): """Generate the composite.""" projectables = self.match_data_arrays(list(projectables) + list(info.get("optional_datasets", []))) vis = projectables[0] - for correction in ["sunz_corrected", "effective_solar_path_length_corrected"]: - if vis.attrs.get(correction): + for correction in ["sunz_corrected", "effective_solar_pathlength_corrected"]: + if vis.attrs.get(correction) or correction in vis.attrs.get("modifiers"): logger.debug(f"Sun zenith correction '{correction}' already applied. Using data as is.") return vis From 9ba3952246e674848e7a65a0aaaf4a7f87d4312f Mon Sep 17 00:00:00 2001 From: Johan Strandgren Date: Wed, 20 May 2026 14:30:23 +0000 Subject: [PATCH 05/49] Clarify log message for dual correction. Add type annotation. --- satpy/modifiers/angles.py | 3 ++- satpy/modifiers/geometry.py | 8 ++++++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/satpy/modifiers/angles.py b/satpy/modifiers/angles.py index 02c4694dfc..e9965b6d8f 100644 --- a/satpy/modifiers/angles.py +++ b/satpy/modifiers/angles.py @@ -628,7 +628,8 @@ def _sunzen_corr_cos_ndarray(data: np.ndarray, return data * corr -def atmospheric_path_length_correction(data, cos_zen): +def atmospheric_path_length_correction(data: xr.DataArray, + cos_zen: xr.DataArray) -> xr.DataArray: """Perform Sun zenith angle correction following the Li and Shibata parameterization. This function uses the correction method proposed by diff --git a/satpy/modifiers/geometry.py b/satpy/modifiers/geometry.py index 3e0825a4cf..13f688f878 100644 --- a/satpy/modifiers/geometry.py +++ b/satpy/modifiers/geometry.py @@ -43,7 +43,10 @@ def __call__(self, projectables, **info): vis = projectables[0] for correction in ["sunz_corrected", "effective_solar_pathlength_corrected"]: if vis.attrs.get(correction) or correction in vis.attrs.get("modifiers"): - logger.debug(f"Sun zenith correction '{correction}' already applied. Using data as is.") + logger.debug( + f"Sun zenith angle correction '{correction}' already applied. " + f"Skipping correction '{self.method}'." + ) return vis logger.debug("Applying Sun zenith angle correction") @@ -130,6 +133,7 @@ def __init__( Additional keyword arguments passed to the parent class. """ + self.method = "sunz_corrected" self.correction_limit = correction_limit self.max_sza = max_sza super(SunZenithCorrector, self).__init__(**kwargs) @@ -188,7 +192,7 @@ def __init__( "it can be achieved by using the SunZenithCorrector with the same " "`correction_limit` and `max_sza` parameters." ) - + self.method = "effective_solar_pathlength_corrected" super(EffectiveSolarPathLengthCorrector, self).__init__(**kwargs) def _apply_correction(self, proj, coszen): From b77e52cdb179e06e9642a7573ba913ecf385f8c3 Mon Sep 17 00:00:00 2001 From: Johan Strandgren Date: Thu, 21 May 2026 08:50:38 +0000 Subject: [PATCH 06/49] Change tolerance given that the correction is now done in degrees instead of radians --- satpy/tests/test_modifiers.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/satpy/tests/test_modifiers.py b/satpy/tests/test_modifiers.py index 11e09a8803..cb4c114f41 100644 --- a/satpy/tests/test_modifiers.py +++ b/satpy/tests/test_modifiers.py @@ -111,7 +111,7 @@ def sunz_sza(): class TestSunZenithCorrector: - """Test case for the zenith corrector.""" + """Test case for the standard Sun zenith angle corrector.""" @pytest.mark.parametrize("as_32bit", [False, True]) def test_basic_default_not_provided(self, sunz_ds1, as_32bit): @@ -123,14 +123,14 @@ def test_basic_default_not_provided(self, sunz_ds1, as_32bit): comp = SunZenithCorrector(name="sza_test", modifiers=tuple()) res = comp((sunz_ds1,), test_attr="test") np.testing.assert_allclose(res.values, np.array([[22.401667, 22.31777], [22.437503, 22.353533]]), - rtol=1e-6) + rtol=1e-5) assert "y" in res.coords assert "x" in res.coords ds1 = sunz_ds1.copy().drop_vars(("y", "x")) res = comp((ds1,), test_attr="test") res_np = res.compute() np.testing.assert_allclose(res_np.values, np.array([[22.401667, 22.31777], [22.437503, 22.353533]]), - rtol=1e-6) + rtol=1e-5) assert res.dtype == res_np.dtype assert "y" not in res.coords assert "x" not in res.coords @@ -158,7 +158,7 @@ def test_basic_default_provided(self, data_arr, sunz_sza, dtype): res = comp((data_arr.astype(dtype), sunz_sza.astype(dtype)), test_attr="test") expected = np.array([[22.401667, 22.31777], [22.437503, 22.353533]], dtype=dtype) values = res.values - np.testing.assert_allclose(values, expected) + np.testing.assert_allclose(values, expected, rtol=1e-5) assert res.dtype == dtype assert values.dtype == dtype From 6ac410c84008491e13593d89cef6b93fcf3956e3 Mon Sep 17 00:00:00 2001 From: Johan Strandgren Date: Thu, 21 May 2026 11:00:18 +0000 Subject: [PATCH 07/49] Fix tests for SunZenithCorrector: - Fix bug to make sure that custom sza values are used when actually intended and pass as optional_dataset instead of as a projectable. - Use different sza values in order to be able to properly test the available options concerning correction_limit and max_sza. - Add tests for more combinations of correction_limit and max_sza --- satpy/tests/test_modifiers.py | 67 +++++++++++++++++++++++++---------- 1 file changed, 49 insertions(+), 18 deletions(-) diff --git a/satpy/tests/test_modifiers.py b/satpy/tests/test_modifiers.py index cb4c114f41..7975ae9429 100644 --- a/satpy/tests/test_modifiers.py +++ b/satpy/tests/test_modifiers.py @@ -101,8 +101,7 @@ def sunz_ds2(): def sunz_sza(): """Generate fake solar zenith angle data array for testing.""" sza = xr.DataArray( - np.rad2deg(np.arccos(da.from_array([[0.0149581333, 0.0146694376], [0.0150812684, 0.0147925727]], - chunks=2))), + da.from_array([[80.0, 87.0], [89.0, 93.0]], chunks=2), attrs={"area": _sunz_area_def()}, dims=("y", "x"), coords={"y": [0, 1], "x": [0, 1]}, @@ -114,7 +113,7 @@ class TestSunZenithCorrector: """Test case for the standard Sun zenith angle corrector.""" @pytest.mark.parametrize("as_32bit", [False, True]) - def test_basic_default_not_provided(self, sunz_ds1, as_32bit): + def test_default_with_sza_not_provided(self, sunz_ds1, as_32bit): """Test default limits when SZA isn't provided.""" from satpy.modifiers.geometry import SunZenithCorrector @@ -138,12 +137,14 @@ def test_basic_default_not_provided(self, sunz_ds1, as_32bit): assert res.dtype == np.float32 @pytest.mark.parametrize("dtype", [np.float32, np.float64]) - def test_basic_lims_not_provided(self, sunz_ds1, dtype): - """Test custom limits when SZA isn't provided.""" + @pytest.mark.parametrize("data_arr", [lazy_fixture("sunz_ds1"), lazy_fixture("sunz_ds1_stacked")]) + def test_default_with_sza_provided(self, data_arr, sunz_sza, dtype): + """Test default limits when SZA is provided.""" from satpy.modifiers.geometry import SunZenithCorrector - comp = SunZenithCorrector(name="sza_test", modifiers=tuple(), correction_limit=90) - res = comp((sunz_ds1.astype(dtype),), test_attr="test") - expected = np.array([[66.853262, 68.168939], [66.30742, 67.601493]], dtype=dtype) + comp = SunZenithCorrector(name="sza_test", modifiers=tuple()) + info = {"test_attr": "test", "optional_datasets": [sunz_sza.astype(dtype)]} + res = comp((data_arr.astype(dtype),), **info) + expected = np.array([[5.758770, 19.107323], [23.133712, 6.372368]], dtype=dtype) values = res.values np.testing.assert_allclose(values, expected, rtol=1e-5) assert res.dtype == dtype @@ -151,12 +152,13 @@ def test_basic_lims_not_provided(self, sunz_ds1, dtype): @pytest.mark.parametrize("dtype", [np.float32, np.float64]) @pytest.mark.parametrize("data_arr", [lazy_fixture("sunz_ds1"), lazy_fixture("sunz_ds1_stacked")]) - def test_basic_default_provided(self, data_arr, sunz_sza, dtype): - """Test default limits when SZA is provided.""" + def test_standard_with_sza_provided(self, data_arr, sunz_sza, dtype): + """Test correction_limit=None and max_sza=None when SZA is provided.""" from satpy.modifiers.geometry import SunZenithCorrector - comp = SunZenithCorrector(name="sza_test", modifiers=tuple()) - res = comp((data_arr.astype(dtype), sunz_sza.astype(dtype)), test_attr="test") - expected = np.array([[22.401667, 22.31777], [22.437503, 22.353533]], dtype=dtype) + comp = SunZenithCorrector(name="sza_test", modifiers=tuple(), correction_limit=None, max_sza=None) + info = {"test_attr": "test", "optional_datasets": [sunz_sza.astype(dtype)]} + res = comp((data_arr.astype(dtype),), **info) + expected = np.array([[5.758770, 19.107323], [57.298689, 0.0]], dtype=dtype) values = res.values np.testing.assert_allclose(values, expected, rtol=1e-5) assert res.dtype == dtype @@ -164,12 +166,41 @@ def test_basic_default_provided(self, data_arr, sunz_sza, dtype): @pytest.mark.parametrize("dtype", [np.float32, np.float64]) @pytest.mark.parametrize("data_arr", [lazy_fixture("sunz_ds1"), lazy_fixture("sunz_ds1_stacked")]) - def test_basic_lims_provided(self, data_arr, sunz_sza, dtype): - """Test custom limits when SZA is provided.""" + def test_custom_max_sza_with_sza_provided(self, data_arr, sunz_sza, dtype): + """Test custom max_sza (and correction_limit=None) when SZA is provided.""" from satpy.modifiers.geometry import SunZenithCorrector - comp = SunZenithCorrector(name="sza_test", modifiers=tuple(), correction_limit=90) - res = comp((data_arr.astype(dtype), sunz_sza.astype(dtype)), test_attr="test") - expected = np.array([[66.853262, 68.168939], [66.30742, 67.601493]], dtype=dtype) + comp = SunZenithCorrector(name="sza_test", modifiers=tuple(), correction_limit=None, max_sza=88) + info = {"test_attr": "test", "optional_datasets": [sunz_sza.astype(dtype)]} + res = comp((data_arr.astype(dtype),), **info) + expected = np.array([[5.758770, 19.107323], [0.0, 0.0]], dtype=dtype) + values = res.values + np.testing.assert_allclose(values, expected, rtol=1e-5) + assert res.dtype == dtype + assert values.dtype == dtype + + @pytest.mark.parametrize("dtype", [np.float32, np.float64]) + @pytest.mark.parametrize("data_arr", [lazy_fixture("sunz_ds1"), lazy_fixture("sunz_ds1_stacked")]) + def test_custom_correction_limit_with_sza_provided(self, data_arr, sunz_sza, dtype): + """Test custom correction_limit (and max_sza=None) when SZA is provided.""" + from satpy.modifiers.geometry import SunZenithCorrector + comp = SunZenithCorrector(name="sza_test", modifiers=tuple(), correction_limit=88, max_sza=None) + info = {"test_attr": "test", "optional_datasets": [sunz_sza.astype(dtype)]} + res = comp((data_arr.astype(dtype),), **info) + expected = np.array([[5.758770, 19.107323], [28.653708, 28.653708]], dtype=dtype) + values = res.values + np.testing.assert_allclose(values, expected, rtol=1e-5) + assert res.dtype == dtype + assert values.dtype == dtype + + @pytest.mark.parametrize("dtype", [np.float32, np.float64]) + @pytest.mark.parametrize("data_arr", [lazy_fixture("sunz_ds1"), lazy_fixture("sunz_ds1_stacked")]) + def test_custom_max_sza_and_correction_limit_with_sza_provided(self, data_arr, sunz_sza, dtype): + """Test custom correction_limit and max_sza when SZA is provided.""" + from satpy.modifiers.geometry import SunZenithCorrector + comp = SunZenithCorrector(name="sza_test", modifiers=tuple(), correction_limit=88, max_sza=95) + info = {"test_attr": "test", "optional_datasets": [sunz_sza.astype(dtype)]} + res = comp((data_arr.astype(dtype),), **info) + expected = np.array([[5.758770, 19.107323], [23.133712, 6.372368]], dtype=dtype) values = res.values np.testing.assert_allclose(values, expected, rtol=1e-5) assert res.dtype == dtype From b8cfe96a7c158c8bba643c86c6423e3f3d551530 Mon Sep 17 00:00:00 2001 From: Johan Strandgren Date: Thu, 21 May 2026 11:05:05 +0000 Subject: [PATCH 08/49] Add tests to verify that data are not computed and kept lazy --- satpy/tests/test_modifiers.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/satpy/tests/test_modifiers.py b/satpy/tests/test_modifiers.py index 7975ae9429..864385223d 100644 --- a/satpy/tests/test_modifiers.py +++ b/satpy/tests/test_modifiers.py @@ -149,6 +149,7 @@ def test_default_with_sza_provided(self, data_arr, sunz_sza, dtype): np.testing.assert_allclose(values, expected, rtol=1e-5) assert res.dtype == dtype assert values.dtype == dtype + assert type(res.data) is type(data_arr.data) @pytest.mark.parametrize("dtype", [np.float32, np.float64]) @pytest.mark.parametrize("data_arr", [lazy_fixture("sunz_ds1"), lazy_fixture("sunz_ds1_stacked")]) @@ -163,6 +164,7 @@ def test_standard_with_sza_provided(self, data_arr, sunz_sza, dtype): np.testing.assert_allclose(values, expected, rtol=1e-5) assert res.dtype == dtype assert values.dtype == dtype + assert type(res.data) is type(data_arr.data) @pytest.mark.parametrize("dtype", [np.float32, np.float64]) @pytest.mark.parametrize("data_arr", [lazy_fixture("sunz_ds1"), lazy_fixture("sunz_ds1_stacked")]) @@ -177,6 +179,7 @@ def test_custom_max_sza_with_sza_provided(self, data_arr, sunz_sza, dtype): np.testing.assert_allclose(values, expected, rtol=1e-5) assert res.dtype == dtype assert values.dtype == dtype + assert type(res.data) is type(data_arr.data) @pytest.mark.parametrize("dtype", [np.float32, np.float64]) @pytest.mark.parametrize("data_arr", [lazy_fixture("sunz_ds1"), lazy_fixture("sunz_ds1_stacked")]) @@ -191,6 +194,7 @@ def test_custom_correction_limit_with_sza_provided(self, data_arr, sunz_sza, dty np.testing.assert_allclose(values, expected, rtol=1e-5) assert res.dtype == dtype assert values.dtype == dtype + assert type(res.data) is type(data_arr.data) @pytest.mark.parametrize("dtype", [np.float32, np.float64]) @pytest.mark.parametrize("data_arr", [lazy_fixture("sunz_ds1"), lazy_fixture("sunz_ds1_stacked")]) @@ -205,6 +209,7 @@ def test_custom_max_sza_and_correction_limit_with_sza_provided(self, data_arr, s np.testing.assert_allclose(values, expected, rtol=1e-5) assert res.dtype == dtype assert values.dtype == dtype + assert type(res.data) is type(data_arr.data) def test_imcompatible_areas(self, sunz_ds2, sunz_sza): """Test sunz correction on incompatible areas.""" From e9d1398f0227cfe6ca3e7b4a57a3c622d1bf43a0 Mon Sep 17 00:00:00 2001 From: Johan Strandgren Date: Thu, 21 May 2026 11:05:55 +0000 Subject: [PATCH 09/49] Remove keyword argument from test where it's not used --- satpy/tests/test_modifiers.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/satpy/tests/test_modifiers.py b/satpy/tests/test_modifiers.py index 864385223d..9214d5ba1e 100644 --- a/satpy/tests/test_modifiers.py +++ b/satpy/tests/test_modifiers.py @@ -215,7 +215,7 @@ def test_imcompatible_areas(self, sunz_ds2, sunz_sza): """Test sunz correction on incompatible areas.""" from satpy.composites.core import IncompatibleAreas from satpy.modifiers.geometry import SunZenithCorrector - comp = SunZenithCorrector(name="sza_test", modifiers=tuple(), correction_limit=90) + comp = SunZenithCorrector(name="sza_test", modifiers=tuple()) with pytest.raises(IncompatibleAreas): comp((sunz_ds2, sunz_sza), test_attr="test") From 6da9aebb199b2af77d7fc01c0e396277bf54972f Mon Sep 17 00:00:00 2001 From: Johan Strandgren Date: Thu, 21 May 2026 12:39:27 +0000 Subject: [PATCH 10/49] Fix typo and pass sunz angle as optional_dataset --- satpy/tests/test_modifiers.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/satpy/tests/test_modifiers.py b/satpy/tests/test_modifiers.py index 9214d5ba1e..ad0dde22c1 100644 --- a/satpy/tests/test_modifiers.py +++ b/satpy/tests/test_modifiers.py @@ -211,13 +211,14 @@ def test_custom_max_sza_and_correction_limit_with_sza_provided(self, data_arr, s assert values.dtype == dtype assert type(res.data) is type(data_arr.data) - def test_imcompatible_areas(self, sunz_ds2, sunz_sza): + def test_incompatible_areas(self, sunz_ds2, sunz_sza): """Test sunz correction on incompatible areas.""" from satpy.composites.core import IncompatibleAreas from satpy.modifiers.geometry import SunZenithCorrector comp = SunZenithCorrector(name="sza_test", modifiers=tuple()) + info = {"test_attr": "test", "optional_datasets": [sunz_sza]} with pytest.raises(IncompatibleAreas): - comp((sunz_ds2, sunz_sza), test_attr="test") + comp((sunz_ds2,), **info) class TestSunZenithReducer: From 4cfff677b5da982e3fc43276ff7a713fcb064854 Mon Sep 17 00:00:00 2001 From: Johan Strandgren Date: Thu, 21 May 2026 13:01:11 +0000 Subject: [PATCH 11/49] Add missing tests for EffectiveSolarPathLengthCorrector --- satpy/tests/test_modifiers.py | 52 +++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/satpy/tests/test_modifiers.py b/satpy/tests/test_modifiers.py index ad0dde22c1..a540c82e0c 100644 --- a/satpy/tests/test_modifiers.py +++ b/satpy/tests/test_modifiers.py @@ -221,6 +221,58 @@ def test_incompatible_areas(self, sunz_ds2, sunz_sza): comp((sunz_ds2,), **info) +class TestEffectiveSolarPathLengthCorrector: + """Test case for the effective solar path length corrector.""" + + @pytest.mark.parametrize("as_32bit", [False, True]) + def test_with_sza_not_provided(self, sunz_ds1, as_32bit): + """Test when SZA isn't provided.""" + from satpy.modifiers.geometry import EffectiveSolarPathLengthCorrector + + if as_32bit: + sunz_ds1 = sunz_ds1.astype(np.float32) + comp = EffectiveSolarPathLengthCorrector(name="sza_test", modifiers=tuple()) + res = comp((sunz_ds1,), test_attr="test") + np.testing.assert_allclose(res.values, np.array([[22.458680, 22.512698], [22.435495, 22.489718]]), + rtol=1e-5) + assert "y" in res.coords + assert "x" in res.coords + ds1 = sunz_ds1.copy().drop_vars(("y", "x")) + res = comp((ds1,), test_attr="test") + res_np = res.compute() + np.testing.assert_allclose(res_np.values, np.array([[22.458680, 22.512698], [22.435495, 22.489718]]), + rtol=1e-5) + assert res.dtype == res_np.dtype + assert "y" not in res.coords + assert "x" not in res.coords + if as_32bit: + assert res.dtype == np.float32 + + @pytest.mark.parametrize("dtype", [np.float32, np.float64]) + @pytest.mark.parametrize("data_arr", [lazy_fixture("sunz_ds1"), lazy_fixture("sunz_ds1_stacked")]) + def test_with_sza_provided(self, data_arr, sunz_sza, dtype): + """Test when SZA is provided.""" + from satpy.modifiers.geometry import EffectiveSolarPathLengthCorrector + comp = EffectiveSolarPathLengthCorrector(name="sza_test", modifiers=tuple()) + info = {"test_attr": "test", "optional_datasets": [sunz_sza.astype(dtype)]} + res = comp((data_arr.astype(dtype),), **info) + expected = np.array([[5.595989, 14.823307], [21.973671, 16.988299]], dtype=dtype) + values = res.values + np.testing.assert_allclose(values, expected, rtol=1e-5) + assert res.dtype == dtype + assert values.dtype == dtype + assert type(res.data) is type(data_arr.data) + + def test_incompatible_areas(self, sunz_ds2, sunz_sza): + """Test with incompatible areas.""" + from satpy.composites.core import IncompatibleAreas + from satpy.modifiers.geometry import EffectiveSolarPathLengthCorrector + comp = EffectiveSolarPathLengthCorrector(name="sza_test", modifiers=tuple()) + info = {"test_attr": "test", "optional_datasets": [sunz_sza]} + with pytest.raises(IncompatibleAreas): + comp((sunz_ds2,), **info) + + class TestSunZenithReducer: """Test case for the sun zenith reducer.""" From df6ca46173e2eedfb7f8791d7ec2ef70f59dfc52 Mon Sep 17 00:00:00 2001 From: Johan Strandgren Date: Thu, 21 May 2026 13:08:11 +0000 Subject: [PATCH 12/49] Add UserWarning tests for deprecated reduction parameters in EffectiveSolarPathLengthCorrector --- satpy/tests/test_modifiers.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/satpy/tests/test_modifiers.py b/satpy/tests/test_modifiers.py index a540c82e0c..d3cb3e471a 100644 --- a/satpy/tests/test_modifiers.py +++ b/satpy/tests/test_modifiers.py @@ -263,6 +263,18 @@ def test_with_sza_provided(self, data_arr, sunz_sza, dtype): assert values.dtype == dtype assert type(res.data) is type(data_arr.data) + def test_with_deprecated_correction_limit(self): + """Test with deprecated correction_limit.""" + from satpy.modifiers.geometry import EffectiveSolarPathLengthCorrector + with pytest.raises(UserWarning): + EffectiveSolarPathLengthCorrector(name="sza_test", modifiers=tuple(), correction_limit=88) + + def test_with_deprecated_sza_max(self): + """Test with deprecated max_sza.""" + from satpy.modifiers.geometry import EffectiveSolarPathLengthCorrector + with pytest.raises(UserWarning): + EffectiveSolarPathLengthCorrector(name="sza_test", modifiers=tuple(), max_sza=95) + def test_incompatible_areas(self, sunz_ds2, sunz_sza): """Test with incompatible areas.""" from satpy.composites.core import IncompatibleAreas From 157dfda8e64ca6b0f1f13f549a84849d1730d8c5 Mon Sep 17 00:00:00 2001 From: Johan Strandgren Date: Thu, 21 May 2026 13:13:24 +0000 Subject: [PATCH 13/49] Fix SunZenithReducer following refactoring work on SunZenithCorrectorBase --- satpy/modifiers/geometry.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/satpy/modifiers/geometry.py b/satpy/modifiers/geometry.py index 13f688f878..4d1b7b4f96 100644 --- a/satpy/modifiers/geometry.py +++ b/satpy/modifiers/geometry.py @@ -226,8 +226,9 @@ def __init__(self, correction_limit=80., max_sza=90, strength=1.3, **kwargs): # """ self.correction_limit = correction_limit + self.max_sza = max_sza self.strength = strength - super(SunZenithReducer, self).__init__(max_sza=max_sza, **kwargs) + super(SunZenithReducer, self).__init__(**kwargs) if self.max_sza is None: raise ValueError("`max_sza` must be defined when using the SunZenithReducer.") From 402488e975111af9c26fef2bae0acaea151403d9 Mon Sep 17 00:00:00 2001 From: Johan Strandgren Date: Thu, 21 May 2026 13:28:38 +0000 Subject: [PATCH 14/49] Fix SunZenithReducer tests to make sure that sunz_sza is passed and used as expected. Fix expected values to pass updated values of sunz_sza. --- satpy/tests/test_modifiers.py | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/satpy/tests/test_modifiers.py b/satpy/tests/test_modifiers.py index d3cb3e471a..eebc4e484a 100644 --- a/satpy/tests/test_modifiers.py +++ b/satpy/tests/test_modifiers.py @@ -299,26 +299,24 @@ def setup_class(cls): @pytest.mark.parametrize("dtype", [np.float32, np.float64]) def test_default_settings(self, sunz_ds1, sunz_sza, dtype): """Test default settings with sza data available.""" - res = self.default((sunz_ds1.astype(dtype), sunz_sza.astype(dtype)), test_attr="test") - expected = np.array([[0.02916261, 0.02839063], [0.02949383, 0.02871911]], dtype=dtype) + info = {"test_attr": "test", "optional_datasets": [sunz_sza.astype(dtype)]} + res = self.default((sunz_ds1.astype(dtype),), **info) + expected = np.array([[1.0, 0.176790], [0.036095, 0.0]], dtype=dtype) assert res.dtype == dtype values = res.values assert values.dtype == dtype - np.testing.assert_allclose(values, - expected, - rtol=2e-5) + np.testing.assert_allclose(values, expected, rtol=2e-5) @pytest.mark.parametrize("dtype", [np.float32, np.float64]) def test_custom_settings(self, sunz_ds1, sunz_sza, dtype): """Test custom settings with sza data available.""" - res = self.custom((sunz_ds1.astype(dtype), sunz_sza.astype(dtype)), test_attr="test") - expected = np.array([[0.01041319, 0.01030033], [0.01046164, 0.01034834]], dtype=dtype) + info = {"test_attr": "test", "optional_datasets": [sunz_sza.astype(dtype)]} + res = self.custom((sunz_ds1.astype(dtype),), **info) + expected = np.array([[5.436207e-01, 3.657017e-02], [1.143065e-02, 2.450100e-04]], dtype=dtype) assert res.dtype == dtype values = res.values assert values.dtype == dtype - np.testing.assert_allclose(values, - expected, - rtol=1e-5) + np.testing.assert_allclose(values, expected, rtol=2e-5) def test_invalid_max_sza(self, sunz_ds1, sunz_sza): """Test invalid max_sza with sza data available.""" From 16541047433a182d0522d5d475b95bce148c3b57 Mon Sep 17 00:00:00 2001 From: Johan Strandgren Date: Thu, 21 May 2026 13:29:13 +0000 Subject: [PATCH 15/49] Remove unused arguments --- satpy/tests/test_modifiers.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/satpy/tests/test_modifiers.py b/satpy/tests/test_modifiers.py index eebc4e484a..6dbfcb4d4c 100644 --- a/satpy/tests/test_modifiers.py +++ b/satpy/tests/test_modifiers.py @@ -318,7 +318,7 @@ def test_custom_settings(self, sunz_ds1, sunz_sza, dtype): assert values.dtype == dtype np.testing.assert_allclose(values, expected, rtol=2e-5) - def test_invalid_max_sza(self, sunz_ds1, sunz_sza): + def test_invalid_max_sza(self): """Test invalid max_sza with sza data available.""" from satpy.modifiers.geometry import SunZenithReducer with pytest.raises(ValueError, match="`max_sza` must be defined when using the SunZenithReducer."): From e060df04e4d46cdb95de0d49fa1925b7786d2850 Mon Sep 17 00:00:00 2001 From: Johan Strandgren Date: Thu, 21 May 2026 13:46:34 +0000 Subject: [PATCH 16/49] Make sure sunzen_corr_cos doesn't compute any data and remove map_blocks wrapper --- satpy/modifiers/angles.py | 27 +++++++++------------------ satpy/modifiers/geometry.py | 4 +--- 2 files changed, 10 insertions(+), 21 deletions(-) diff --git a/satpy/modifiers/angles.py b/satpy/modifiers/angles.py index e9965b6d8f..b74c2a4c0e 100644 --- a/satpy/modifiers/angles.py +++ b/satpy/modifiers/angles.py @@ -534,10 +534,10 @@ def _get_sensor_angles_ndarray(lons, lats, start_time, sat_lon, sat_lat, sat_alt return np.stack([sata, satz]) -def sunzen_corr_cos(data: da.Array, - cos_zen: da.Array, +def sunzen_corr_cos(data: xr.DataArray, + cos_zen: xr.DataArray, correction_limit: Optional[float] = 88., - max_sza: Optional[float] = 95.) -> da.Array: + max_sza: Optional[float] = 95.) -> xr.DataArray: """Perform standard Sun zenith angle correction. The correction is based on the provided cosine of the solar zenith angle @@ -556,16 +556,6 @@ def sunzen_corr_cos(data: da.Array, Both ``data`` and ``cos_zen`` should be 2D arrays of the same shape. """ - return da.map_blocks(_sunzen_corr_cos_ndarray, - data, cos_zen, correction_limit, max_sza, - meta=np.array((), dtype=data.dtype), - chunks=data.chunks) - - -def _sunzen_corr_cos_ndarray(data: np.ndarray, - cos_zen: np.ndarray, - correction_limit: Optional[float], - max_sza: Optional[float]) -> np.ndarray: sunz = np.rad2deg(np.arccos(cos_zen)) # Start from standard cosine correction @@ -582,13 +572,13 @@ def _sunzen_corr_cos_ndarray(data: np.ndarray, f"Apply the standard sun-zenith correction [1/cos(sunz)] but set correction (and reflectance) " f"to 0 for angles larger than {max_sza} degrees." ) - corr = np.where(sunz <= max_sza, corr, 0.).astype(data.dtype, copy=False) + corr = corr.where(sunz <= max_sza, 0).astype(data.dtype, copy=False) elif correction_limit is not None and max_sza is None: logger.debug( f"Apply the standard sun-zenith correction [1/cos(sunz)] but cap the maximum correction " f"for angles larger than {correction_limit} degrees." ) - corr = np.where(sunz <= correction_limit, corr, corr_at_limit).astype(data.dtype, copy=False) + corr = corr.where(sunz <= correction_limit, corr_at_limit).astype(data.dtype, copy=False) elif correction_limit is not None and max_sza is not None: logger.debug( f"Apply the standard sun-zenith correction [1/cos(sunz)] but gradually reduce the correction " @@ -605,9 +595,9 @@ def _sunzen_corr_cos_ndarray(data: np.ndarray, with np.errstate(invalid="ignore"): # we expect space pixels to be invalid reduction_factor = 1. - np.log(reduction_factor + 1) / np.log(2) - corr_with_reduction = (corr_at_limit * reduction_factor).astype(data.dtype, copy=False) + corr_with_reduction = (corr_at_limit * reduction_factor) - corr = np.where(sunz < correction_limit, corr, corr_with_reduction) + corr = corr.where(sunz < correction_limit, corr_with_reduction).astype(data.dtype, copy=False) if correction_limit is not None: logger.warning( @@ -623,7 +613,7 @@ def _sunzen_corr_cos_ndarray(data: np.ndarray, corr = corr.clip(0.) # Force "night" and space pixels to 0 (where SZA is invalid) - corr[np.isnan(cos_zen)] = 0 + corr = corr.where(cos_zen.notnull(), 0) return data * corr @@ -659,6 +649,7 @@ def sunzen_reduction(data: da.Array, return da.map_blocks(_sunzen_reduction_ndarray, data, sunz, limit, max_sza, strength, meta=np.array((), dtype=data.dtype), chunks=data.chunks) + def _sunzen_reduction_ndarray(data: np.ndarray, sunz: np.ndarray, limit: float, diff --git a/satpy/modifiers/geometry.py b/satpy/modifiers/geometry.py index 4d1b7b4f96..91863a24bf 100644 --- a/satpy/modifiers/geometry.py +++ b/satpy/modifiers/geometry.py @@ -139,9 +139,7 @@ def __init__( super(SunZenithCorrector, self).__init__(**kwargs) def _apply_correction(self, proj, coszen): - res = proj.copy() - res.data = sunzen_corr_cos(proj.data, coszen.data, correction_limit=self.correction_limit, max_sza=self.max_sza) - return res + return sunzen_corr_cos(proj, coszen, correction_limit=self.correction_limit, max_sza=self.max_sza) class EffectiveSolarPathLengthCorrector(SunZenithCorrectorBase): From 7db07fee730645c97c039717804a6d262967e02a Mon Sep 17 00:00:00 2001 From: Johan Strandgren Date: Thu, 21 May 2026 13:49:59 +0000 Subject: [PATCH 17/49] Add tests to check that data type is preserved in SunZenithReducer and that no computation is triggered. --- satpy/tests/test_modifiers.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/satpy/tests/test_modifiers.py b/satpy/tests/test_modifiers.py index 6dbfcb4d4c..bcf0612742 100644 --- a/satpy/tests/test_modifiers.py +++ b/satpy/tests/test_modifiers.py @@ -306,6 +306,7 @@ def test_default_settings(self, sunz_ds1, sunz_sza, dtype): values = res.values assert values.dtype == dtype np.testing.assert_allclose(values, expected, rtol=2e-5) + assert type(res.data) is type(sunz_ds1.data) @pytest.mark.parametrize("dtype", [np.float32, np.float64]) def test_custom_settings(self, sunz_ds1, sunz_sza, dtype): @@ -317,6 +318,7 @@ def test_custom_settings(self, sunz_ds1, sunz_sza, dtype): values = res.values assert values.dtype == dtype np.testing.assert_allclose(values, expected, rtol=2e-5) + assert type(res.data) is type(sunz_ds1.data) def test_invalid_max_sza(self): """Test invalid max_sza with sza data available.""" @@ -374,7 +376,6 @@ def setup_method(self): "units": "K", }) - @pytest.mark.parametrize( ("include_sunz", "include_co2", "exp_res"), [ From 8977287453599482289d5cf67f96f5627563f42f Mon Sep 17 00:00:00 2001 From: Johan Strandgren Date: Thu, 21 May 2026 14:00:27 +0000 Subject: [PATCH 18/49] Make sure sunzen_reduction doesn't compute any data and remove map_blocks wrapper --- satpy/modifiers/angles.py | 21 ++++++--------------- satpy/modifiers/geometry.py | 12 ++++++------ 2 files changed, 12 insertions(+), 21 deletions(-) diff --git a/satpy/modifiers/angles.py b/satpy/modifiers/angles.py index b74c2a4c0e..e026d593dc 100644 --- a/satpy/modifiers/angles.py +++ b/satpy/modifiers/angles.py @@ -640,21 +640,12 @@ def atmospheric_path_length_correction(data: xr.DataArray, return data * corr -def sunzen_reduction(data: da.Array, - sunz: da.Array, +def sunzen_reduction(data: xr.DataArray, + sunz: xr.DataArray, limit: float = 55., max_sza: float = 90., - strength: float = 1.5) -> da.Array: + strength: float = 1.5) -> xr.DataArray: """Reduced strength of signal at high sun zenith angles.""" - return da.map_blocks(_sunzen_reduction_ndarray, data, sunz, limit, max_sza, strength, - meta=np.array((), dtype=data.dtype), chunks=data.chunks) - - -def _sunzen_reduction_ndarray(data: np.ndarray, - sunz: np.ndarray, - limit: float, - max_sza: float, - strength: float) -> np.ndarray: # compute reduction factor (0.0 - 1.0) between limit and maz_sza reduction_factor = (sunz - limit) / (max_sza - limit) reduction_factor = reduction_factor.clip(0., 1.) @@ -669,11 +660,11 @@ def _sunzen_reduction_ndarray(data: np.ndarray, reduction_factor = reduction_factor ** strength / ( reduction_factor ** strength + (1 - reduction_factor) ** strength) - # compute final correction term, with no reduction for angles < limit - corr = np.where(sunz < limit, 1.0, reduction_factor) + # compute final correction term, with no reduction (=1.0) for angles < limit + corr = reduction_factor.where(sunz >= limit, 1.0) # force "night" pixels to 0 (where SZA is invalid) - corr[np.isnan(sunz)] = 0 + corr = corr.where(sunz.notnull(), 0) # reduce data signal with correction term res = data * corr diff --git a/satpy/modifiers/geometry.py b/satpy/modifiers/geometry.py index 91863a24bf..d6e4c7c35f 100644 --- a/satpy/modifiers/geometry.py +++ b/satpy/modifiers/geometry.py @@ -233,10 +233,10 @@ def __init__(self, correction_limit=80., max_sza=90, strength=1.3, **kwargs): # def _apply_correction(self, proj, coszen): logger.debug(f"Applying sun-zenith signal reduction with correction_limit {self.correction_limit} deg," f" strength {self.strength}, and max_sza {self.max_sza} deg.") - res = proj.copy() - sunz = np.rad2deg(np.arccos(coszen.data)) - res.data = sunzen_reduction(proj.data, sunz, - limit=self.correction_limit, - max_sza=self.max_sza, - strength=self.strength) + sunz = np.rad2deg(np.arccos(coszen)) + res = sunzen_reduction(proj, + sunz, + limit=self.correction_limit, + max_sza=self.max_sza, + strength=self.strength) return res From feb958f26317540c371e0674760a059d9c1fc56b Mon Sep 17 00:00:00 2001 From: Johan Strandgren Date: Thu, 21 May 2026 15:13:23 +0000 Subject: [PATCH 19/49] Refactor sunzen_corr_cos to reduce cyclomatic complexity, --- satpy/modifiers/angles.py | 52 +++++++++++++++++++++++---------------- 1 file changed, 31 insertions(+), 21 deletions(-) diff --git a/satpy/modifiers/angles.py b/satpy/modifiers/angles.py index e026d593dc..28655f3da6 100644 --- a/satpy/modifiers/angles.py +++ b/satpy/modifiers/angles.py @@ -557,29 +557,28 @@ def sunzen_corr_cos(data: xr.DataArray, """ sunz = np.rad2deg(np.arccos(cos_zen)) + corr_standard = (1. / cos_zen) + corr_at_limit = ( + 1. / np.cos(np.deg2rad(correction_limit)) + if correction_limit is not None + else None + ) - # Start from standard cosine correction - corr = (1. / cos_zen).astype(data.dtype, copy=False) - - if correction_limit is not None: - corr_at_limit = 1. / np.cos(np.deg2rad(correction_limit)) - - if correction_limit is None and max_sza is None: - logger.debug("Apply the standard sun-zenith correction [1/cos(sunz)].") - # Nothing more to do, the standard correction is already applied above. - elif correction_limit is None and max_sza is not None: + def cutoff(): logger.debug( f"Apply the standard sun-zenith correction [1/cos(sunz)] but set correction (and reflectance) " f"to 0 for angles larger than {max_sza} degrees." ) - corr = corr.where(sunz <= max_sza, 0).astype(data.dtype, copy=False) - elif correction_limit is not None and max_sza is None: + return corr_standard.where(sunz <= max_sza, 0) + + def capped(): logger.debug( f"Apply the standard sun-zenith correction [1/cos(sunz)] but cap the maximum correction " f"for angles larger than {correction_limit} degrees." ) - corr = corr.where(sunz <= correction_limit, corr_at_limit).astype(data.dtype, copy=False) - elif correction_limit is not None and max_sza is not None: + return corr_standard.where(sunz <= correction_limit, corr_at_limit) + + def reduced(): logger.debug( f"Apply the standard sun-zenith correction [1/cos(sunz)] but gradually reduce the correction " f"for angles larger than {correction_limit} degrees up to {max_sza} degrees where the " @@ -597,22 +596,33 @@ def sunzen_corr_cos(data: xr.DataArray, corr_with_reduction = (corr_at_limit * reduction_factor) - corr = corr.where(sunz < correction_limit, corr_with_reduction).astype(data.dtype, copy=False) + return corr_standard.where(sunz < correction_limit, corr_with_reduction) + + # Check if any modification of the standard correction is requested + if correction_limit is None and max_sza is not None: + corr = cutoff() + elif correction_limit is not None and max_sza is None: + corr = capped() + elif correction_limit is not None and max_sza is not None: + corr = reduced() + else: + logger.debug("Apply the standard sun-zenith correction [1/cos(sunz)].") + corr = corr_standard if correction_limit is not None: logger.warning( "Capping or reducing the standard Sun zenith angle correction may lead to underesimated " - "reflectance values which is undesireble for scientific applications. To reduce the " - "overcorrection for (RGB) imagery the effective pathlength parameterization by Li and " - "Shibata (2006) is recommended over the standard correction. See " + "reflectance values which is undesireble for quantitative and scientific applications. " + "To reduce the overcorrection for (RGB) imagery the effective pathlength parameterization " + "by Li and Shibata (2006) is recommended over the standard correction. See " "EffectiveSolarPathLengthCorrector for more details on this parameterization and how " "to use it." ) - # Make sure we don't make anything negative + # Preserve data type, make sure we don't produce negative values and set correction to 0 for + # "night" and space pixels where SZA is invalid + corr = corr.astype(data.dtype, copy=False) corr = corr.clip(0.) - - # Force "night" and space pixels to 0 (where SZA is invalid) corr = corr.where(cos_zen.notnull(), 0) return data * corr From afc345ff1f5b1b478d18f7419249bbfa35cac537 Mon Sep 17 00:00:00 2001 From: Johan Strandgren Date: Fri, 22 May 2026 07:35:14 +0000 Subject: [PATCH 20/49] Refactor tests for sunz modifiers to reduce duplicate code --- satpy/tests/test_modifiers.py | 128 ++++++++++++++-------------------- 1 file changed, 53 insertions(+), 75 deletions(-) diff --git a/satpy/tests/test_modifiers.py b/satpy/tests/test_modifiers.py index bcf0612742..f9e3e645ae 100644 --- a/satpy/tests/test_modifiers.py +++ b/satpy/tests/test_modifiers.py @@ -109,6 +109,29 @@ def sunz_sza(): return sza +def call_sunz_modifier(comp, data_arr, sunz_sza=None, dtype=None): + """Helper function for running sunz modifiers.""" + if dtype is not None: + data_arr = data_arr.astype(dtype) + if sunz_sza is not None: + sunz_sza = sunz_sza.astype(dtype) + + info = {"test_attr": "test"} + if sunz_sza is not None: + info["optional_datasets"] = [sunz_sza] + + return comp((data_arr,), **info) + + +def assert_sunz_modifier_result(res, expected, data_arr, dtype=None, rtol=1e-5): + """Helper function for asserting sunz modifier results.""" + np.testing.assert_allclose(res.values, expected, rtol=rtol) + assert type(res.data) is type(data_arr.data) + if dtype is not None: + assert res.dtype == dtype + assert res.values.dtype == dtype + + class TestSunZenithCorrector: """Test case for the standard Sun zenith angle corrector.""" @@ -116,20 +139,19 @@ class TestSunZenithCorrector: def test_default_with_sza_not_provided(self, sunz_ds1, as_32bit): """Test default limits when SZA isn't provided.""" from satpy.modifiers.geometry import SunZenithCorrector - if as_32bit: sunz_ds1 = sunz_ds1.astype(np.float32) comp = SunZenithCorrector(name="sza_test", modifiers=tuple()) - res = comp((sunz_ds1,), test_attr="test") - np.testing.assert_allclose(res.values, np.array([[22.401667, 22.31777], [22.437503, 22.353533]]), - rtol=1e-5) + expected = np.array([[22.401667, 22.31777], [22.437503, 22.353533]]) + res = call_sunz_modifier(comp, sunz_ds1) + assert_sunz_modifier_result(res, expected, sunz_ds1) assert "y" in res.coords assert "x" in res.coords + ds1 = sunz_ds1.copy().drop_vars(("y", "x")) - res = comp((ds1,), test_attr="test") + res = call_sunz_modifier(comp, ds1) res_np = res.compute() - np.testing.assert_allclose(res_np.values, np.array([[22.401667, 22.31777], [22.437503, 22.353533]]), - rtol=1e-5) + np.testing.assert_allclose(res_np.values, expected, rtol=1e-5) assert res.dtype == res_np.dtype assert "y" not in res.coords assert "x" not in res.coords @@ -142,14 +164,9 @@ def test_default_with_sza_provided(self, data_arr, sunz_sza, dtype): """Test default limits when SZA is provided.""" from satpy.modifiers.geometry import SunZenithCorrector comp = SunZenithCorrector(name="sza_test", modifiers=tuple()) - info = {"test_attr": "test", "optional_datasets": [sunz_sza.astype(dtype)]} - res = comp((data_arr.astype(dtype),), **info) expected = np.array([[5.758770, 19.107323], [23.133712, 6.372368]], dtype=dtype) - values = res.values - np.testing.assert_allclose(values, expected, rtol=1e-5) - assert res.dtype == dtype - assert values.dtype == dtype - assert type(res.data) is type(data_arr.data) + res = call_sunz_modifier(comp, data_arr, sunz_sza, dtype) + assert_sunz_modifier_result(res, expected, data_arr, dtype) @pytest.mark.parametrize("dtype", [np.float32, np.float64]) @pytest.mark.parametrize("data_arr", [lazy_fixture("sunz_ds1"), lazy_fixture("sunz_ds1_stacked")]) @@ -157,14 +174,9 @@ def test_standard_with_sza_provided(self, data_arr, sunz_sza, dtype): """Test correction_limit=None and max_sza=None when SZA is provided.""" from satpy.modifiers.geometry import SunZenithCorrector comp = SunZenithCorrector(name="sza_test", modifiers=tuple(), correction_limit=None, max_sza=None) - info = {"test_attr": "test", "optional_datasets": [sunz_sza.astype(dtype)]} - res = comp((data_arr.astype(dtype),), **info) expected = np.array([[5.758770, 19.107323], [57.298689, 0.0]], dtype=dtype) - values = res.values - np.testing.assert_allclose(values, expected, rtol=1e-5) - assert res.dtype == dtype - assert values.dtype == dtype - assert type(res.data) is type(data_arr.data) + res = call_sunz_modifier(comp, data_arr, sunz_sza, dtype) + assert_sunz_modifier_result(res, expected, data_arr, dtype) @pytest.mark.parametrize("dtype", [np.float32, np.float64]) @pytest.mark.parametrize("data_arr", [lazy_fixture("sunz_ds1"), lazy_fixture("sunz_ds1_stacked")]) @@ -172,14 +184,9 @@ def test_custom_max_sza_with_sza_provided(self, data_arr, sunz_sza, dtype): """Test custom max_sza (and correction_limit=None) when SZA is provided.""" from satpy.modifiers.geometry import SunZenithCorrector comp = SunZenithCorrector(name="sza_test", modifiers=tuple(), correction_limit=None, max_sza=88) - info = {"test_attr": "test", "optional_datasets": [sunz_sza.astype(dtype)]} - res = comp((data_arr.astype(dtype),), **info) expected = np.array([[5.758770, 19.107323], [0.0, 0.0]], dtype=dtype) - values = res.values - np.testing.assert_allclose(values, expected, rtol=1e-5) - assert res.dtype == dtype - assert values.dtype == dtype - assert type(res.data) is type(data_arr.data) + res = call_sunz_modifier(comp, data_arr, sunz_sza, dtype) + assert_sunz_modifier_result(res, expected, data_arr, dtype) @pytest.mark.parametrize("dtype", [np.float32, np.float64]) @pytest.mark.parametrize("data_arr", [lazy_fixture("sunz_ds1"), lazy_fixture("sunz_ds1_stacked")]) @@ -187,14 +194,9 @@ def test_custom_correction_limit_with_sza_provided(self, data_arr, sunz_sza, dty """Test custom correction_limit (and max_sza=None) when SZA is provided.""" from satpy.modifiers.geometry import SunZenithCorrector comp = SunZenithCorrector(name="sza_test", modifiers=tuple(), correction_limit=88, max_sza=None) - info = {"test_attr": "test", "optional_datasets": [sunz_sza.astype(dtype)]} - res = comp((data_arr.astype(dtype),), **info) expected = np.array([[5.758770, 19.107323], [28.653708, 28.653708]], dtype=dtype) - values = res.values - np.testing.assert_allclose(values, expected, rtol=1e-5) - assert res.dtype == dtype - assert values.dtype == dtype - assert type(res.data) is type(data_arr.data) + res = call_sunz_modifier(comp, data_arr, sunz_sza, dtype) + assert_sunz_modifier_result(res, expected, data_arr, dtype) @pytest.mark.parametrize("dtype", [np.float32, np.float64]) @pytest.mark.parametrize("data_arr", [lazy_fixture("sunz_ds1"), lazy_fixture("sunz_ds1_stacked")]) @@ -202,23 +204,17 @@ def test_custom_max_sza_and_correction_limit_with_sza_provided(self, data_arr, s """Test custom correction_limit and max_sza when SZA is provided.""" from satpy.modifiers.geometry import SunZenithCorrector comp = SunZenithCorrector(name="sza_test", modifiers=tuple(), correction_limit=88, max_sza=95) - info = {"test_attr": "test", "optional_datasets": [sunz_sza.astype(dtype)]} - res = comp((data_arr.astype(dtype),), **info) expected = np.array([[5.758770, 19.107323], [23.133712, 6.372368]], dtype=dtype) - values = res.values - np.testing.assert_allclose(values, expected, rtol=1e-5) - assert res.dtype == dtype - assert values.dtype == dtype - assert type(res.data) is type(data_arr.data) + res = call_sunz_modifier(comp, data_arr, sunz_sza, dtype) + assert_sunz_modifier_result(res, expected, data_arr, dtype) def test_incompatible_areas(self, sunz_ds2, sunz_sza): """Test sunz correction on incompatible areas.""" from satpy.composites.core import IncompatibleAreas from satpy.modifiers.geometry import SunZenithCorrector comp = SunZenithCorrector(name="sza_test", modifiers=tuple()) - info = {"test_attr": "test", "optional_datasets": [sunz_sza]} with pytest.raises(IncompatibleAreas): - comp((sunz_ds2,), **info) + call_sunz_modifier(comp, sunz_ds2, sunz_sza) class TestEffectiveSolarPathLengthCorrector: @@ -228,20 +224,19 @@ class TestEffectiveSolarPathLengthCorrector: def test_with_sza_not_provided(self, sunz_ds1, as_32bit): """Test when SZA isn't provided.""" from satpy.modifiers.geometry import EffectiveSolarPathLengthCorrector - if as_32bit: sunz_ds1 = sunz_ds1.astype(np.float32) comp = EffectiveSolarPathLengthCorrector(name="sza_test", modifiers=tuple()) - res = comp((sunz_ds1,), test_attr="test") - np.testing.assert_allclose(res.values, np.array([[22.458680, 22.512698], [22.435495, 22.489718]]), - rtol=1e-5) + expected = np.array([[22.458680, 22.512698], [22.435495, 22.489718]]) + res = call_sunz_modifier(comp, sunz_ds1) + assert_sunz_modifier_result(res, expected, sunz_ds1) assert "y" in res.coords assert "x" in res.coords + ds1 = sunz_ds1.copy().drop_vars(("y", "x")) - res = comp((ds1,), test_attr="test") + res = call_sunz_modifier(comp, ds1) res_np = res.compute() - np.testing.assert_allclose(res_np.values, np.array([[22.458680, 22.512698], [22.435495, 22.489718]]), - rtol=1e-5) + np.testing.assert_allclose(res_np.values, expected, rtol=1e-5) assert res.dtype == res_np.dtype assert "y" not in res.coords assert "x" not in res.coords @@ -254,14 +249,9 @@ def test_with_sza_provided(self, data_arr, sunz_sza, dtype): """Test when SZA is provided.""" from satpy.modifiers.geometry import EffectiveSolarPathLengthCorrector comp = EffectiveSolarPathLengthCorrector(name="sza_test", modifiers=tuple()) - info = {"test_attr": "test", "optional_datasets": [sunz_sza.astype(dtype)]} - res = comp((data_arr.astype(dtype),), **info) expected = np.array([[5.595989, 14.823307], [21.973671, 16.988299]], dtype=dtype) - values = res.values - np.testing.assert_allclose(values, expected, rtol=1e-5) - assert res.dtype == dtype - assert values.dtype == dtype - assert type(res.data) is type(data_arr.data) + res = call_sunz_modifier(comp, data_arr, sunz_sza, dtype) + assert_sunz_modifier_result(res, expected, data_arr, dtype) def test_with_deprecated_correction_limit(self): """Test with deprecated correction_limit.""" @@ -280,9 +270,8 @@ def test_incompatible_areas(self, sunz_ds2, sunz_sza): from satpy.composites.core import IncompatibleAreas from satpy.modifiers.geometry import EffectiveSolarPathLengthCorrector comp = EffectiveSolarPathLengthCorrector(name="sza_test", modifiers=tuple()) - info = {"test_attr": "test", "optional_datasets": [sunz_sza]} with pytest.raises(IncompatibleAreas): - comp((sunz_ds2,), **info) + call_sunz_modifier(comp, sunz_ds2, sunz_sza) class TestSunZenithReducer: @@ -299,26 +288,16 @@ def setup_class(cls): @pytest.mark.parametrize("dtype", [np.float32, np.float64]) def test_default_settings(self, sunz_ds1, sunz_sza, dtype): """Test default settings with sza data available.""" - info = {"test_attr": "test", "optional_datasets": [sunz_sza.astype(dtype)]} - res = self.default((sunz_ds1.astype(dtype),), **info) expected = np.array([[1.0, 0.176790], [0.036095, 0.0]], dtype=dtype) - assert res.dtype == dtype - values = res.values - assert values.dtype == dtype - np.testing.assert_allclose(values, expected, rtol=2e-5) - assert type(res.data) is type(sunz_ds1.data) + res = call_sunz_modifier(self.default, sunz_ds1, sunz_sza, dtype) + assert_sunz_modifier_result(res, expected, sunz_ds1, dtype, rtol=2e-5) @pytest.mark.parametrize("dtype", [np.float32, np.float64]) def test_custom_settings(self, sunz_ds1, sunz_sza, dtype): """Test custom settings with sza data available.""" - info = {"test_attr": "test", "optional_datasets": [sunz_sza.astype(dtype)]} - res = self.custom((sunz_ds1.astype(dtype),), **info) expected = np.array([[5.436207e-01, 3.657017e-02], [1.143065e-02, 2.450100e-04]], dtype=dtype) - assert res.dtype == dtype - values = res.values - assert values.dtype == dtype - np.testing.assert_allclose(values, expected, rtol=2e-5) - assert type(res.data) is type(sunz_ds1.data) + res = call_sunz_modifier(self.custom, sunz_ds1, sunz_sza, dtype) + assert_sunz_modifier_result(res, expected, sunz_ds1, dtype, rtol=2e-5) def test_invalid_max_sza(self): """Test invalid max_sza with sza data available.""" @@ -326,7 +305,6 @@ def test_invalid_max_sza(self): with pytest.raises(ValueError, match="`max_sza` must be defined when using the SunZenithReducer."): SunZenithReducer(name="sza_reduction_test_invalid", modifiers=tuple(), max_sza=None) - class TestNIRReflectance: """Test NIR reflectance compositor.""" From d72c4c9fa3c60aa76cc7f67f0ce88131a8b121b4 Mon Sep 17 00:00:00 2001 From: Johan Strandgren Date: Fri, 22 May 2026 09:59:00 +0000 Subject: [PATCH 21/49] Change default behaviour of SunZenithCorrector to compute true reflectance instead. Modify sunz_corrected to still use previous reduction for now and ad a warning that this will change in satpy v1.0 --- satpy/etc/composites/visir.yaml | 11 ++++++++++- satpy/modifiers/geometry.py | 13 ++++++++++--- satpy/tests/test_modifiers.py | 4 ++-- 3 files changed, 22 insertions(+), 6 deletions(-) diff --git a/satpy/etc/composites/visir.yaml b/satpy/etc/composites/visir.yaml index 6738f59878..0f3c6ef3ab 100644 --- a/satpy/etc/composites/visir.yaml +++ b/satpy/etc/composites/visir.yaml @@ -8,8 +8,17 @@ composite_identification_keys: modifiers: sunz_corrected: modifier: !!python/name:satpy.modifiers.SunZenithCorrector + user_warning: > + The reduction of the correction above 88 degrees will be removed in satpy v1.0 + in order to compute the true reflectance with the 'sunz_corrected' modifier. + To avoid overcorrection at high angles for (RGB) imagery it's + recommended to use the 'effective_solar_pathlength_corrected' modifier instead. + If you still want to keep the current behaviour, please set the 'correction_limit' + parameter to 88.0 and 'max_sza' to 95.0. + correction_limit: 88.0 + max_sza: 95.0 optional_prerequisites: - - solar_zenith_angle + - solar_zenith_angle effective_solar_pathlength_corrected: modifier: !!python/name:satpy.modifiers.EffectiveSolarPathLengthCorrector diff --git a/satpy/modifiers/geometry.py b/satpy/modifiers/geometry.py index d6e4c7c35f..e9b5f47c31 100644 --- a/satpy/modifiers/geometry.py +++ b/satpy/modifiers/geometry.py @@ -20,6 +20,7 @@ from __future__ import annotations import logging +import warnings from typing import Optional import numpy as np @@ -112,8 +113,9 @@ class SunZenithCorrector(SunZenithCorrectorBase): def __init__( self, - correction_limit: Optional[float] = 88.0, - max_sza: Optional[float] = 95.0, + correction_limit: Optional[float] = None, + max_sza: Optional[float] = None, + user_warning: Optional[str] = None, **kwargs, ): """Collect custom configuration values. @@ -129,6 +131,9 @@ def __init__( Pixels with solar zenith angles greater than ``max_sza`` are set to 0. + user_warning: + Optional user warning to be shown when applying the correction. + **kwargs: Additional keyword arguments passed to the parent class. @@ -136,9 +141,12 @@ def __init__( self.method = "sunz_corrected" self.correction_limit = correction_limit self.max_sza = max_sza + self.user_warning = user_warning super(SunZenithCorrector, self).__init__(**kwargs) def _apply_correction(self, proj, coszen): + if self.user_warning: + warnings.warn(self.user_warning, UserWarning, stacklevel=2) return sunzen_corr_cos(proj, coszen, correction_limit=self.correction_limit, max_sza=self.max_sza) @@ -176,7 +184,6 @@ def __init__( max_sza: Maximum valid angle in degrees for solar zenith angle correction. Deprecated. - **kwargs: Additional keyword arguments passed to the parent class. diff --git a/satpy/tests/test_modifiers.py b/satpy/tests/test_modifiers.py index f9e3e645ae..cf59012eb9 100644 --- a/satpy/tests/test_modifiers.py +++ b/satpy/tests/test_modifiers.py @@ -142,7 +142,7 @@ def test_default_with_sza_not_provided(self, sunz_ds1, as_32bit): if as_32bit: sunz_ds1 = sunz_ds1.astype(np.float32) comp = SunZenithCorrector(name="sza_test", modifiers=tuple()) - expected = np.array([[22.401667, 22.31777], [22.437503, 22.353533]]) + expected = np.array([[66.853256, 68.168938], [66.307419, 67.601494]]) res = call_sunz_modifier(comp, sunz_ds1) assert_sunz_modifier_result(res, expected, sunz_ds1) assert "y" in res.coords @@ -164,7 +164,7 @@ def test_default_with_sza_provided(self, data_arr, sunz_sza, dtype): """Test default limits when SZA is provided.""" from satpy.modifiers.geometry import SunZenithCorrector comp = SunZenithCorrector(name="sza_test", modifiers=tuple()) - expected = np.array([[5.758770, 19.107323], [23.133712, 6.372368]], dtype=dtype) + expected = np.array([[5.758770, 19.107323], [57.298689, 0.0]], dtype=dtype) res = call_sunz_modifier(comp, data_arr, sunz_sza, dtype) assert_sunz_modifier_result(res, expected, data_arr, dtype) From be37d098b9a760f01d068bbc95c8e60197aabacb Mon Sep 17 00:00:00 2001 From: Johan Strandgren Date: Fri, 22 May 2026 09:59:54 +0000 Subject: [PATCH 22/49] use warnings package instead for warning of deprecated use. Fix use of tick marks --- satpy/modifiers/geometry.py | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/satpy/modifiers/geometry.py b/satpy/modifiers/geometry.py index e9b5f47c31..b505cd6867 100644 --- a/satpy/modifiers/geometry.py +++ b/satpy/modifiers/geometry.py @@ -189,14 +189,14 @@ def __init__( """ if correction_limit is not None or max_sza is not None: - raise UserWarning( - "The `correction_limit` and `max_sza` parameters are deprecated and not " - "used for the EffectiveSolarPathLengthCorrector since the parameterization " - "by Li and Shibata (2006) already accounts for overcorrection at high solar " - "zenith angles. If capping or reduction of the correction is still desireble " - "it can be achieved by using the SunZenithCorrector with the same " - "`correction_limit` and `max_sza` parameters." - ) + msg = "The ``correction_limit`` and ``max_sza`` parameters have been deprecated and are no " \ + "longer used for the EffectiveSolarPathLengthCorrector and will be fully removed " \ + "in satpy v1.0. This is done since the parameterization by Li and Shibata (2006) " \ + "already accounts for overcorrection at high solar zenith angles. If capping or " \ + "reduction of the correction is still desirable it can be achieved by using the " \ + "``SunZenithCorrector`` with the same ``correction_limit`` and ``max_sza`` parameters." + warnings.warn(msg, UserWarning, stacklevel=2) + self.method = "effective_solar_pathlength_corrected" super(EffectiveSolarPathLengthCorrector, self).__init__(**kwargs) @@ -214,7 +214,7 @@ class SunZenithReducer(SunZenithCorrectorBase): where reduction_factor is a pixel-level value ranging from 0 to 1 within the sunz interval. - The `strength` parameter can be used for a non-linear reduction within the sunz interval. A strength larger + The ``strength`` parameter can be used for a non-linear reduction within the sunz interval. A strength larger than 1.0 will decelerate the signal reduction towards the sunz interval extremes, whereas a strength smaller than 1.0 will accelerate the signal reduction towards the sunz interval extremes. From 384a9df6174465e8cb242ed61efc87d8cbca3f2e Mon Sep 17 00:00:00 2001 From: Johan Strandgren Date: Fri, 22 May 2026 10:01:33 +0000 Subject: [PATCH 23/49] Change from warning to debug message when still applying reduction to SunZenithCorrector given that this is a feature available for a long time and would also lead to frequent warnings for VIIRS users where this will still be needed given differences in EDR and L1B data.. --- satpy/modifiers/angles.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/satpy/modifiers/angles.py b/satpy/modifiers/angles.py index 28655f3da6..224f48cc2f 100644 --- a/satpy/modifiers/angles.py +++ b/satpy/modifiers/angles.py @@ -610,13 +610,13 @@ def reduced(): corr = corr_standard if correction_limit is not None: - logger.warning( + logger.debug( "Capping or reducing the standard Sun zenith angle correction may lead to underesimated " "reflectance values which is undesireble for quantitative and scientific applications. " "To reduce the overcorrection for (RGB) imagery the effective pathlength parameterization " - "by Li and Shibata (2006) is recommended over the standard correction. See " - "EffectiveSolarPathLengthCorrector for more details on this parameterization and how " - "to use it." + "by Li and Shibata (2006) is recommended over the standard correction. This is available " + "through the ``effective_solar_pathlength_corrected`` modifier which can be used instead of " + "``sunz_corrected``" ) # Preserve data type, make sure we don't produce negative values and set correction to 0 for From 400fd5380e96b2371d7f6ba96be388d0a82299a6 Mon Sep 17 00:00:00 2001 From: Johan Strandgren Date: Fri, 22 May 2026 15:44:35 +0000 Subject: [PATCH 24/49] Remove log message when correction_limit is used for sunz_corrected since this will have to be used for VIIRS and may be used by others as well --- satpy/modifiers/angles.py | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/satpy/modifiers/angles.py b/satpy/modifiers/angles.py index 224f48cc2f..175482e10f 100644 --- a/satpy/modifiers/angles.py +++ b/satpy/modifiers/angles.py @@ -609,16 +609,6 @@ def reduced(): logger.debug("Apply the standard sun-zenith correction [1/cos(sunz)].") corr = corr_standard - if correction_limit is not None: - logger.debug( - "Capping or reducing the standard Sun zenith angle correction may lead to underesimated " - "reflectance values which is undesireble for quantitative and scientific applications. " - "To reduce the overcorrection for (RGB) imagery the effective pathlength parameterization " - "by Li and Shibata (2006) is recommended over the standard correction. This is available " - "through the ``effective_solar_pathlength_corrected`` modifier which can be used instead of " - "``sunz_corrected``" - ) - # Preserve data type, make sure we don't produce negative values and set correction to 0 for # "night" and space pixels where SZA is invalid corr = corr.astype(data.dtype, copy=False) From 5b294b25a3f309e70df32ff38ded706f0e408cde Mon Sep 17 00:00:00 2001 From: Johan Strandgren Date: Fri, 22 May 2026 15:53:26 +0000 Subject: [PATCH 25/49] clarify warning message --- satpy/etc/composites/visir.yaml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/satpy/etc/composites/visir.yaml b/satpy/etc/composites/visir.yaml index 0f3c6ef3ab..f6c72876f7 100644 --- a/satpy/etc/composites/visir.yaml +++ b/satpy/etc/composites/visir.yaml @@ -9,12 +9,12 @@ modifiers: sunz_corrected: modifier: !!python/name:satpy.modifiers.SunZenithCorrector user_warning: > - The reduction of the correction above 88 degrees will be removed in satpy v1.0 - in order to compute the true reflectance with the 'sunz_corrected' modifier. - To avoid overcorrection at high angles for (RGB) imagery it's - recommended to use the 'effective_solar_pathlength_corrected' modifier instead. + The reduction of the standard Sun zenith angle correction above 88 degrees will + be removed in satpy v1.0 in order to compute the true reflectance with the + 'sunz_corrected' modifier. To avoid overcorrection at high angles for (RGB) imagery + it's recommended to use the 'effective_solar_pathlength_corrected' modifier instead. If you still want to keep the current behaviour, please set the 'correction_limit' - parameter to 88.0 and 'max_sza' to 95.0. + parameter to 88.0 and 'max_sza' to 95.0 in a local definition of the modifier. correction_limit: 88.0 max_sza: 95.0 optional_prerequisites: From 854f0adf4066007f26b0ab2689d86add7446e4a6 Mon Sep 17 00:00:00 2001 From: Johan Strandgren Date: Tue, 26 May 2026 12:27:48 +0000 Subject: [PATCH 26/49] Fix warning in tests. --- satpy/tests/test_modifiers.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/satpy/tests/test_modifiers.py b/satpy/tests/test_modifiers.py index cf59012eb9..5394b09256 100644 --- a/satpy/tests/test_modifiers.py +++ b/satpy/tests/test_modifiers.py @@ -256,13 +256,13 @@ def test_with_sza_provided(self, data_arr, sunz_sza, dtype): def test_with_deprecated_correction_limit(self): """Test with deprecated correction_limit.""" from satpy.modifiers.geometry import EffectiveSolarPathLengthCorrector - with pytest.raises(UserWarning): + with pytest.warns(UserWarning, match="deprecated"): EffectiveSolarPathLengthCorrector(name="sza_test", modifiers=tuple(), correction_limit=88) def test_with_deprecated_sza_max(self): """Test with deprecated max_sza.""" from satpy.modifiers.geometry import EffectiveSolarPathLengthCorrector - with pytest.raises(UserWarning): + with pytest.warns(UserWarning, match="deprecated"): EffectiveSolarPathLengthCorrector(name="sza_test", modifiers=tuple(), max_sza=95) def test_incompatible_areas(self, sunz_ds2, sunz_sza): From 019a2e8a0711ff994233128b42c78c3e5d73d683 Mon Sep 17 00:00:00 2001 From: Johan Strandgren Date: Tue, 26 May 2026 12:33:36 +0000 Subject: [PATCH 27/49] Add more tests for warnings and invalid combination --- satpy/modifiers/angles.py | 2 +- satpy/tests/test_modifiers.py | 19 +++++++++++++++++++ 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/satpy/modifiers/angles.py b/satpy/modifiers/angles.py index 175482e10f..16990ce8c6 100644 --- a/satpy/modifiers/angles.py +++ b/satpy/modifiers/angles.py @@ -586,7 +586,7 @@ def reduced(): ) if max_sza <= correction_limit: raise ValueError( - "max_sza should be larger than correction_limit for a gradual " + "`max_sza` must be larger than `correction_limit` for a gradual " "reduction of the correction to work.") reduction_factor = (sunz - correction_limit) / (max_sza - correction_limit) diff --git a/satpy/tests/test_modifiers.py b/satpy/tests/test_modifiers.py index 5394b09256..77d8118e7f 100644 --- a/satpy/tests/test_modifiers.py +++ b/satpy/tests/test_modifiers.py @@ -208,6 +208,25 @@ def test_custom_max_sza_and_correction_limit_with_sza_provided(self, data_arr, s res = call_sunz_modifier(comp, data_arr, sunz_sza, dtype) assert_sunz_modifier_result(res, expected, data_arr, dtype) + @pytest.mark.parametrize("dtype", [np.float32, np.float64]) + @pytest.mark.parametrize("data_arr", [lazy_fixture("sunz_ds1"), lazy_fixture("sunz_ds1_stacked")]) + def test_invalid_max_sza_and_correction_limit_with_sza_provided(self, data_arr, sunz_sza, dtype): + """Test with correction_limit > max_sza when SZA is provided.""" + from satpy.modifiers.geometry import SunZenithCorrector + comp = SunZenithCorrector(name="sza_test", modifiers=tuple(), correction_limit=88, max_sza=80) + with pytest.raises(ValueError, match="`max_sza` must be larger than `correction_limit`"): + call_sunz_modifier(comp, data_arr, sunz_sza, dtype) + + @pytest.mark.parametrize("dtype", [np.float32, np.float64]) + @pytest.mark.parametrize("data_arr", [lazy_fixture("sunz_ds1"), lazy_fixture("sunz_ds1_stacked")]) + def test_custom_warning_with_sza_provided(self, data_arr, sunz_sza, dtype): + """Test custom warning when SZA is provided.""" + from satpy.modifiers.geometry import SunZenithCorrector + msg = "This is a custom warning." + comp = SunZenithCorrector(name="sza_test", modifiers=tuple(), user_warning=msg) + with pytest.warns(UserWarning, match=msg): + call_sunz_modifier(comp, data_arr, sunz_sza, dtype) + def test_incompatible_areas(self, sunz_ds2, sunz_sza): """Test sunz correction on incompatible areas.""" from satpy.composites.core import IncompatibleAreas From 7b88b02136aecd83c08f6d72d470cb2ec30d49fb Mon Sep 17 00:00:00 2001 From: Johan Strandgren Date: Tue, 26 May 2026 13:56:55 +0000 Subject: [PATCH 28/49] Add comment on why sunz_corrected is needed for VIIRS data and explicitly set correction_limit to avoid overcorrection at high sun zenith angles given new default behaviour of SunZenithCorrector --- satpy/etc/composites/viirs.yaml | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/satpy/etc/composites/viirs.yaml b/satpy/etc/composites/viirs.yaml index c2f43670c4..03f8c750b0 100644 --- a/satpy/etc/composites/viirs.yaml +++ b/satpy/etc/composites/viirs.yaml @@ -101,14 +101,30 @@ modifiers: - name: solar_zenith_angle resolution: 742 + # Although `effective_solar_pathlength_corrected` is now the recommended solar zenith + # angle correction modifier for (RGB) imagery (agreed during RGB workshop in + # Norrkoeping 2025), we need to keep using `sunz_corrected` (SunZenithCorrector) + # for VIIRS data given that the SDR data come with the `1/cos(sunz)` normalization + # already applied, whereas the L1B data do not. Consequently, the `sunz_corrected` + # modifier is attached to the dataset when loading VIIRS SDR data. Hence, if we would + # use the `effective_solar_pathlength_corrected` modifier in the recipes defined below, + # we would not be able to load composites using VIIRS SDR data since satpy would not + # be able to find the "base" dataset with no modifiers applied, but only the one with + # the `sunz_corrected` modifier applied. + # Since the default behaviour of `sunz_corrected` has changed to compute the true + # reflectance, we explicitly define `correction_limit` in order to avoid over-correction + # at very high sun zenith angles. sunz_corrected: modifier: !!python/name:satpy.modifiers.SunZenithCorrector + correction_limit: 86 prerequisites: - name: solar_zenith_angle resolution: 742 + # See comment above concerning the use of `SunZenithCorrector` for VIIRS data. sunz_corrected_iband: modifier: !!python/name:satpy.modifiers.SunZenithCorrector + correction_limit: 86 prerequisites: - name: solar_zenith_angle resolution: 371 From 53b03350074584f975a34d185a9942290bcf87bc Mon Sep 17 00:00:00 2001 From: Johan Strandgren Date: Wed, 27 May 2026 07:31:36 +0000 Subject: [PATCH 29/49] change from `sunz_corrected` to `effective_solar_pathlength_corrected` modifier for sun zenith angle correction in composite recipes. --- satpy/etc/composites/abi.yaml | 96 +++++++++++++-------------- satpy/etc/composites/agri.yaml | 44 ++++++------ satpy/etc/composites/ahi.yaml | 42 ++++++------ satpy/etc/composites/ami.yaml | 40 +++++------ satpy/etc/composites/ec_msi.yaml | 15 ++++- satpy/etc/composites/epic.yaml | 15 ++++- satpy/etc/composites/fci.yaml | 94 +++++++++++++++++--------- satpy/etc/composites/ghi.yaml | 6 +- satpy/etc/composites/insat3d_img.yaml | 4 +- satpy/etc/composites/mersi-1.yaml | 33 +++++---- satpy/etc/composites/mersi-2.yaml | 36 ++++++---- satpy/etc/composites/mersi-3.yaml | 36 ++++++---- satpy/etc/composites/mersi-rm.yaml | 22 ++++-- satpy/etc/composites/modis.yaml | 56 ++++++++-------- satpy/etc/composites/msu-gs.yaml | 4 +- satpy/etc/composites/msu_gsa.yaml | 10 +-- satpy/etc/composites/seviri.yaml | 63 ++++++++++-------- satpy/etc/composites/slstr.yaml | 12 ++-- satpy/etc/composites/vii.yaml | 24 +++---- satpy/etc/composites/virr.yaml | 21 ++++-- satpy/etc/composites/visir.yaml | 38 +++++------ 21 files changed, 408 insertions(+), 303 deletions(-) diff --git a/satpy/etc/composites/abi.yaml b/satpy/etc/composites/abi.yaml index 0a6f0b9999..649a8ad6db 100644 --- a/satpy/etc/composites/abi.yaml +++ b/satpy/etc/composites/abi.yaml @@ -32,11 +32,11 @@ composites: prerequisites: # should we be using the most corrected or least corrected inputs? - name: C01 - modifiers: [sunz_corrected, rayleigh_corrected_crefl] + modifiers: [effective_solar_pathlength_corrected, rayleigh_corrected_crefl] - name: C02 - modifiers: [sunz_corrected, rayleigh_corrected_crefl] + modifiers: [effective_solar_pathlength_corrected, rayleigh_corrected_crefl] - name: C03 - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] standard_name: toa_bidirectional_reflectance green_raw: @@ -46,11 +46,11 @@ composites: prerequisites: # should we be using the most corrected or least corrected inputs? - name: C01 - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] - name: C02 - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] - name: C03 - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] standard_name: toa_bidirectional_reflectance green: @@ -60,11 +60,11 @@ composites: prerequisites: # should we be using the most corrected or least corrected inputs? - name: C01 - modifiers: [sunz_corrected, rayleigh_corrected] + modifiers: [effective_solar_pathlength_corrected, rayleigh_corrected] - name: C02 - modifiers: [sunz_corrected, rayleigh_corrected] + modifiers: [effective_solar_pathlength_corrected, rayleigh_corrected] - name: C03 - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] standard_name: toa_bidirectional_reflectance green_nocorr: @@ -82,30 +82,30 @@ composites: compositor: !!python/name:satpy.composites.resolution.SelfSharpenedRGB prerequisites: - name: C02 - modifiers: [sunz_corrected, rayleigh_corrected_crefl] + modifiers: [effective_solar_pathlength_corrected, rayleigh_corrected_crefl] - name: green_crefl - name: C01 - modifiers: [sunz_corrected, rayleigh_corrected_crefl] + modifiers: [effective_solar_pathlength_corrected, rayleigh_corrected_crefl] standard_name: true_color true_color_raw: compositor: !!python/name:satpy.composites.resolution.SelfSharpenedRGB prerequisites: - name: C02 - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] - name: green_raw - name: C01 - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] standard_name: true_color true_color: compositor: !!python/name:satpy.composites.resolution.SelfSharpenedRGB prerequisites: - name: C02 - modifiers: [sunz_corrected, rayleigh_corrected] + modifiers: [effective_solar_pathlength_corrected, rayleigh_corrected] - name: green - name: C01 - modifiers: [sunz_corrected, rayleigh_corrected] + modifiers: [effective_solar_pathlength_corrected, rayleigh_corrected] standard_name: true_color true_color_nocorr: @@ -120,11 +120,11 @@ composites: compositor: !!python/name:satpy.composites.resolution.SelfSharpenedRGB prerequisites: - name: C05 - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] - name: C03 - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] - name: C02 - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] high_resolution_band: blue standard_name: natural_color @@ -149,9 +149,9 @@ composites: compositor: !!python/name:satpy.composites.core.GenericCompositor prerequisites: - name: C02 - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] - name: C03 - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] - C14 standard_name: overview @@ -190,11 +190,11 @@ composites: prerequisites: # should we be using the most corrected or least corrected inputs? - name: C01 - modifiers: [sunz_corrected, rayleigh_corrected] + modifiers: [effective_solar_pathlength_corrected, rayleigh_corrected] - name: C02 - modifiers: [sunz_corrected, rayleigh_corrected] + modifiers: [effective_solar_pathlength_corrected, rayleigh_corrected] - name: C03 - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] standard_name: toa_bidirectional_reflectance cimss_green_sunz: @@ -203,11 +203,11 @@ composites: prerequisites: # should we be using the most corrected or least corrected inputs? - name: C01 - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] - name: C02 - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] - name: C03 - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] standard_name: toa_bidirectional_reflectance cimss_green: @@ -232,10 +232,10 @@ composites: Research Article: https://agupubs.onlinelibrary.wiley.com/doi/10.1029/2018EA000379 prerequisites: - name: C02 - modifiers: [sunz_corrected, rayleigh_corrected] + modifiers: [effective_solar_pathlength_corrected, rayleigh_corrected] - name: cimss_green_sunz_rayleigh - name: C01 - modifiers: [sunz_corrected, rayleigh_corrected] + modifiers: [effective_solar_pathlength_corrected, rayleigh_corrected] standard_name: cimss_true_color cimss_true_color_sunz: @@ -250,10 +250,10 @@ composites: Research Article: https://agupubs.onlinelibrary.wiley.com/doi/10.1029/2018EA000379 prerequisites: - name: C02 - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] - name: cimss_green_sunz - name: C01 - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] standard_name: cimss_true_color cimss_true_color: @@ -439,9 +439,9 @@ composites: prerequisites: - name: C13 - name: C02 - modifiers: [sunz_corrected, rayleigh_corrected] + modifiers: [effective_solar_pathlength_corrected, rayleigh_corrected] - name: C05 - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] standard_name: cloud_phase_distinction day_cloud_type_distinction: @@ -600,9 +600,9 @@ composites: compositor: !!python/name:satpy.composites.core.GenericCompositor prerequisites: - name: C03 - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] - name: C05 - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] - compositor: !!python/name:satpy.composites.arithmetic.DifferenceCompositor prerequisites: - name: C07 @@ -680,9 +680,9 @@ composites: prerequisites: - name: C06 - name: C03 - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] - name: C02 - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] standard_name: land_cloud_fire land_cloud: @@ -694,9 +694,9 @@ composites: prerequisites: - name: C05 - name: C03 - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] - name: C02 - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] standard_name: land_cloud snow: @@ -709,9 +709,9 @@ composites: compositor: !!python/name:satpy.composites.core.GenericCompositor prerequisites: - name: C03 - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] - name: C05 - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] - name: C07 modifiers: [nir_reflectance] standard_name: snow @@ -726,7 +726,7 @@ composites: compositor: !!python/name:satpy.composites.core.GenericCompositor prerequisites: - name: C03 - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] - name: C07 modifiers: [nir_reflectance] - name: C14 @@ -754,11 +754,11 @@ composites: compositor: !!python/name:satpy.composites.core.GenericCompositor prerequisites: - name: C05 - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] - name: C06 - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] - name: C02 - modifiers: [sunz_corrected, rayleigh_corrected] + modifiers: [effective_solar_pathlength_corrected, rayleigh_corrected] standard_name: cloud_phase cloud_phase_raw: @@ -796,9 +796,9 @@ composites: compositor: !!python/name:satpy.composites.resolution.SelfSharpenedRGB prerequisites: - name: C03 - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] - name: C02 - modifiers: [sunz_corrected, rayleigh_corrected] + modifiers: [effective_solar_pathlength_corrected, rayleigh_corrected] - name: green standard_name: true_color @@ -824,10 +824,10 @@ composites: compositor: !!python/name:satpy.composites.resolution.SelfSharpenedRGB prerequisites: - name: C02 - modifiers: [sunz_corrected, rayleigh_corrected] + modifiers: [effective_solar_pathlength_corrected, rayleigh_corrected] - name: green - name: C01 - modifiers: [sunz_corrected, rayleigh_corrected] + modifiers: [effective_solar_pathlength_corrected, rayleigh_corrected] standard_name: true_color_reproduction_color_stretch true_color_reproduction_uncorr: diff --git a/satpy/etc/composites/agri.yaml b/satpy/etc/composites/agri.yaml index 63a22cec76..5e5f48db00 100644 --- a/satpy/etc/composites/agri.yaml +++ b/satpy/etc/composites/agri.yaml @@ -8,11 +8,11 @@ composites: prerequisites: # should we be using the most corrected or least corrected inputs? - name: C01 - modifiers: [sunz_corrected, rayleigh_corrected] + modifiers: [effective_solar_pathlength_corrected, rayleigh_corrected] - name: C02 - modifiers: [sunz_corrected, rayleigh_corrected] + modifiers: [effective_solar_pathlength_corrected, rayleigh_corrected] - name: C03 - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] standard_name: toa_bidirectional_reflectance green_nocorr: @@ -33,9 +33,9 @@ composites: prerequisites: # should we be using the most corrected or least corrected inputs? - name: C02 - modifiers: [sunz_corrected, rayleigh_corrected] + modifiers: [effective_solar_pathlength_corrected, rayleigh_corrected] - name: C03 - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] standard_name: toa_bidirectional_reflectance pseudored_nocorr: @@ -54,7 +54,7 @@ composites: - name: pseudored - name: green - name: C01 - modifiers: [sunz_corrected, rayleigh_corrected] + modifiers: [effective_solar_pathlength_corrected, rayleigh_corrected] standard_name: true_color true_color_nocorr: @@ -77,9 +77,9 @@ composites: prerequisites: - name: C12 - name: C02 - modifiers: [sunz_corrected, rayleigh_corrected] + modifiers: [effective_solar_pathlength_corrected, rayleigh_corrected] - name: C05 - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] standard_name: cloud_phase_distinction cloud_phase_distinction_raw: @@ -101,9 +101,9 @@ composites: compositor: !!python/name:satpy.composites.core.GenericCompositor prerequisites: - name: C03 - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] - name: C05 - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] - compositor: !!python/name:satpy.composites.arithmetic.DifferenceCompositor prerequisites: - name: C07 @@ -133,9 +133,9 @@ composites: prerequisites: - name: C06 - name: C03 - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] - name: C02 - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] standard_name: land_cloud_fire land_cloud: @@ -148,9 +148,9 @@ composites: prerequisites: - name: C05 - name: C03 - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] - name: C02 - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] standard_name: land_cloud snow: @@ -163,9 +163,9 @@ composites: compositor: !!python/name:satpy.composites.core.GenericCompositor prerequisites: - name: C03 - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] - name: C05 - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] - name: C07 modifiers: [nir_reflectance] standard_name: snow @@ -180,7 +180,7 @@ composites: compositor: !!python/name:satpy.composites.core.GenericCompositor prerequisites: - name: C03 - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] - name: C07 modifiers: [nir_reflectance] - name: C12 @@ -211,11 +211,11 @@ composites: compositor: !!python/name:satpy.composites.core.GenericCompositor prerequisites: - name: C05 - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] - name: C06 - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] - name: C02 - modifiers: [sunz_corrected, rayleigh_corrected] + modifiers: [effective_solar_pathlength_corrected, rayleigh_corrected] standard_name: natural_color cloud_phase_raw: @@ -234,9 +234,9 @@ composites: compositor: !!python/name:satpy.composites.resolution.SelfSharpenedRGB prerequisites: - name: C03 - modifiers: [sunz_corrected, rayleigh_corrected] + modifiers: [effective_solar_pathlength_corrected, rayleigh_corrected] - name: C02 - modifiers: [sunz_corrected, rayleigh_corrected] + modifiers: [effective_solar_pathlength_corrected, rayleigh_corrected] - name: green standard_name: true_color diff --git a/satpy/etc/composites/ahi.yaml b/satpy/etc/composites/ahi.yaml index af8e96b4d3..f4774ed984 100644 --- a/satpy/etc/composites/ahi.yaml +++ b/satpy/etc/composites/ahi.yaml @@ -24,9 +24,9 @@ composites: # should we be using the most corrected or least corrected inputs? # what happens if something requests more modifiers on top of this? - wavelength: 0.51 - modifiers: [sunz_corrected, rayleigh_corrected] + modifiers: [effective_solar_pathlength_corrected, rayleigh_corrected] - wavelength: 0.85 - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] standard_name: toa_bidirectional_reflectance reproduced_green: @@ -35,11 +35,11 @@ composites: fractions: [0.6321, 0.2928, 0.0751] prerequisites: - name: B02 - modifiers: [sunz_corrected, rayleigh_corrected] + modifiers: [effective_solar_pathlength_corrected, rayleigh_corrected] - name: B03 - modifiers: [sunz_corrected, rayleigh_corrected] + modifiers: [effective_solar_pathlength_corrected, rayleigh_corrected] - name: B04 - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] standard_name: none reproduced_green_uncorr: @@ -69,11 +69,11 @@ composites: strength: 3.0 prerequisites: - name: B02 - modifiers: [sunz_corrected, rayleigh_corrected, sunz_reduced] + modifiers: [effective_solar_pathlength_corrected, rayleigh_corrected] - name: B03 - modifiers: [sunz_corrected, rayleigh_corrected, sunz_reduced] + modifiers: [effective_solar_pathlength_corrected, rayleigh_corrected] - name: B04 - modifiers: [sunz_corrected, sunz_reduced] + modifiers: [effective_solar_pathlength_corrected] standard_name: toa_bidirectional_reflectance airmass: @@ -200,9 +200,9 @@ composites: - wavelength: 3.85 modifiers: [nir_reflectance] - wavelength: 2.26 - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] - wavelength: 1.61 - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] standard_name: fire_temperature name: fire_temperature_39refl @@ -210,9 +210,9 @@ composites: compositor: !!python/name:satpy.composites.core.GenericCompositor prerequisites: - name: B03 - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] - name: B04 - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] - name: B13 standard_name: overview @@ -228,11 +228,11 @@ composites: compositor: !!python/name:satpy.composites.resolution.SelfSharpenedRGB prerequisites: - wavelength: 1.63 - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] - wavelength: 0.85 - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] - wavelength: 0.635 - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] high_resolution_band: blue standard_name: natural_color @@ -240,10 +240,10 @@ composites: compositor: !!python/name:satpy.composites.resolution.SelfSharpenedRGB prerequisites: - name: B03 - modifiers: [sunz_corrected, rayleigh_corrected] + modifiers: [effective_solar_pathlength_corrected, rayleigh_corrected] - name: hybrid_green - name: B01 - modifiers: [sunz_corrected, rayleigh_corrected] + modifiers: [effective_solar_pathlength_corrected, rayleigh_corrected] high_resolution_band: red standard_name: true_color @@ -251,10 +251,10 @@ composites: compositor: !!python/name:satpy.composites.resolution.SelfSharpenedRGB prerequisites: - name: B03 - modifiers: [sunz_corrected, rayleigh_corrected, sunz_reduced] + modifiers: [effective_solar_pathlength_corrected, rayleigh_corrected] - name: ndvi_hybrid_green - name: B01 - modifiers: [sunz_corrected, rayleigh_corrected, sunz_reduced] + modifiers: [effective_solar_pathlength_corrected, rayleigh_corrected] high_resolution_band: red standard_name: true_color @@ -302,10 +302,10 @@ composites: compositor: !!python/name:satpy.composites.resolution.SelfSharpenedRGB prerequisites: - name: B03 - modifiers: [sunz_corrected, rayleigh_corrected] + modifiers: [effective_solar_pathlength_corrected, rayleigh_corrected] - name: reproduced_green - name: B01 - modifiers: [sunz_corrected, rayleigh_corrected] + modifiers: [effective_solar_pathlength_corrected, rayleigh_corrected] standard_name: true_color_reproduction_color_stretch true_color_reproduction_uncorr: diff --git a/satpy/etc/composites/ami.yaml b/satpy/etc/composites/ami.yaml index 8dd9c3fc7b..c1b57c0699 100644 --- a/satpy/etc/composites/ami.yaml +++ b/satpy/etc/composites/ami.yaml @@ -6,9 +6,9 @@ composites: compositor: !!python/name:satpy.composites.spectral.HybridGreen prerequisites: - name: VI005 - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] - name: VI008 - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] standard_name: toa_bidirectional_reflectance fraction: 0.15 @@ -17,9 +17,9 @@ composites: compositor: !!python/name:satpy.composites.spectral.HybridGreen prerequisites: - name: VI005 - modifiers: [sunz_corrected, rayleigh_corrected] + modifiers: [effective_solar_pathlength_corrected, rayleigh_corrected] - name: VI008 - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] standard_name: toa_bidirectional_reflectance fraction: 0.15 @@ -36,9 +36,9 @@ composites: compositor: !!python/name:satpy.composites.spectral.HybridGreen prerequisites: - name: VI005 - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] - name: VI008 - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] standard_name: toa_bidirectional_reflectance fraction: 0.15 @@ -46,9 +46,9 @@ composites: compositor: !!python/name:satpy.composites.spectral.HybridGreen prerequisites: - name: VI005 - modifiers: [sunz_corrected, rayleigh_corrected] + modifiers: [effective_solar_pathlength_corrected, rayleigh_corrected] - name: VI008 - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] standard_name: toa_bidirectional_reflectance fraction: 0.15 @@ -72,11 +72,11 @@ composites: strength: 3.0 prerequisites: - name: VI005 - modifiers: [sunz_corrected, rayleigh_corrected] + modifiers: [effective_solar_pathlength_corrected, rayleigh_corrected] - name: VI006 - modifiers: [sunz_corrected, rayleigh_corrected] + modifiers: [effective_solar_pathlength_corrected, rayleigh_corrected] - name: VI008 - modifiers: [sunz_corrected ] + modifiers: [effective_solar_pathlength_corrected ] standard_name: toa_bidirectional_reflectance ndvi_hybrid_green_raw: @@ -95,20 +95,20 @@ composites: compositor: !!python/name:satpy.composites.resolution.SelfSharpenedRGB prerequisites: - name: VI006 - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] - name: hybrid_green_raw - name: VI004 - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] standard_name: true_color true_color: compositor: !!python/name:satpy.composites.resolution.SelfSharpenedRGB prerequisites: - name: VI006 - modifiers: [sunz_corrected, rayleigh_corrected] + modifiers: [effective_solar_pathlength_corrected, rayleigh_corrected] - name: hybrid_green - name: VI004 - modifiers: [sunz_corrected, rayleigh_corrected] + modifiers: [effective_solar_pathlength_corrected, rayleigh_corrected] standard_name: true_color true_color_nocorr: @@ -137,11 +137,11 @@ composites: compositor: !!python/name:satpy.composites.resolution.SelfSharpenedRGB prerequisites: - name: NR016 - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] - name: VI008 - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] - name: VI006 - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] high_resolution_band: blue standard_name: natural_color @@ -308,10 +308,10 @@ composites: compositor: !!python/name:satpy.composites.resolution.SelfSharpenedRGB prerequisites: - name: VI006 - modifiers: [sunz_corrected, rayleigh_corrected] + modifiers: [effective_solar_pathlength_corrected, rayleigh_corrected] - name: ndvi_hybrid_green - name: VI004 - modifiers: [sunz_corrected, rayleigh_corrected] + modifiers: [effective_solar_pathlength_corrected, rayleigh_corrected] standard_name: true_color_reproduction_color_stretch true_color_reproduction_uncorr: diff --git a/satpy/etc/composites/ec_msi.yaml b/satpy/etc/composites/ec_msi.yaml index 9a3242c69e..715eb34664 100644 --- a/satpy/etc/composites/ec_msi.yaml +++ b/satpy/etc/composites/ec_msi.yaml @@ -3,6 +3,15 @@ sensor_name: visir/ec_msi modifiers: sunz_corrected: + user_warning: > + The reduction of the standard Sun zenith angle correction above 88 degrees will + be removed in satpy v1.0 in order to compute the true reflectance with the + 'sunz_corrected' modifier. To avoid overcorrection at high angles for (RGB) imagery + it's recommended to use the 'effective_solar_pathlength_corrected' modifier instead. + If you still want to keep the current behaviour, please set the 'correction_limit' + parameter to 88.0 and 'max_sza' to 95.0 in a local definition of the modifier. + correction_limit: 88.0 + max_sza: 95.0 modifier: !!python/name:satpy.modifiers.SunZenithCorrector rayleigh_corrected: @@ -31,9 +40,9 @@ composites: compositor: !!python/name:satpy.composites.core.GenericCompositor prerequisites: - name: SWIR1 - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] - name: NIR - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] - name: VIS - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] standard_name: natural_color diff --git a/satpy/etc/composites/epic.yaml b/satpy/etc/composites/epic.yaml index 2bfca8ca0d..98a723d857 100644 --- a/satpy/etc/composites/epic.yaml +++ b/satpy/etc/composites/epic.yaml @@ -3,6 +3,15 @@ sensor_name: visir/epic modifiers: sunz_corrected: modifier: !!python/name:satpy.modifiers.SunZenithCorrector + user_warning: > + The reduction of the standard Sun zenith angle correction above 88 degrees will + be removed in satpy v1.0 in order to compute the true reflectance with the + 'sunz_corrected' modifier. To avoid overcorrection at high angles for (RGB) imagery + it's recommended to use the 'effective_solar_pathlength_corrected' modifier instead. + If you still want to keep the current behaviour, please set the 'correction_limit' + parameter to 88.0 and 'max_sza' to 95.0 in a local definition of the modifier. + correction_limit: 88.0 + max_sza: 95.0 optional_prerequisites: - solar_zenith_angle @@ -24,11 +33,11 @@ composites: compositor: !!python/name:satpy.composites.core.GenericCompositor prerequisites: - name: B680 - modifiers: [sunz_corrected, rayleigh_corrected] + modifiers: [effective_solar_pathlength_corrected, rayleigh_corrected] - name: B551 - modifiers: [sunz_corrected, rayleigh_corrected] + modifiers: [effective_solar_pathlength_corrected, rayleigh_corrected] - name: B443 - modifiers: [sunz_corrected, rayleigh_corrected] + modifiers: [effective_solar_pathlength_corrected, rayleigh_corrected] standard_name: true_color true_color_raw: diff --git a/satpy/etc/composites/fci.yaml b/satpy/etc/composites/fci.yaml index f73df3e557..57c8aedb10 100644 --- a/satpy/etc/composites/fci.yaml +++ b/satpy/etc/composites/fci.yaml @@ -54,11 +54,11 @@ composites: strength: 3.0 prerequisites: - name: vis_05 - modifiers: [sunz_corrected, rayleigh_corrected, sunz_reduced] + modifiers: [effective_solar_pathlength_corrected, rayleigh_corrected] - name: vis_06 - modifiers: [sunz_corrected, rayleigh_corrected, sunz_reduced] + modifiers: [effective_solar_pathlength_corrected, rayleigh_corrected] - name: vis_08 - modifiers: [sunz_corrected, sunz_reduced] + modifiers: [effective_solar_pathlength_corrected] standard_name: toa_bidirectional_reflectance ndvi_hybrid_green_raw: @@ -73,18 +73,18 @@ composites: - name: vis_08 standard_name: toa_bidirectional_reflectance - ndvi_hybrid_green_fully_sunzencorrected: + ndvi_hybrid_green_sunz_reduced: description: Same as ndvi_hybrid_green, but without Sun-zenith reduction compositor: !!python/name:satpy.composites.spectral.NDVIHybridGreen limits: [0.15, 0.05] strength: 3.0 prerequisites: - name: vis_05 - modifiers: [sunz_corrected, rayleigh_corrected] + modifiers: [effective_solar_pathlength_corrected, rayleigh_corrected, sunz_reduced] - name: vis_06 - modifiers: [sunz_corrected, rayleigh_corrected] + modifiers: [effective_solar_pathlength_corrected, rayleigh_corrected, sunz_reduced] - name: vis_08 - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected, sunz_reduced] standard_name: toa_bidirectional_reflectance ### Non-official HRV Clouds composite similar to SEVIRI @@ -94,9 +94,9 @@ composites: standard_name: hrv_clouds prerequisites: - name: vis_06 - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] - name: vis_06 - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] - ir_105 ### True Color @@ -108,23 +108,23 @@ composites: of the ndvi_hybrid_green composites for details. prerequisites: - name: vis_06 - modifiers: [sunz_corrected, rayleigh_corrected, sunz_reduced] + modifiers: [effective_solar_pathlength_corrected, rayleigh_corrected] - name: ndvi_hybrid_green - name: vis_04 - modifiers: [sunz_corrected, rayleigh_corrected, sunz_reduced] + modifiers: [effective_solar_pathlength_corrected, rayleigh_corrected] standard_name: true_color - true_color_fully_sunzencorrected: + true_color_sunz_reduced: compositor: !!python/name:satpy.composites.resolution.SelfSharpenedRGB description: > Same as true_color, but without Sun-zenith reduction. For users that want to maintain as much data as possible close to the terminator, at cost of some artefacts (bright limb and reddish clouds) (see issue #2643). prerequisites: - name: vis_06 - modifiers: [sunz_corrected, rayleigh_corrected] - - name: ndvi_hybrid_green_fully_sunzencorrected + modifiers: [effective_solar_pathlength_corrected, rayleigh_corrected, sunz_reduced] + - name: ndvi_hybrid_green_sunz_reduced - name: vis_04 - modifiers: [sunz_corrected, rayleigh_corrected] + modifiers: [effective_solar_pathlength_corrected, rayleigh_corrected, sunz_reduced] standard_name: true_color true_color_raw_with_corrected_green: @@ -187,10 +187,10 @@ composites: compositor: !!python/name:satpy.composites.resolution.SelfSharpenedRGB prerequisites: - name: vis_06 - modifiers: [sunz_corrected, rayleigh_corrected] + modifiers: [effective_solar_pathlength_corrected, rayleigh_corrected] - name: ndvi_hybrid_green - name: vis_04 - modifiers: [sunz_corrected, rayleigh_corrected] + modifiers: [effective_solar_pathlength_corrected, rayleigh_corrected] standard_name: true_color_reproduction_color_stretch true_color_reproduction_uncorr: @@ -358,7 +358,7 @@ composites: standard_name: ir_sandwich prerequisites: - name: "vis_06" - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] - name: colorized_ir_clouds colorized_ir_clouds: @@ -379,23 +379,39 @@ composites: ### other RGBs cloud_type: description: > - Equal to cimss_cloud_type recipe, but with additional sunz_reducer modifier to avoid saturation at the terminator. + Equal to cimss_cloud_type recipe. + references: + EUMETRAIN Quick Guide: https://resources.eumetrain.org/rgb_quick_guides/quick_guides/CloudTypeRGB.pdf + Recipe: https://resources.eumetrain.org/RGBguide/recipes/RGB_recipes.pdf + compositor: !!python/name:satpy.composites.core.GenericCompositor + prerequisites: + - name: nir_13 + modifiers: [effective_solar_pathlength_corrected] + - name: vis_06 + modifiers: [effective_solar_pathlength_corrected] + - name: nir_16 + modifiers: [effective_solar_pathlength_corrected] + standard_name: cimss_cloud_type + + cloud_type_sunz_reduced: + description: > + Equal to cloud_type recipe, but with additional sunz_reducer modifier to avoid saturation at the terminator. references: EUMETRAIN Quick Guide: https://resources.eumetrain.org/rgb_quick_guides/quick_guides/CloudTypeRGB.pdf Recipe: https://resources.eumetrain.org/RGBguide/recipes/RGB_recipes.pdf compositor: !!python/name:satpy.composites.core.GenericCompositor prerequisites: - name: nir_13 - modifiers: [sunz_corrected, sunz_reduced] + modifiers: [effective_solar_pathlength_corrected, sunz_reduced] - name: vis_06 - modifiers: [sunz_corrected, sunz_reduced] + modifiers: [effective_solar_pathlength_corrected, sunz_reduced] - name: nir_16 - modifiers: [sunz_corrected, sunz_reduced] + modifiers: [effective_solar_pathlength_corrected, sunz_reduced] standard_name: cimss_cloud_type day_cloud_type_chmi: description: > - Equal to cimss_cloud_type recipe, but with effective_solar_pathlength_corrected modifier to avoid saturation at the terminator. + Equal to cloud_type recipe, but with alternative enhancement by CHMI to avoid saturation. references: EUMETRAIN Quick Guide: https://eumetrain.org/sites/default/files/2021-05/CloudTypeRGB.pdf EUMETRAIN extended Guide: https://resources.eumetrain.org/data/7/736/index.htm @@ -421,6 +437,20 @@ composites: - night_ir105 cloud_phase: + references: + EUMETRAIN Quick Guide: https://resources.eumetrain.org/rgb_quick_guides/quick_guides/CloudPhaseRGB.pdf + Recipe: https://resources.eumetrain.org/RGBguide/recipes/RGB_recipes.pdf + compositor: !!python/name:satpy.composites.core.GenericCompositor + prerequisites: + - name: nir_16 + modifiers: [effective_solar_pathlength_corrected] + - name: nir_22 + modifiers: [effective_solar_pathlength_corrected] + - name: vis_06 + modifiers: [effective_solar_pathlength_corrected, rayleigh_corrected] + standard_name: cloud_phase + + cloud_phase_sunz_reduced: description: > Equal to cloud_phase recipe, but with additional sunz_reducer modifier to avoid saturation at the terminator. references: @@ -429,16 +459,16 @@ composites: compositor: !!python/name:satpy.composites.core.GenericCompositor prerequisites: - name: nir_16 - modifiers: [sunz_corrected, sunz_reduced] + modifiers: [effective_solar_pathlength_corrected, sunz_reduced] - name: nir_22 - modifiers: [sunz_corrected, sunz_reduced] + modifiers: [effective_solar_pathlength_corrected, sunz_reduced] - name: vis_06 - modifiers: [sunz_corrected, rayleigh_corrected, sunz_reduced] + modifiers: [effective_solar_pathlength_corrected, rayleigh_corrected, sunz_reduced] standard_name: cloud_phase day_cloud_phase_chmi: description: > - Equal to cloud_phase recipe, but with effective_solar_pathlength_corrected modifier to avoid saturation at the terminator. + Equal to cloud_phase recipe, but with alternative enhancement by CHMI to avoid saturation. compositor: !!python/name:satpy.composites.core.GenericCompositor prerequisites: - name: nir_16 @@ -494,9 +524,9 @@ composites: - name: ir_38 modifiers: [nir_reflectance] - name: nir_22 - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] - name: nir_16 - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] fire_temperature_rad: standard_name: fire_temperature_fci_rad @@ -520,9 +550,9 @@ composites: compositor: !!python/name:satpy.composites.core.GenericCompositor prerequisites: - name: vis_08 - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] - name: nir_16 - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] - name: ir_38 modifiers: [nir_reflectance] standard_name: snow @@ -655,7 +685,7 @@ composites: standard_name: vis-crude prerequisites: - name: vis_06 - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] _ir105: compositor: !!python/name:satpy.composites.core.SingleBandCompositor diff --git a/satpy/etc/composites/ghi.yaml b/satpy/etc/composites/ghi.yaml index 5a47f728fd..8aaf7d8269 100644 --- a/satpy/etc/composites/ghi.yaml +++ b/satpy/etc/composites/ghi.yaml @@ -5,11 +5,11 @@ composites: compositor: !!python/name:satpy.composites.resolution.SelfSharpenedRGB prerequisites: - name: C04 - modifiers: [sunz_corrected, rayleigh_corrected] + modifiers: [effective_solar_pathlength_corrected, rayleigh_corrected] - name: C03 - modifiers: [sunz_corrected, rayleigh_corrected] + modifiers: [effective_solar_pathlength_corrected, rayleigh_corrected] - name: C02 - modifiers: [sunz_corrected, rayleigh_corrected] + modifiers: [effective_solar_pathlength_corrected, rayleigh_corrected] standard_name: true_color true_color_nocorr: diff --git a/satpy/etc/composites/insat3d_img.yaml b/satpy/etc/composites/insat3d_img.yaml index 8b80e13414..85a3d3ad54 100644 --- a/satpy/etc/composites/insat3d_img.yaml +++ b/satpy/etc/composites/insat3d_img.yaml @@ -13,9 +13,9 @@ composites: prerequisites: - wavelength: 10.8 - wavelength: 0.64 - modifiers: [ sunz_corrected, rayleigh_corrected ] + modifiers: [ effective_solar_pathlength_corrected, rayleigh_corrected ] - wavelength: 1.6 - modifiers: [ sunz_corrected ] + modifiers: [ effective_solar_pathlength_corrected ] standard_name: cloud_phase_distinction cloud_phase_distinction_raw: diff --git a/satpy/etc/composites/mersi-1.yaml b/satpy/etc/composites/mersi-1.yaml index a3fac0787a..06ea7b35c2 100644 --- a/satpy/etc/composites/mersi-1.yaml +++ b/satpy/etc/composites/mersi-1.yaml @@ -16,6 +16,15 @@ modifiers: sunz_corrected: modifier: !!python/name:satpy.modifiers.SunZenithCorrector + user_warning: > + The reduction of the standard Sun zenith angle correction above 88 degrees will + be removed in satpy v1.0 in order to compute the true reflectance with the + 'sunz_corrected' modifier. To avoid overcorrection at high angles for (RGB) imagery + it's recommended to use the 'effective_solar_pathlength_corrected' modifier instead. + If you still want to keep the current behaviour, please set the 'correction_limit' + parameter to 88.0 and 'max_sza' to 95.0 in a local definition of the modifier. + correction_limit: 88.0 + max_sza: 95.0 prerequisites: - name: solar_zenith_angle @@ -38,36 +47,36 @@ composites: compositor: !!python/name:satpy.composites.core.GenericCompositor prerequisites: - name: '3' - modifiers: [sunz_corrected, rayleigh_corrected] + modifiers: [effective_solar_pathlength_corrected, rayleigh_corrected] - name: '2' - modifiers: [sunz_corrected, rayleigh_corrected] + modifiers: [effective_solar_pathlength_corrected, rayleigh_corrected] - name: '1' - modifiers: [sunz_corrected, rayleigh_corrected] + modifiers: [effective_solar_pathlength_corrected, rayleigh_corrected] standard_name: true_color true_color_uncorr: compositor: !!python/name:satpy.composites.core.GenericCompositor prerequisites: - name: '3' - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] - name: '2' - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] - name: '1' - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] standard_name: true_color natural_color: compositor: !!python/name:satpy.composites.resolution.RatioSharpenedRGB prerequisites: - name: '6' - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] - name: '16' - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] - name: '3' - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] optional_prerequisites: - name: '4' - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] high_resolution_band: green neutral_resolution_band: blue standard_name: natural_color @@ -76,8 +85,8 @@ composites: compositor: !!python/name:satpy.composites.core.GenericCompositor prerequisites: - name: '3' - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] - name: '4' - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] - name: '5' standard_name: overview diff --git a/satpy/etc/composites/mersi-2.yaml b/satpy/etc/composites/mersi-2.yaml index 231e03c161..0aa14d12f8 100644 --- a/satpy/etc/composites/mersi-2.yaml +++ b/satpy/etc/composites/mersi-2.yaml @@ -13,8 +13,18 @@ modifiers: - name: satellite_zenith_angle - name: solar_azimuth_angle - name: solar_zenith_angle + sunz_corrected: modifier: !!python/name:satpy.modifiers.SunZenithCorrector + user_warning: > + The reduction of the standard Sun zenith angle correction above 88 degrees will + be removed in satpy v1.0 in order to compute the true reflectance with the + 'sunz_corrected' modifier. To avoid overcorrection at high angles for (RGB) imagery + it's recommended to use the 'effective_solar_pathlength_corrected' modifier instead. + If you still want to keep the current behaviour, please set the 'correction_limit' + parameter to 88.0 and 'max_sza' to 95.0 in a local definition of the modifier. + correction_limit: 88.0 + max_sza: 95.0 prerequisites: - solar_zenith_angle @@ -54,25 +64,25 @@ composites: compositor: !!python/name:satpy.composites.core.GenericCompositor prerequisites: - name: '3' # 0.65 - modifiers: [sunz_corrected, rayleigh_corrected] + modifiers: [effective_solar_pathlength_corrected, rayleigh_corrected] - name: '2' - modifiers: [sunz_corrected, rayleigh_corrected] + modifiers: [effective_solar_pathlength_corrected, rayleigh_corrected] - name: '1' # 0.47 - modifiers: [sunz_corrected, rayleigh_corrected] + modifiers: [effective_solar_pathlength_corrected, rayleigh_corrected] standard_name: true_color natural_color: compositor: !!python/name:satpy.composites.resolution.RatioSharpenedRGB prerequisites: - name: '6' - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] - name: '15' - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] - name: '3' - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] optional_prerequisites: - name: '4' - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] standard_name: natural_color high_resolution_band: green @@ -80,11 +90,11 @@ composites: compositor: !!python/name:satpy.composites.core.GenericCompositor prerequisites: - name: '6' - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] - name: '15' - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] - name: '12' - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] standard_name: natural_color overview_raw: @@ -99,9 +109,9 @@ composites: compositor: !!python/name:satpy.composites.core.GenericCompositor prerequisites: - name: '12' - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] - name: '15' - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] - name: '24' standard_name: overview @@ -117,7 +127,7 @@ composites: compositor: !!python/name:satpy.composites.core.GenericCompositor prerequisites: - name: '15' - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] - name: '20' modifiers: [nir_reflectance] - name: '24' diff --git a/satpy/etc/composites/mersi-3.yaml b/satpy/etc/composites/mersi-3.yaml index 932e12ddbc..1066ecfcea 100644 --- a/satpy/etc/composites/mersi-3.yaml +++ b/satpy/etc/composites/mersi-3.yaml @@ -13,8 +13,18 @@ modifiers: - name: satellite_zenith_angle - name: solar_azimuth_angle - name: solar_zenith_angle + sunz_corrected: modifier: !!python/name:satpy.modifiers.SunZenithCorrector + user_warning: > + The reduction of the standard Sun zenith angle correction above 88 degrees will + be removed in satpy v1.0 in order to compute the true reflectance with the + 'sunz_corrected' modifier. To avoid overcorrection at high angles for (RGB) imagery + it's recommended to use the 'effective_solar_pathlength_corrected' modifier instead. + If you still want to keep the current behaviour, please set the 'correction_limit' + parameter to 88.0 and 'max_sza' to 95.0 in a local definition of the modifier. + correction_limit: 88.0 + max_sza: 95.0 prerequisites: - solar_zenith_angle @@ -54,25 +64,25 @@ composites: compositor: !!python/name:satpy.composites.core.GenericCompositor prerequisites: - name: '3' # 0.65 - modifiers: [sunz_corrected, rayleigh_corrected] + modifiers: [effective_solar_pathlength_corrected, rayleigh_corrected] - name: '2' - modifiers: [sunz_corrected, rayleigh_corrected] + modifiers: [effective_solar_pathlength_corrected, rayleigh_corrected] - name: '1' # 0.47 - modifiers: [sunz_corrected, rayleigh_corrected] + modifiers: [effective_solar_pathlength_corrected, rayleigh_corrected] standard_name: true_color natural_color: compositor: !!python/name:satpy.composites.resolution.RatioSharpenedRGB prerequisites: - name: '6' - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] - name: '15' - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] - name: '3' - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] optional_prerequisites: - name: '4' - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] standard_name: natural_color high_resolution_band: green @@ -80,11 +90,11 @@ composites: compositor: !!python/name:satpy.composites.core.GenericCompositor prerequisites: - name: '6' - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] - name: '15' - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] - name: '12' - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] standard_name: natural_color overview_raw: @@ -99,9 +109,9 @@ composites: compositor: !!python/name:satpy.composites.core.GenericCompositor prerequisites: - name: '12' - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] - name: '15' - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] - name: '24' standard_name: overview @@ -117,7 +127,7 @@ composites: compositor: !!python/name:satpy.composites.core.GenericCompositor prerequisites: - name: '15' - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] - name: '20' modifiers: [nir_reflectance] - name: '24' diff --git a/satpy/etc/composites/mersi-rm.yaml b/satpy/etc/composites/mersi-rm.yaml index e76b2925fa..4a5e410e55 100644 --- a/satpy/etc/composites/mersi-rm.yaml +++ b/satpy/etc/composites/mersi-rm.yaml @@ -13,8 +13,18 @@ modifiers: - name: satellite_zenith_angle - name: solar_azimuth_angle - name: solar_zenith_angle + sunz_corrected: modifier: !!python/name:satpy.modifiers.SunZenithCorrector + user_warning: > + The reduction of the standard Sun zenith angle correction above 88 degrees will + be removed in satpy v1.0 in order to compute the true reflectance with the + 'sunz_corrected' modifier. To avoid overcorrection at high angles for (RGB) imagery + it's recommended to use the 'effective_solar_pathlength_corrected' modifier instead. + If you still want to keep the current behaviour, please set the 'correction_limit' + parameter to 88.0 and 'max_sza' to 95.0 in a local definition of the modifier. + correction_limit: 88.0 + max_sza: 95.0 prerequisites: - solar_zenith_angle @@ -31,11 +41,11 @@ composites: compositor: !!python/name:satpy.composites.resolution.RatioSharpenedRGB prerequisites: - name: '5' - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] - name: '3' - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] - name: '1' - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] standard_name: natural_color overview_raw: @@ -50,9 +60,9 @@ composites: compositor: !!python/name:satpy.composites.core.GenericCompositor prerequisites: - name: '1' - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] - name: '2' - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] - name: '7' standard_name: overview @@ -68,7 +78,7 @@ composites: compositor: !!python/name:satpy.composites.core.GenericCompositor prerequisites: - name: '2' - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] - name: '7' modifiers: [nir_reflectance] - name: '8' diff --git a/satpy/etc/composites/modis.yaml b/satpy/etc/composites/modis.yaml index aeda364908..45744311da 100644 --- a/satpy/etc/composites/modis.yaml +++ b/satpy/etc/composites/modis.yaml @@ -28,59 +28,59 @@ composites: compositor: !!python/name:satpy.composites.core.GenericCompositor prerequisites: - name: '1' - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] - name: '4' - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] - name: '3' - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] standard_name: true_color true_color: compositor: !!python/name:satpy.composites.core.GenericCompositor prerequisites: - name: '1' - modifiers: [sunz_corrected, rayleigh_corrected] + modifiers: [effective_solar_pathlength_corrected, rayleigh_corrected] - name: '4' - modifiers: [sunz_corrected, rayleigh_corrected] + modifiers: [effective_solar_pathlength_corrected, rayleigh_corrected] - name: '3' - modifiers: [sunz_corrected, rayleigh_corrected] + modifiers: [effective_solar_pathlength_corrected, rayleigh_corrected] standard_name: true_color true_color_thin: compositor: !!python/name:satpy.composites.fill.FillingCompositor prerequisites: - name: '1' - modifiers: [sunz_corrected, rayleigh_corrected] + modifiers: [effective_solar_pathlength_corrected, rayleigh_corrected] - name: '1' - modifiers: [sunz_corrected, rayleigh_corrected] + modifiers: [effective_solar_pathlength_corrected, rayleigh_corrected] - name: '12' - modifiers: [sunz_corrected, rayleigh_corrected] + modifiers: [effective_solar_pathlength_corrected, rayleigh_corrected] - name: '10' - modifiers: [sunz_corrected, rayleigh_corrected] + modifiers: [effective_solar_pathlength_corrected, rayleigh_corrected] standard_name: true_color true_color_crefl: compositor: !!python/name:satpy.composites.core.GenericCompositor prerequisites: - name: '1' - modifiers: [sunz_corrected, rayleigh_corrected_crefl] + modifiers: [effective_solar_pathlength_corrected, rayleigh_corrected_crefl] - name: '4' - modifiers: [sunz_corrected, rayleigh_corrected_crefl] + modifiers: [effective_solar_pathlength_corrected, rayleigh_corrected_crefl] - name: '3' - modifiers: [sunz_corrected, rayleigh_corrected_crefl] + modifiers: [effective_solar_pathlength_corrected, rayleigh_corrected_crefl] standard_name: true_color overview: compositor: !!python/name:satpy.composites.core.GenericCompositor prerequisites: - name: '1' - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] - compositor: !!python/name:satpy.composites.fill.Filler prerequisites: - name: '2' - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] - name: '1' - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] - name: '31' standard_name: overview @@ -90,11 +90,11 @@ composites: - compositor: !!python/name:satpy.composites.fill.Filler prerequisites: - name: '2' - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] - name: '1' - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] - name: '6' - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] - name: '20' modifiers: [nir_reflectance] standard_name: snow @@ -103,15 +103,15 @@ composites: compositor: !!python/name:satpy.composites.core.GenericCompositor prerequisites: - name: '6' - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] - compositor: !!python/name:satpy.composites.fill.Filler prerequisites: - name: '2' - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] - name: '1' - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] - name: '1' - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] standard_name: natural_color day_microphysics: @@ -120,9 +120,9 @@ composites: - compositor: !!python/name:satpy.composites.fill.Filler prerequisites: - name: '2' - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] - name: '1' - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] - name: '20' modifiers: [nir_reflectance] - name: '31' @@ -146,11 +146,11 @@ composites: compositor: !!python/name:satpy.composites.core.GenericCompositor prerequisites: - name: '1' - modifiers: [sunz_corrected, rayleigh_corrected] + modifiers: [effective_solar_pathlength_corrected, rayleigh_corrected] - name: '4' - modifiers: [sunz_corrected, rayleigh_corrected] + modifiers: [effective_solar_pathlength_corrected, rayleigh_corrected] - name: '3' - modifiers: [sunz_corrected, rayleigh_corrected] + modifiers: [effective_solar_pathlength_corrected, rayleigh_corrected] standard_name: ocean_color night_fog: diff --git a/satpy/etc/composites/msu-gs.yaml b/satpy/etc/composites/msu-gs.yaml index 0e45292460..b456a27738 100644 --- a/satpy/etc/composites/msu-gs.yaml +++ b/satpy/etc/composites/msu-gs.yaml @@ -12,8 +12,8 @@ composites: compositor: !!python/name:satpy.composites.core.RGBCompositor prerequisites: - name: 00_9 - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] - name: 00_9 - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] - 10.8 standard_name: overview diff --git a/satpy/etc/composites/msu_gsa.yaml b/satpy/etc/composites/msu_gsa.yaml index 8d924d58d6..1f3edfa987 100644 --- a/satpy/etc/composites/msu_gsa.yaml +++ b/satpy/etc/composites/msu_gsa.yaml @@ -12,20 +12,20 @@ composites: compositor: !!python/name:satpy.composites.core.RGBCompositor prerequisites: - name: C01 - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] - name: C03 - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] - name: C09 standard_name: overview msugsa_color: compositor: !!python/name:satpy.composites.core.RGBCompositor prerequisites: - name: C03 - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] - name: C02 - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] - name: C01 - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] standard_name: natural_color msugsa_color_raw: compositor: !!python/name:satpy.composites.core.RGBCompositor diff --git a/satpy/etc/composites/seviri.yaml b/satpy/etc/composites/seviri.yaml index 4a5b59ee68..69a407bac3 100644 --- a/satpy/etc/composites/seviri.yaml +++ b/satpy/etc/composites/seviri.yaml @@ -3,6 +3,15 @@ sensor_name: visir/seviri modifiers: sunz_corrected: modifier: !!python/name:satpy.modifiers.SunZenithCorrector + user_warning: > + The reduction of the standard Sun zenith angle correction above 88 degrees will + be removed in satpy v1.0 in order to compute the true reflectance with the + 'sunz_corrected' modifier. To avoid overcorrection at high angles for (RGB) imagery + it's recommended to use the 'effective_solar_pathlength_corrected' modifier instead. + If you still want to keep the current behaviour, please set the 'correction_limit' + parameter to 88.0 and 'max_sza' to 95.0 in a local definition of the modifier. + correction_limit: 88.0 + max_sza: 95.0 co2_corrected: modifier: !!python/name:satpy.modifiers.CO2Corrector @@ -137,9 +146,9 @@ composites: compositor: !!python/name:satpy.composites.core.GenericCompositor prerequisites: - name: VIS008 - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] - name: IR_016 - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] - name: IR_039 modifiers: [nir_reflectance] standard_name: snow @@ -148,7 +157,7 @@ composites: compositor: !!python/name:satpy.composites.core.GenericCompositor prerequisites: - name: VIS008 - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] - name: IR_039 modifiers: [nir_reflectance] - IR_108 @@ -158,7 +167,7 @@ composites: compositor: !!python/name:satpy.composites.core.GenericCompositor prerequisites: - name: VIS008 - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] - name: IR_039 modifiers: [nir_reflectance] - IR_108 @@ -176,11 +185,11 @@ composites: compositor: !!python/name:satpy.composites.core.GenericCompositor prerequisites: - name: IR_016 - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] - name: VIS008 - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] - name: VIS006 - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] standard_name: natural_color natural_color_nocorr: @@ -336,11 +345,11 @@ composites: standard_name: realistic_colors prerequisites: - name: VIS006 - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] - name: VIS008 - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] - name: HRV - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] ir_overview: compositor: !!python/name:satpy.composites.core.GenericCompositor @@ -362,9 +371,9 @@ composites: compositor: !!python/name:satpy.composites.core.RGBCompositor prerequisites: - name: VIS006 - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] - name: VIS008 - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] - IR_108 standard_name: overview @@ -387,7 +396,7 @@ composites: standard_name: vis_sharpened_ir prerequisites: - name: 'HRV' - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] - name: colorized_ir_clouds ir_sandwich: @@ -395,7 +404,7 @@ composites: standard_name: ir_sandwich prerequisites: - name: 'HRV' - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] - name: colorized_ir_clouds natural_enh: @@ -406,20 +415,20 @@ composites: ch06_w: 2.2 prerequisites: - name: IR_016 - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] - name: VIS008 - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] - name: VIS006 - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] hrv_clouds: compositor: !!python/name:satpy.composites.core.GenericCompositor standard_name: hrv_clouds prerequisites: - name: HRV - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] - name: HRV - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] - IR_108 hrv_fog: @@ -427,19 +436,19 @@ composites: standard_name: hrv_fog prerequisites: - name: IR_016 - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] - name: HRV - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] - name: HRV - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] hrv_severe_storms: compositor: !!python/name:satpy.composites.core.GenericCompositor prerequisites: - name: HRV - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] - name: HRV - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] - compositor: !!python/name:satpy.composites.arithmetic.DifferenceCompositor prerequisites: - wavelength: 10.8 @@ -463,7 +472,7 @@ composites: - name: hrv_severe_storms # Data used in masking - name: HRV - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] standard_name: hrv_severe_storms_masked natural_with_night_fog: @@ -538,14 +547,14 @@ composites: standard_name: vis06 prerequisites: - name: VIS006 - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] _hrv: compositor: !!python/name:satpy.composites.core.GenericCompositor standard_name: hrv prerequisites: - name: HRV - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] _vis06_filled_hrv: compositor: !!python/name:satpy.composites.fill.Filler diff --git a/satpy/etc/composites/slstr.yaml b/satpy/etc/composites/slstr.yaml index e21be27ba6..5aa786f863 100644 --- a/satpy/etc/composites/slstr.yaml +++ b/satpy/etc/composites/slstr.yaml @@ -31,9 +31,9 @@ composites: compositor: !!python/name:satpy.composites.core.GenericCompositor prerequisites: - name: S2 - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] - name: S3 - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] - S8 standard_name: overview @@ -41,18 +41,18 @@ composites: compositor: !!python/name:satpy.composites.core.GenericCompositor prerequisites: - name: S5 - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] - name: S3 - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] - name: S2 - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] standard_name: natural_color day_microphysics: compositor: !!python/name:satpy.composites.core.GenericCompositor prerequisites: - name: S3 - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] - name: S7 modifiers: [nir_reflectance] - S8 diff --git a/satpy/etc/composites/vii.yaml b/satpy/etc/composites/vii.yaml index 1543ca852f..c93e9b2a53 100644 --- a/satpy/etc/composites/vii.yaml +++ b/satpy/etc/composites/vii.yaml @@ -14,40 +14,40 @@ composites: compositor: !!python/name:satpy.composites.core.GenericCompositor prerequisites: - name: 'vii_668' - modifiers: [ sunz_corrected ] + modifiers: [ effective_solar_pathlength_corrected ] - name: 'vii_555' - modifiers: [ sunz_corrected ] + modifiers: [ effective_solar_pathlength_corrected ] - name: 'vii_443' - modifiers: [ sunz_corrected ] + modifiers: [ effective_solar_pathlength_corrected ] standard_name: true_color true_color: compositor: !!python/name:satpy.composites.core.GenericCompositor prerequisites: - name: 'vii_668' - modifiers: [ sunz_corrected, rayleigh_corrected ] + modifiers: [ effective_solar_pathlength_corrected, rayleigh_corrected ] - name: 'vii_555' - modifiers: [ sunz_corrected, rayleigh_corrected ] + modifiers: [ effective_solar_pathlength_corrected, rayleigh_corrected ] - name: 'vii_443' - modifiers: [ sunz_corrected, rayleigh_corrected ] + modifiers: [ effective_solar_pathlength_corrected, rayleigh_corrected ] standard_name: true_color natural_color: compositor: !!python/name:satpy.composites.core.GenericCompositor prerequisites: - name: 'vii_1630' - modifiers: [ sunz_corrected ] + modifiers: [ effective_solar_pathlength_corrected ] - name: 'vii_865' - modifiers: [ sunz_corrected ] + modifiers: [ effective_solar_pathlength_corrected ] - name: 'vii_668' - modifiers: [ sunz_corrected, rayleigh_corrected ] + modifiers: [ effective_solar_pathlength_corrected, rayleigh_corrected ] standard_name: natural_color day_microphysics: compositor: !!python/name:satpy.composites.core.GenericCompositor prerequisites: - name: 'vii_865' - modifiers: [ sunz_corrected ] + modifiers: [ effective_solar_pathlength_corrected ] - name: 'vii_3740' modifiers: [ nir_reflectance ] - name: 'vii_10690' @@ -57,9 +57,9 @@ composites: compositor: !!python/name:satpy.composites.core.GenericCompositor prerequisites: - name: 'vii_865' - modifiers: [ sunz_corrected ] + modifiers: [ effective_solar_pathlength_corrected ] - name: 'vii_1630' - modifiers: [ sunz_corrected ] + modifiers: [ effective_solar_pathlength_corrected ] - name: 'vii_3740' modifiers: [ nir_reflectance ] standard_name: snow diff --git a/satpy/etc/composites/virr.yaml b/satpy/etc/composites/virr.yaml index 0043048306..994196ec02 100644 --- a/satpy/etc/composites/virr.yaml +++ b/satpy/etc/composites/virr.yaml @@ -3,6 +3,15 @@ sensor_name: visir/virr modifiers: sunz_corrected: modifier: !!python/name:satpy.modifiers.SunZenithCorrector + user_warning: > + The reduction of the standard Sun zenith angle correction above 88 degrees will + be removed in satpy v1.0 in order to compute the true reflectance with the + 'sunz_corrected' modifier. To avoid overcorrection at high angles for (RGB) imagery + it's recommended to use the 'effective_solar_pathlength_corrected' modifier instead. + If you still want to keep the current behaviour, please set the 'correction_limit' + parameter to 88.0 and 'max_sza' to 95.0 in a local definition of the modifier. + correction_limit: 88.0 + max_sza: 95.0 prerequisites: - name: solar_zenith_angle @@ -24,20 +33,20 @@ composites: compositor: !!python/name:satpy.composites.core.GenericCompositor prerequisites: - name: '1' - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] - name: '9' - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] - name: '7' - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] standard_name: true_color true_color: compositor: !!python/name:satpy.composites.core.GenericCompositor prerequisites: - name: '1' - modifiers: [sunz_corrected, rayleigh_corrected] + modifiers: [effective_solar_pathlength_corrected, rayleigh_corrected] - name: '9' - modifiers: [sunz_corrected, rayleigh_corrected] + modifiers: [effective_solar_pathlength_corrected, rayleigh_corrected] - name: '7' - modifiers: [sunz_corrected, rayleigh_corrected] + modifiers: [effective_solar_pathlength_corrected, rayleigh_corrected] standard_name: true_color diff --git a/satpy/etc/composites/visir.yaml b/satpy/etc/composites/visir.yaml index f6c72876f7..38b0c7d28d 100644 --- a/satpy/etc/composites/visir.yaml +++ b/satpy/etc/composites/visir.yaml @@ -188,9 +188,9 @@ composites: compositor: !!python/name:satpy.composites.core.GenericCompositor prerequisites: - wavelength: 0.8 - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] - wavelength: 1.63 - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] - wavelength: 3.9 modifiers: [nir_reflectance] standard_name: snow @@ -199,7 +199,7 @@ composites: compositor: !!python/name:satpy.composites.core.GenericCompositor prerequisites: - wavelength: 0.85 - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] - wavelength: 3.9 modifiers: [nir_reflectance] - 10.8 @@ -253,11 +253,11 @@ composites: compositor: !!python/name:satpy.composites.core.GenericCompositor prerequisites: - wavelength: 1.63 - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] - wavelength: 0.85 - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] - wavelength: 0.635 - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] standard_name: natural_color night_fog: @@ -286,9 +286,9 @@ composites: compositor: !!python/name:satpy.composites.core.GenericCompositor prerequisites: - wavelength: 0.6 - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] - wavelength: 0.8 - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] - 10.8 standard_name: overview @@ -536,11 +536,11 @@ composites: standard_name: natural_enh prerequisites: - wavelength: 1.6 - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] - wavelength: 0.8 - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] - wavelength: 0.6 - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] _night_background: compositor: !!python/name:satpy.composites.aux_data.StaticImageCompositor @@ -566,9 +566,9 @@ composites: prerequisites: - wavelength: 10.3 - wavelength: 0.64 - modifiers: [sunz_corrected, rayleigh_corrected] + modifiers: [effective_solar_pathlength_corrected, rayleigh_corrected] - wavelength: 1.6 - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] standard_name: cloud_phase_distinction cloud_phase_distinction_raw: @@ -590,11 +590,11 @@ composites: compositor: !!python/name:satpy.composites.core.GenericCompositor prerequisites: - wavelength: 1.6 - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] - wavelength: 2.25 - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] - wavelength: 0.67 - modifiers: [sunz_corrected, rayleigh_corrected] + modifiers: [effective_solar_pathlength_corrected, rayleigh_corrected] standard_name: cloud_phase cloud_phase_raw: @@ -616,11 +616,11 @@ composites: compositor: !!python/name:satpy.composites.core.GenericCompositor prerequisites: - wavelength: 1.38 - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] - wavelength: 0.64 - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] - wavelength: 1.61 - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] standard_name: cimss_cloud_type cimss_cloud_type_raw: From 7091e4f492aef4799762fc87e3140e9bc8e47cae Mon Sep 17 00:00:00 2001 From: Johan Strandgren Date: Wed, 27 May 2026 08:06:23 +0000 Subject: [PATCH 30/49] Update documentation wrt. sunz corrections --- doc/source/composites.rst | 8 +++++--- doc/source/dev_guide/custom_reader.rst | 3 ++- doc/source/modifiers.rst | 10 +++++++--- satpy/composites/spectral.py | 16 ++++++++-------- 4 files changed, 22 insertions(+), 15 deletions(-) diff --git a/doc/source/composites.rst b/doc/source/composites.rst index 9f6f1d3d03..001e43fd9e 100644 --- a/doc/source/composites.rst +++ b/doc/source/composites.rst @@ -371,9 +371,9 @@ can be applied in the following way:: compositor: !!python/name:satpy.composites.core.GenericCompositor prerequisites: - name: VIS006 - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] - name: VIS008 - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] - IR_108 standard_name: overview @@ -384,7 +384,9 @@ Here we see two changes: 2. a list of modifiers attached to the dictionary defining the channel The modifier above is a built-in that normalizes the Solar zenith -angle to Sun being directly at the zenith. +angle to Sun being directly at the zenith following the Li and Shibata +(2006, :doi:`10.1175/JAS3682.1`) parameterization that reduces over-correction at high Solar +zenith angles. More examples can be found in Satpy source code directory `satpy/etc/composites `_. diff --git a/doc/source/dev_guide/custom_reader.rst b/doc/source/dev_guide/custom_reader.rst index 0475e07144..363cb9983a 100644 --- a/doc/source/dev_guide/custom_reader.rst +++ b/doc/source/dev_guide/custom_reader.rst @@ -218,7 +218,8 @@ Parameters you can define for example are: when it is returned by the file handler. Only a few of these have been standardized across Satpy, but are based on the names of the modifiers configured in the "composites" YAML files. Examples include - ``sunz_corrected`` or ``rayleigh_corrected``. See the + ``sunz_corrected``, ``effective_solar_pathlength_corrected`` + or ``rayleigh_corrected``. See the `metadata wiki `_ for more information. - file\_type: Name of file type (see above). diff --git a/doc/source/modifiers.rst b/doc/source/modifiers.rst index 4869fe9091..4ed9c82726 100644 --- a/doc/source/modifiers.rst +++ b/doc/source/modifiers.rst @@ -34,11 +34,15 @@ on those modifiers can be found in the linked API documentation. - Description * - ``sunz_corrected`` - :class:`~satpy.modifiers.geometry.SunZenithCorrector` - - Modifies solar channels for the solar zenith angle to provide - smoother images. + - Normalizes solar channels for the solar zenith angle to compute the true reflectance. + For Satpy < v1.0 the correction is reduced at high solar zenith angles (> 88 degrees) + to avoid over-correction and achieve better looking (RGB) imagery. * - ``effective_solar_pathlength_corrected`` - :class:`~satpy.modifiers.geometry.EffectiveSolarPathLengthCorrector` - - Modifies solar channels for atmospheric path length of solar radiation. + - Normalizes solar channels for the solar zenith angle to compute the reflectance, + but parameterized following Li and Shibata (2006, :doi:`10.1175/JAS3682.1`) to avoid + over-correction at high solar zenith angles for better looking (RGB) imagery. This should + not be used for quantitative or scientific applications. * - ``nir_reflectance`` - :class:`~satpy.modifiers.spectral.NIRReflectance` - Calculates reflective part of channels at the edge of solar and diff --git a/satpy/composites/spectral.py b/satpy/composites/spectral.py index e130a6a337..54d3af1d0e 100644 --- a/satpy/composites/spectral.py +++ b/satpy/composites/spectral.py @@ -41,11 +41,11 @@ class SpectralBlender(GenericCompositor): fractions: [0.63, 0.29, 0.08] prerequisites: - name: B02 - modifiers: [sunz_corrected, rayleigh_corrected] + modifiers: [effective_solar_pathlength_corrected, rayleigh_corrected] - name: B03 - modifiers: [sunz_corrected, rayleigh_corrected] + modifiers: [effective_solar_pathlength_corrected, rayleigh_corrected] - name: B04 - modifiers: [sunz_corrected, rayleigh_corrected] + modifiers: [effective_solar_pathlength_corrected, rayleigh_corrected] standard_name: toa_bidirectional_reflectance Other examples can be found in the``ahi.yaml`` composite file in the satpy distribution. @@ -93,9 +93,9 @@ class HybridGreen(SpectralBlender): fraction: 0.15 prerequisites: - name: B02 - modifiers: [sunz_corrected, rayleigh_corrected] + modifiers: [effective_solar_pathlength_corrected, rayleigh_corrected] - name: B04 - modifiers: [sunz_corrected, rayleigh_corrected] + modifiers: [effective_solar_pathlength_corrected, rayleigh_corrected] standard_name: toa_bidirectional_reflectance Other examples can be found in the ``ahi.yaml`` and ``ami.yaml`` composite @@ -126,11 +126,11 @@ class NDVIHybridGreen(SpectralBlender): strength: 1.0 prerequisites: - name: vis_05 - modifiers: [sunz_corrected, rayleigh_corrected] + modifiers: [effective_solar_pathlength_corrected, rayleigh_corrected] - name: vis_06 - modifiers: [sunz_corrected, rayleigh_corrected] + modifiers: [effective_solar_pathlength_corrected, rayleigh_corrected] - name: vis_08 - modifiers: [sunz_corrected ] + modifiers: [effective_solar_pathlength_corrected ] standard_name: toa_bidirectional_reflectance In this example, pixels with NDVI=0.0 will be a weighted average with 15% contribution from the From aa95b4299ca2172ee4f102d08a167357e2efcef6 Mon Sep 17 00:00:00 2001 From: Johan Strandgren Date: Wed, 27 May 2026 12:31:34 +0000 Subject: [PATCH 31/49] Add missing 'method' for SunZenithReducer and make sure to skip when checking for mutually exclusive sunz correction methods --- satpy/modifiers/geometry.py | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/satpy/modifiers/geometry.py b/satpy/modifiers/geometry.py index b505cd6867..9460915864 100644 --- a/satpy/modifiers/geometry.py +++ b/satpy/modifiers/geometry.py @@ -42,13 +42,17 @@ def __call__(self, projectables, **info): """Generate the composite.""" projectables = self.match_data_arrays(list(projectables) + list(info.get("optional_datasets", []))) vis = projectables[0] - for correction in ["sunz_corrected", "effective_solar_pathlength_corrected"]: - if vis.attrs.get(correction) or correction in vis.attrs.get("modifiers"): - logger.debug( - f"Sun zenith angle correction '{correction}' already applied. " - f"Skipping correction '{self.method}'." - ) - return vis + + # Make sure to avoid alternative but mutually exclusive sun zenith angle corrections + sunz_correction_methods = {"sunz_corrected", "effective_solar_pathlength_corrected"} + if self.method in sunz_correction_methods: + for correction in sunz_correction_methods: + if vis.attrs.get(correction) or correction in vis.attrs.get("modifiers"): + logger.debug( + f"Sun zenith angle correction '{correction}' already applied. " + f"Skipping correction '{self.method}'." + ) + return vis logger.debug("Applying Sun zenith angle correction") if not info.get("optional_datasets"): @@ -230,6 +234,7 @@ def __init__(self, correction_limit=80., max_sza=90, strength=1.3, **kwargs): # strength (float): The strength of the non-linear signal reduction. """ + self.method = "sunz_reduced" self.correction_limit = correction_limit self.max_sza = max_sza self.strength = strength From fca4a32f60da3b0ce4dc851d5d0ff98c5312ece0 Mon Sep 17 00:00:00 2001 From: Johan Strandgren Date: Wed, 27 May 2026 13:14:16 +0000 Subject: [PATCH 32/49] Add tests for skipping double sunz correction --- satpy/tests/test_modifiers.py | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/satpy/tests/test_modifiers.py b/satpy/tests/test_modifiers.py index 77d8118e7f..5746592e83 100644 --- a/satpy/tests/test_modifiers.py +++ b/satpy/tests/test_modifiers.py @@ -208,6 +208,18 @@ def test_custom_max_sza_and_correction_limit_with_sza_provided(self, data_arr, s res = call_sunz_modifier(comp, data_arr, sunz_sza, dtype) assert_sunz_modifier_result(res, expected, data_arr, dtype) + @pytest.mark.parametrize("dtype", [np.float32, np.float64]) + @pytest.mark.parametrize("data_arr", [lazy_fixture("sunz_ds1"), lazy_fixture("sunz_ds1_stacked")]) + def test_double_correction(self, data_arr, sunz_sza, dtype): + """Test double sunz correction when SZA is provided.""" + from satpy.modifiers.geometry import SunZenithCorrector + comp = SunZenithCorrector(name="sza_test", modifiers=tuple()) + data_arr = data_arr.copy() + data_arr.attrs["modifiers"] = ("effective_solar_pathlength_corrected",) + expected = data_arr.values + res = call_sunz_modifier(comp, data_arr, sunz_sza, dtype) + assert_sunz_modifier_result(res, expected, data_arr, dtype) + @pytest.mark.parametrize("dtype", [np.float32, np.float64]) @pytest.mark.parametrize("data_arr", [lazy_fixture("sunz_ds1"), lazy_fixture("sunz_ds1_stacked")]) def test_invalid_max_sza_and_correction_limit_with_sza_provided(self, data_arr, sunz_sza, dtype): @@ -272,6 +284,18 @@ def test_with_sza_provided(self, data_arr, sunz_sza, dtype): res = call_sunz_modifier(comp, data_arr, sunz_sza, dtype) assert_sunz_modifier_result(res, expected, data_arr, dtype) + @pytest.mark.parametrize("dtype", [np.float32, np.float64]) + @pytest.mark.parametrize("data_arr", [lazy_fixture("sunz_ds1"), lazy_fixture("sunz_ds1_stacked")]) + def test_double_correction(self, data_arr, sunz_sza, dtype): + """Test double sunz correction when SZA is provided.""" + from satpy.modifiers.geometry import EffectiveSolarPathLengthCorrector + comp = EffectiveSolarPathLengthCorrector(name="sza_test", modifiers=tuple()) + data_arr = data_arr.copy() + data_arr.attrs["modifiers"] = ("sunz_corrected",) + expected = data_arr.values + res = call_sunz_modifier(comp, data_arr, sunz_sza, dtype) + assert_sunz_modifier_result(res, expected, data_arr, dtype) + def test_with_deprecated_correction_limit(self): """Test with deprecated correction_limit.""" from satpy.modifiers.geometry import EffectiveSolarPathLengthCorrector From 64bf5f117a2a7697ffa40506e4fd7a329324d002 Mon Sep 17 00:00:00 2001 From: Johan Strandgren Date: Wed, 27 May 2026 14:17:57 +0000 Subject: [PATCH 33/49] Use `effective_solar_pathlength_corrected` instead of `sunz_corrected` as Sun zenith angle correction modifier for pre-configured Rayleigh correction modifiers. This is done since `sunz_corrected` will eventually be changed to the simple 1/cos(sunz) correction which would not work well for imagery purposes since the reflectance of the red band would become 0 for angles larger than 90 degrees and thus break the rayleigh correction. The reduction over clouds would also not work well close to 90 degrees since also clear-sky becomes very bright at high sun zenith angles. Furthermore, `effective_solar_pathlength_corrected` has been demonstrated to produce smoother and better looking imagery around the terminator compared to the `sunz_corrected` using the default reduction of the correction that has been applied up to now. --- satpy/etc/composites/ahi.yaml | 2 +- satpy/etc/composites/ec_msi.yaml | 2 +- satpy/etc/composites/epic.yaml | 2 +- satpy/etc/composites/mersi-1.yaml | 2 +- satpy/etc/composites/mersi-2.yaml | 2 +- satpy/etc/composites/mersi-3.yaml | 2 +- satpy/etc/composites/mersi-rm.yaml | 2 +- satpy/etc/composites/modis.yaml | 2 +- satpy/etc/composites/olci.yaml | 10 +++++----- satpy/etc/composites/oli_tirs.yaml | 22 +++++++++++----------- satpy/etc/composites/sen2_msi.yaml | 22 +++++++++++----------- satpy/etc/composites/seviri.yaml | 2 +- satpy/etc/composites/sgli.yaml | 10 +++++----- satpy/etc/composites/virr.yaml | 2 +- satpy/etc/composites/visir.yaml | 8 ++++---- satpy/modifiers/atmosphere.py | 2 +- 16 files changed, 47 insertions(+), 47 deletions(-) diff --git a/satpy/etc/composites/ahi.yaml b/satpy/etc/composites/ahi.yaml index f4774ed984..393dee7d32 100644 --- a/satpy/etc/composites/ahi.yaml +++ b/satpy/etc/composites/ahi.yaml @@ -7,7 +7,7 @@ modifiers: aerosol_type: rayleigh_only prerequisites: - name: B03 - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] optional_prerequisites: - satellite_azimuth_angle - satellite_zenith_angle diff --git a/satpy/etc/composites/ec_msi.yaml b/satpy/etc/composites/ec_msi.yaml index 715eb34664..cc82df8f30 100644 --- a/satpy/etc/composites/ec_msi.yaml +++ b/satpy/etc/composites/ec_msi.yaml @@ -20,7 +20,7 @@ modifiers: aerosol_type: rayleigh_only prerequisites: - name: VIS - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] optional_prerequisites: - satellite_azimuth_angle - satellite_zenith_angle diff --git a/satpy/etc/composites/epic.yaml b/satpy/etc/composites/epic.yaml index 98a723d857..38f9bc5646 100644 --- a/satpy/etc/composites/epic.yaml +++ b/satpy/etc/composites/epic.yaml @@ -21,7 +21,7 @@ modifiers: aerosol_type: rayleigh_only prerequisites: - name: B680 - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] optional_prerequisites: - satellite_azimuth_angle - satellite_zenith_angle diff --git a/satpy/etc/composites/mersi-1.yaml b/satpy/etc/composites/mersi-1.yaml index 06ea7b35c2..f2bf8aaa82 100644 --- a/satpy/etc/composites/mersi-1.yaml +++ b/satpy/etc/composites/mersi-1.yaml @@ -7,7 +7,7 @@ modifiers: aerosol_type: rayleigh_only prerequisites: - name: '3' - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] optional_prerequisites: - name: satellite_azimuth_angle - name: satellite_zenith_angle diff --git a/satpy/etc/composites/mersi-2.yaml b/satpy/etc/composites/mersi-2.yaml index 0aa14d12f8..54c196cae3 100644 --- a/satpy/etc/composites/mersi-2.yaml +++ b/satpy/etc/composites/mersi-2.yaml @@ -7,7 +7,7 @@ modifiers: aerosol_type: rayleigh_only prerequisites: - name: '3' - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] optional_prerequisites: - name: satellite_azimuth_angle - name: satellite_zenith_angle diff --git a/satpy/etc/composites/mersi-3.yaml b/satpy/etc/composites/mersi-3.yaml index 1066ecfcea..9fb8f98044 100644 --- a/satpy/etc/composites/mersi-3.yaml +++ b/satpy/etc/composites/mersi-3.yaml @@ -7,7 +7,7 @@ modifiers: aerosol_type: rayleigh_only prerequisites: - name: '3' - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] optional_prerequisites: - name: satellite_azimuth_angle - name: satellite_zenith_angle diff --git a/satpy/etc/composites/mersi-rm.yaml b/satpy/etc/composites/mersi-rm.yaml index 4a5e410e55..78e4a69f93 100644 --- a/satpy/etc/composites/mersi-rm.yaml +++ b/satpy/etc/composites/mersi-rm.yaml @@ -7,7 +7,7 @@ modifiers: aerosol_type: rayleigh_only prerequisites: - name: '1' - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] optional_prerequisites: - name: satellite_azimuth_angle - name: satellite_zenith_angle diff --git a/satpy/etc/composites/modis.yaml b/satpy/etc/composites/modis.yaml index 45744311da..0ba3c2e4d2 100644 --- a/satpy/etc/composites/modis.yaml +++ b/satpy/etc/composites/modis.yaml @@ -17,7 +17,7 @@ modifiers: aerosol_type: rayleigh_only prerequisites: - name: '1' - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] - satellite_azimuth_angle - satellite_zenith_angle - solar_azimuth_angle diff --git a/satpy/etc/composites/olci.yaml b/satpy/etc/composites/olci.yaml index 3b0377b582..0dd29ebc21 100644 --- a/satpy/etc/composites/olci.yaml +++ b/satpy/etc/composites/olci.yaml @@ -9,7 +9,7 @@ modifiers: aerosol_type: rayleigh_only prerequisites: - name: 'Oa08' - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] optional_prerequisites: - satellite_azimuth_angle - satellite_zenith_angle @@ -22,7 +22,7 @@ modifiers: aerosol_type: marine_clean_aerosol prerequisites: - name: 'Oa08' - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] optional_prerequisites: - satellite_azimuth_angle - satellite_zenith_angle @@ -35,7 +35,7 @@ modifiers: aerosol_type: marine_tropical_aerosol prerequisites: - name: 'Oa08' - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] optional_prerequisites: - satellite_azimuth_angle - satellite_zenith_angle @@ -48,7 +48,7 @@ modifiers: aerosol_type: desert_aerosol prerequisites: - name: 'Oa08' - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] optional_prerequisites: - satellite_azimuth_angle - satellite_zenith_angle @@ -61,7 +61,7 @@ modifiers: aerosol_type: continental_average_aerosol prerequisites: - name: 'Oa08' - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] optional_prerequisites: - satellite_azimuth_angle - satellite_zenith_angle diff --git a/satpy/etc/composites/oli_tirs.yaml b/satpy/etc/composites/oli_tirs.yaml index 131e2f6056..c1e0d1fe00 100644 --- a/satpy/etc/composites/oli_tirs.yaml +++ b/satpy/etc/composites/oli_tirs.yaml @@ -7,7 +7,7 @@ modifiers: aerosol_type: rayleigh_only prerequisites: - name: 'B4' - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] optional_prerequisites: - name: satellite_azimuth_angle - name: satellite_zenith_angle @@ -20,7 +20,7 @@ modifiers: aerosol_type: antarctic_aerosol prerequisites: - name: 'B4' - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] optional_prerequisites: - name: satellite_azimuth_angle - name: satellite_zenith_angle @@ -33,7 +33,7 @@ modifiers: aerosol_type: continental_average_aerosol prerequisites: - name: 'B4' - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] optional_prerequisites: - name: satellite_azimuth_angle - name: satellite_zenith_angle @@ -46,7 +46,7 @@ modifiers: aerosol_type: continental_clean_aerosol prerequisites: - name: 'B4' - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] optional_prerequisites: - name: satellite_azimuth_angle - name: satellite_zenith_angle @@ -59,7 +59,7 @@ modifiers: aerosol_type: continental_polluted_aerosol prerequisites: - name: 'B4' - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] optional_prerequisites: - name: satellite_azimuth_angle - name: satellite_zenith_angle @@ -72,7 +72,7 @@ modifiers: aerosol_type: desert_aerosol prerequisites: - name: 'B4' - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] optional_prerequisites: - name: satellite_azimuth_angle - name: satellite_zenith_angle @@ -85,7 +85,7 @@ modifiers: aerosol_type: marine_clean_aerosol prerequisites: - name: 'B4' - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] optional_prerequisites: - name: satellite_azimuth_angle - name: satellite_zenith_angle @@ -98,7 +98,7 @@ modifiers: aerosol_type: marine_polluted_aerosol prerequisites: - name: 'B4' - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] optional_prerequisites: - name: satellite_azimuth_angle - name: satellite_zenith_angle @@ -111,7 +111,7 @@ modifiers: aerosol_type: marine_tropical_aerosol prerequisites: - name: 'B4' - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] optional_prerequisites: - name: satellite_azimuth_angle - name: satellite_zenith_angle @@ -124,7 +124,7 @@ modifiers: aerosol_type: rural_aerosol prerequisites: - name: 'B4' - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] optional_prerequisites: - name: satellite_azimuth_angle - name: satellite_zenith_angle @@ -137,7 +137,7 @@ modifiers: aerosol_type: urban_aerosol prerequisites: - name: 'B4' - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] optional_prerequisites: - name: satellite_azimuth_angle - name: satellite_zenith_angle diff --git a/satpy/etc/composites/sen2_msi.yaml b/satpy/etc/composites/sen2_msi.yaml index c479964536..9b8ce5908c 100644 --- a/satpy/etc/composites/sen2_msi.yaml +++ b/satpy/etc/composites/sen2_msi.yaml @@ -7,7 +7,7 @@ modifiers: aerosol_type: rayleigh_only prerequisites: - name: 'B04' - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] optional_prerequisites: - name: satellite_azimuth_angle - name: satellite_zenith_angle @@ -20,7 +20,7 @@ modifiers: aerosol_type: antarctic_aerosol prerequisites: - name: 'B04' - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] optional_prerequisites: - name: satellite_azimuth_angle - name: satellite_zenith_angle @@ -33,7 +33,7 @@ modifiers: aerosol_type: continental_average_aerosol prerequisites: - name: 'B04' - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] optional_prerequisites: - name: satellite_azimuth_angle - name: satellite_zenith_angle @@ -46,7 +46,7 @@ modifiers: aerosol_type: continental_clean_aerosol prerequisites: - name: 'B04' - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] optional_prerequisites: - name: satellite_azimuth_angle - name: satellite_zenith_angle @@ -59,7 +59,7 @@ modifiers: aerosol_type: continental_polluted_aerosol prerequisites: - name: 'B04' - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] optional_prerequisites: - name: satellite_azimuth_angle - name: satellite_zenith_angle @@ -72,7 +72,7 @@ modifiers: aerosol_type: desert_aerosol prerequisites: - name: 'B04' - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] optional_prerequisites: - name: satellite_azimuth_angle - name: satellite_zenith_angle @@ -85,7 +85,7 @@ modifiers: aerosol_type: marine_clean_aerosol prerequisites: - name: 'B04' - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] optional_prerequisites: - name: satellite_azimuth_angle - name: satellite_zenith_angle @@ -98,7 +98,7 @@ modifiers: aerosol_type: marine_polluted_aerosol prerequisites: - name: 'B04' - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] optional_prerequisites: - name: satellite_azimuth_angle - name: satellite_zenith_angle @@ -111,7 +111,7 @@ modifiers: aerosol_type: marine_tropical_aerosol prerequisites: - name: 'B04' - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] optional_prerequisites: - name: satellite_azimuth_angle - name: satellite_zenith_angle @@ -124,7 +124,7 @@ modifiers: aerosol_type: rural_aerosol prerequisites: - name: 'B04' - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] optional_prerequisites: - name: satellite_azimuth_angle - name: satellite_zenith_angle @@ -137,7 +137,7 @@ modifiers: aerosol_type: urban_aerosol prerequisites: - name: 'B04' - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] optional_prerequisites: - name: satellite_azimuth_angle - name: satellite_zenith_angle diff --git a/satpy/etc/composites/seviri.yaml b/satpy/etc/composites/seviri.yaml index 69a407bac3..276167e1bb 100644 --- a/satpy/etc/composites/seviri.yaml +++ b/satpy/etc/composites/seviri.yaml @@ -26,7 +26,7 @@ modifiers: aerosol_type: rayleigh_only prerequisites: - name: VIS006 - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] optional_prerequisites: - satellite_azimuth_angle - satellite_zenith_angle diff --git a/satpy/etc/composites/sgli.yaml b/satpy/etc/composites/sgli.yaml index 863b902bf3..8085127994 100644 --- a/satpy/etc/composites/sgli.yaml +++ b/satpy/etc/composites/sgli.yaml @@ -9,7 +9,7 @@ modifiers: aerosol_type: rayleigh_only prerequisites: - name: 'VN9' - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] optional_prerequisites: - satellite_azimuth_angle - satellite_zenith_angle @@ -22,7 +22,7 @@ modifiers: aerosol_type: marine_clean_aerosol prerequisites: - name: 'VN8' - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] optional_prerequisites: - satellite_azimuth_angle - satellite_zenith_angle @@ -35,7 +35,7 @@ modifiers: aerosol_type: marine_tropical_aerosol prerequisites: - name: 'VN8' - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] optional_prerequisites: - satellite_azimuth_angle - satellite_zenith_angle @@ -48,7 +48,7 @@ modifiers: aerosol_type: desert_aerosol prerequisites: - name: 'VN8' - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] optional_prerequisites: - satellite_azimuth_angle - satellite_zenith_angle @@ -61,7 +61,7 @@ modifiers: aerosol_type: continental_average_aerosol prerequisites: - name: 'VN8' - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] optional_prerequisites: - satellite_azimuth_angle - satellite_zenith_angle diff --git a/satpy/etc/composites/virr.yaml b/satpy/etc/composites/virr.yaml index 994196ec02..2bac6a5760 100644 --- a/satpy/etc/composites/virr.yaml +++ b/satpy/etc/composites/virr.yaml @@ -21,7 +21,7 @@ modifiers: aerosol_type: rayleigh_only prerequisites: - name: '1' - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] optional_prerequisites: - name: satellite_azimuth_angle - name: satellite_zenith_angle diff --git a/satpy/etc/composites/visir.yaml b/satpy/etc/composites/visir.yaml index 38b0c7d28d..ebbe96956f 100644 --- a/satpy/etc/composites/visir.yaml +++ b/satpy/etc/composites/visir.yaml @@ -64,7 +64,7 @@ modifiers: aerosol_type: rayleigh_only prerequisites: - wavelength: 0.67 - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] optional_prerequisites: - satellite_azimuth_angle - satellite_zenith_angle @@ -77,7 +77,7 @@ modifiers: aerosol_type: marine_tropical_aerosol prerequisites: - wavelength: 0.67 - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] optional_prerequisites: - satellite_azimuth_angle - satellite_zenith_angle @@ -90,7 +90,7 @@ modifiers: aerosol_type: desert_aerosol prerequisites: - wavelength: 0.67 - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] optional_prerequisites: - satellite_azimuth_angle - satellite_zenith_angle @@ -103,7 +103,7 @@ modifiers: aerosol_type: continental_average_aerosol prerequisites: - wavelength: 0.67 - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] optional_prerequisites: - satellite_azimuth_angle - satellite_zenith_angle diff --git a/satpy/modifiers/atmosphere.py b/satpy/modifiers/atmosphere.py index c7144c27ca..03022c31ff 100644 --- a/satpy/modifiers/atmosphere.py +++ b/satpy/modifiers/atmosphere.py @@ -56,7 +56,7 @@ class PSPRayleighReflectance(ModifierBase): reduce_strength: 0.6 prerequisites: - name: B03 - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] optional_prerequisites: - satellite_azimuth_angle - satellite_zenith_angle From 92bf353789c3f601305b55a4275ca266218520fa Mon Sep 17 00:00:00 2001 From: Johan Strandgren Date: Wed, 27 May 2026 14:21:36 +0000 Subject: [PATCH 34/49] Update documentation for Scene --- satpy/scene.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/satpy/scene.py b/satpy/scene.py index 8693cc77b4..cf0e44c34e 100644 --- a/satpy/scene.py +++ b/satpy/scene.py @@ -1452,9 +1452,9 @@ def load(self, wishlist, calibration="*", resolution="*", # noqa: D417 loaded datasets. This is a shortcut similar to calibration, but only represents a single set of modifiers as a tuple. For example, specifying - ``modifiers=('sunz_corrected', 'rayleigh_corrected')`` will + ``modifiers=('effective_solar_pathlength_corrected', 'rayleigh_corrected')`` will attempt to apply both of these modifiers to all loaded - datasets in the specified order ('sunz_corrected' first). + datasets in the specified order ('effective_solar_pathlength_corrected' first). level (list | str): Pressure level to limit available datasets. Pressure should be in hPa or mb. If an altitude is used it should be specified in inverse meters (1/m). The units of this From 05d20e185908b6bfb6c231cb3f8675c0a234fa32 Mon Sep 17 00:00:00 2001 From: Johan Strandgren Date: Thu, 28 May 2026 07:04:43 +0000 Subject: [PATCH 35/49] Update modifiers documentation for solar zenith angle corrections Clarify the normalization method for `sunz_corrected` and `effective_solar_pathlength_corrected`, highlighting the implications of high solar zenith angles on reflectance calculations. --- doc/source/modifiers.rst | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/doc/source/modifiers.rst b/doc/source/modifiers.rst index 4ed9c82726..f3bfab2022 100644 --- a/doc/source/modifiers.rst +++ b/doc/source/modifiers.rst @@ -34,15 +34,16 @@ on those modifiers can be found in the linked API documentation. - Description * - ``sunz_corrected`` - :class:`~satpy.modifiers.geometry.SunZenithCorrector` - - Normalizes solar channels for the solar zenith angle to compute the true reflectance. - For Satpy < v1.0 the correction is reduced at high solar zenith angles (> 88 degrees) - to avoid over-correction and achieve better looking (RGB) imagery. + - Normalizes solar channels for the solar zenith angle using ``1/cos(sza)`` + to compute the true reflectance. This leads to zero reflectance for + solar zenith angles of 90 degrees and above. * - ``effective_solar_pathlength_corrected`` - :class:`~satpy.modifiers.geometry.EffectiveSolarPathLengthCorrector` - Normalizes solar channels for the solar zenith angle to compute the reflectance, but parameterized following Li and Shibata (2006, :doi:`10.1175/JAS3682.1`) to avoid - over-correction at high solar zenith angles for better looking (RGB) imagery. This should - not be used for quantitative or scientific applications. + over-correction at high solar zenith angles for better looking (RGB) imagery, also + extending beyond 90 degrees solar zenith angle. This should not be used for + quantitative or scientific applications. * - ``nir_reflectance`` - :class:`~satpy.modifiers.spectral.NIRReflectance` - Calculates reflective part of channels at the edge of solar and From f2053c028f26add5575019f4a7c9bb63736eed5b Mon Sep 17 00:00:00 2001 From: Johan Strandgren Date: Thu, 28 May 2026 07:12:29 +0000 Subject: [PATCH 36/49] Remove deprecated reduction of pre-defined `sunz_corrected` modifiers --- satpy/etc/composites/ec_msi.yaml | 9 ++++----- satpy/etc/composites/epic.yaml | 9 ++++----- satpy/etc/composites/mersi-1.yaml | 9 ++++----- satpy/etc/composites/mersi-2.yaml | 9 ++++----- satpy/etc/composites/mersi-3.yaml | 9 ++++----- satpy/etc/composites/mersi-rm.yaml | 9 ++++----- satpy/etc/composites/seviri.yaml | 9 ++++----- satpy/etc/composites/virr.yaml | 9 ++++----- satpy/etc/composites/visir.yaml | 9 ++++----- 9 files changed, 36 insertions(+), 45 deletions(-) diff --git a/satpy/etc/composites/ec_msi.yaml b/satpy/etc/composites/ec_msi.yaml index cc82df8f30..2650daf263 100644 --- a/satpy/etc/composites/ec_msi.yaml +++ b/satpy/etc/composites/ec_msi.yaml @@ -4,14 +4,13 @@ sensor_name: visir/ec_msi modifiers: sunz_corrected: user_warning: > - The reduction of the standard Sun zenith angle correction above 88 degrees will - be removed in satpy v1.0 in order to compute the true reflectance with the + The previous default reduction of the standard Sun zenith angle correction above + 88 degrees has been deprecated in order to compute the true reflectance with the 'sunz_corrected' modifier. To avoid overcorrection at high angles for (RGB) imagery it's recommended to use the 'effective_solar_pathlength_corrected' modifier instead. If you still want to keep the current behaviour, please set the 'correction_limit' - parameter to 88.0 and 'max_sza' to 95.0 in a local definition of the modifier. - correction_limit: 88.0 - max_sza: 95.0 + parameter to 88.0 and 'max_sza' to 95.0 in a local definition of the SunZenithCorrector + modifier. modifier: !!python/name:satpy.modifiers.SunZenithCorrector rayleigh_corrected: diff --git a/satpy/etc/composites/epic.yaml b/satpy/etc/composites/epic.yaml index 38f9bc5646..769e181112 100644 --- a/satpy/etc/composites/epic.yaml +++ b/satpy/etc/composites/epic.yaml @@ -4,14 +4,13 @@ modifiers: sunz_corrected: modifier: !!python/name:satpy.modifiers.SunZenithCorrector user_warning: > - The reduction of the standard Sun zenith angle correction above 88 degrees will - be removed in satpy v1.0 in order to compute the true reflectance with the + The previous default reduction of the standard Sun zenith angle correction above + 88 degrees has been deprecated in order to compute the true reflectance with the 'sunz_corrected' modifier. To avoid overcorrection at high angles for (RGB) imagery it's recommended to use the 'effective_solar_pathlength_corrected' modifier instead. If you still want to keep the current behaviour, please set the 'correction_limit' - parameter to 88.0 and 'max_sza' to 95.0 in a local definition of the modifier. - correction_limit: 88.0 - max_sza: 95.0 + parameter to 88.0 and 'max_sza' to 95.0 in a local definition of the SunZenithCorrector + modifier. optional_prerequisites: - solar_zenith_angle diff --git a/satpy/etc/composites/mersi-1.yaml b/satpy/etc/composites/mersi-1.yaml index f2bf8aaa82..34fba394e2 100644 --- a/satpy/etc/composites/mersi-1.yaml +++ b/satpy/etc/composites/mersi-1.yaml @@ -17,14 +17,13 @@ modifiers: sunz_corrected: modifier: !!python/name:satpy.modifiers.SunZenithCorrector user_warning: > - The reduction of the standard Sun zenith angle correction above 88 degrees will - be removed in satpy v1.0 in order to compute the true reflectance with the + The previous default reduction of the standard Sun zenith angle correction above + 88 degrees has been deprecated in order to compute the true reflectance with the 'sunz_corrected' modifier. To avoid overcorrection at high angles for (RGB) imagery it's recommended to use the 'effective_solar_pathlength_corrected' modifier instead. If you still want to keep the current behaviour, please set the 'correction_limit' - parameter to 88.0 and 'max_sza' to 95.0 in a local definition of the modifier. - correction_limit: 88.0 - max_sza: 95.0 + parameter to 88.0 and 'max_sza' to 95.0 in a local definition of the SunZenithCorrector + modifier. prerequisites: - name: solar_zenith_angle diff --git a/satpy/etc/composites/mersi-2.yaml b/satpy/etc/composites/mersi-2.yaml index 54c196cae3..0353a31c38 100644 --- a/satpy/etc/composites/mersi-2.yaml +++ b/satpy/etc/composites/mersi-2.yaml @@ -17,14 +17,13 @@ modifiers: sunz_corrected: modifier: !!python/name:satpy.modifiers.SunZenithCorrector user_warning: > - The reduction of the standard Sun zenith angle correction above 88 degrees will - be removed in satpy v1.0 in order to compute the true reflectance with the + The previous default reduction of the standard Sun zenith angle correction above + 88 degrees has been deprecated in order to compute the true reflectance with the 'sunz_corrected' modifier. To avoid overcorrection at high angles for (RGB) imagery it's recommended to use the 'effective_solar_pathlength_corrected' modifier instead. If you still want to keep the current behaviour, please set the 'correction_limit' - parameter to 88.0 and 'max_sza' to 95.0 in a local definition of the modifier. - correction_limit: 88.0 - max_sza: 95.0 + parameter to 88.0 and 'max_sza' to 95.0 in a local definition of the SunZenithCorrector + modifier. prerequisites: - solar_zenith_angle diff --git a/satpy/etc/composites/mersi-3.yaml b/satpy/etc/composites/mersi-3.yaml index 9fb8f98044..718f4c9617 100644 --- a/satpy/etc/composites/mersi-3.yaml +++ b/satpy/etc/composites/mersi-3.yaml @@ -17,14 +17,13 @@ modifiers: sunz_corrected: modifier: !!python/name:satpy.modifiers.SunZenithCorrector user_warning: > - The reduction of the standard Sun zenith angle correction above 88 degrees will - be removed in satpy v1.0 in order to compute the true reflectance with the + The previous default reduction of the standard Sun zenith angle correction above + 88 degrees has been deprecated in order to compute the true reflectance with the 'sunz_corrected' modifier. To avoid overcorrection at high angles for (RGB) imagery it's recommended to use the 'effective_solar_pathlength_corrected' modifier instead. If you still want to keep the current behaviour, please set the 'correction_limit' - parameter to 88.0 and 'max_sza' to 95.0 in a local definition of the modifier. - correction_limit: 88.0 - max_sza: 95.0 + parameter to 88.0 and 'max_sza' to 95.0 in a local definition of the SunZenithCorrector + modifier. prerequisites: - solar_zenith_angle diff --git a/satpy/etc/composites/mersi-rm.yaml b/satpy/etc/composites/mersi-rm.yaml index 78e4a69f93..218bc90c25 100644 --- a/satpy/etc/composites/mersi-rm.yaml +++ b/satpy/etc/composites/mersi-rm.yaml @@ -17,14 +17,13 @@ modifiers: sunz_corrected: modifier: !!python/name:satpy.modifiers.SunZenithCorrector user_warning: > - The reduction of the standard Sun zenith angle correction above 88 degrees will - be removed in satpy v1.0 in order to compute the true reflectance with the + The previous default reduction of the standard Sun zenith angle correction above + 88 degrees has been deprecated in order to compute the true reflectance with the 'sunz_corrected' modifier. To avoid overcorrection at high angles for (RGB) imagery it's recommended to use the 'effective_solar_pathlength_corrected' modifier instead. If you still want to keep the current behaviour, please set the 'correction_limit' - parameter to 88.0 and 'max_sza' to 95.0 in a local definition of the modifier. - correction_limit: 88.0 - max_sza: 95.0 + parameter to 88.0 and 'max_sza' to 95.0 in a local definition of the SunZenithCorrector + modifier. prerequisites: - solar_zenith_angle diff --git a/satpy/etc/composites/seviri.yaml b/satpy/etc/composites/seviri.yaml index 276167e1bb..68a098a04d 100644 --- a/satpy/etc/composites/seviri.yaml +++ b/satpy/etc/composites/seviri.yaml @@ -4,14 +4,13 @@ modifiers: sunz_corrected: modifier: !!python/name:satpy.modifiers.SunZenithCorrector user_warning: > - The reduction of the standard Sun zenith angle correction above 88 degrees will - be removed in satpy v1.0 in order to compute the true reflectance with the + The previous default reduction of the standard Sun zenith angle correction above + 88 degrees has been deprecated in order to compute the true reflectance with the 'sunz_corrected' modifier. To avoid overcorrection at high angles for (RGB) imagery it's recommended to use the 'effective_solar_pathlength_corrected' modifier instead. If you still want to keep the current behaviour, please set the 'correction_limit' - parameter to 88.0 and 'max_sza' to 95.0 in a local definition of the modifier. - correction_limit: 88.0 - max_sza: 95.0 + parameter to 88.0 and 'max_sza' to 95.0 in a local definition of the SunZenithCorrector + modifier. co2_corrected: modifier: !!python/name:satpy.modifiers.CO2Corrector diff --git a/satpy/etc/composites/virr.yaml b/satpy/etc/composites/virr.yaml index 2bac6a5760..8fa31e911d 100644 --- a/satpy/etc/composites/virr.yaml +++ b/satpy/etc/composites/virr.yaml @@ -4,14 +4,13 @@ modifiers: sunz_corrected: modifier: !!python/name:satpy.modifiers.SunZenithCorrector user_warning: > - The reduction of the standard Sun zenith angle correction above 88 degrees will - be removed in satpy v1.0 in order to compute the true reflectance with the + The previous default reduction of the standard Sun zenith angle correction above + 88 degrees has been deprecated in order to compute the true reflectance with the 'sunz_corrected' modifier. To avoid overcorrection at high angles for (RGB) imagery it's recommended to use the 'effective_solar_pathlength_corrected' modifier instead. If you still want to keep the current behaviour, please set the 'correction_limit' - parameter to 88.0 and 'max_sza' to 95.0 in a local definition of the modifier. - correction_limit: 88.0 - max_sza: 95.0 + parameter to 88.0 and 'max_sza' to 95.0 in a local definition of the SunZenithCorrector + modifier. prerequisites: - name: solar_zenith_angle diff --git a/satpy/etc/composites/visir.yaml b/satpy/etc/composites/visir.yaml index ebbe96956f..cc1e134fbd 100644 --- a/satpy/etc/composites/visir.yaml +++ b/satpy/etc/composites/visir.yaml @@ -9,14 +9,13 @@ modifiers: sunz_corrected: modifier: !!python/name:satpy.modifiers.SunZenithCorrector user_warning: > - The reduction of the standard Sun zenith angle correction above 88 degrees will - be removed in satpy v1.0 in order to compute the true reflectance with the + The previous default reduction of the standard Sun zenith angle correction above + 88 degrees has been deprecated in order to compute the true reflectance with the 'sunz_corrected' modifier. To avoid overcorrection at high angles for (RGB) imagery it's recommended to use the 'effective_solar_pathlength_corrected' modifier instead. If you still want to keep the current behaviour, please set the 'correction_limit' - parameter to 88.0 and 'max_sza' to 95.0 in a local definition of the modifier. - correction_limit: 88.0 - max_sza: 95.0 + parameter to 88.0 and 'max_sza' to 95.0 in a local definition of the SunZenithCorrector + modifier. optional_prerequisites: - solar_zenith_angle From db357c01d4fed7c5abe8024133615e5dd047b7b6 Mon Sep 17 00:00:00 2001 From: Johan Strandgren Date: Thu, 28 May 2026 09:14:00 +0000 Subject: [PATCH 37/49] Use EffectiveSolarPathLengthCorrector modifier but named sunz_corrected for VIIRS data in order to be compatible with VIIRS SDR data. --- satpy/etc/composites/viirs.yaml | 29 +++++++++++------------------ 1 file changed, 11 insertions(+), 18 deletions(-) diff --git a/satpy/etc/composites/viirs.yaml b/satpy/etc/composites/viirs.yaml index 03f8c750b0..ca98117756 100644 --- a/satpy/etc/composites/viirs.yaml +++ b/satpy/etc/composites/viirs.yaml @@ -101,30 +101,23 @@ modifiers: - name: solar_zenith_angle resolution: 742 - # Although `effective_solar_pathlength_corrected` is now the recommended solar zenith - # angle correction modifier for (RGB) imagery (agreed during RGB workshop in - # Norrkoeping 2025), we need to keep using `sunz_corrected` (SunZenithCorrector) - # for VIIRS data given that the SDR data come with the `1/cos(sunz)` normalization - # already applied, whereas the L1B data do not. Consequently, the `sunz_corrected` - # modifier is attached to the dataset when loading VIIRS SDR data. Hence, if we would - # use the `effective_solar_pathlength_corrected` modifier in the recipes defined below, - # we would not be able to load composites using VIIRS SDR data since satpy would not - # be able to find the "base" dataset with no modifiers applied, but only the one with - # the `sunz_corrected` modifier applied. - # Since the default behaviour of `sunz_corrected` has changed to compute the true - # reflectance, we explicitly define `correction_limit` in order to avoid over-correction - # at very high sun zenith angles. + # Although we use the `EffectiveSolarPathLengthCorrector` for VIIRS data, we keep the + # name `sunz_corrected`. This is needed in order to be able to load composites and + # reject further corrections if loading VIIRS SDR data for which the standard + # `1/cos(sunz)` normalization is already applied, with the `sunz_modifier` attached + # to the dataset during reading. If we were to use the `effective_solar_pathlength_corrected` + # name instead, satpy would not be able to find the "base" dataset with no modifiers applied, + # but only the one with the `sunz_corrected` modifier applied, hence leading to failure + # when loading composites using VIIRS SDR data. sunz_corrected: - modifier: !!python/name:satpy.modifiers.SunZenithCorrector - correction_limit: 86 + modifier: !!python/name:satpy.modifiers.EffectiveSolarPathLengthCorrector prerequisites: - name: solar_zenith_angle resolution: 742 - # See comment above concerning the use of `SunZenithCorrector` for VIIRS data. + # See comment above concerning the use of the `sunz_corrected_iband` name for VIIRS data. sunz_corrected_iband: - modifier: !!python/name:satpy.modifiers.SunZenithCorrector - correction_limit: 86 + modifier: !!python/name:satpy.modifiers.EffectiveSolarPathLengthCorrector prerequisites: - name: solar_zenith_angle resolution: 371 From 51fb5c233fded7a9264c5be5b84f0fc5d172b857 Mon Sep 17 00:00:00 2001 From: Johan Strandgren Date: Thu, 28 May 2026 12:33:25 +0000 Subject: [PATCH 38/49] Fix descriptions of FCI true_color_sunz_reduced recipes. Remove FCI cloud_type_sunz_reduced and cloud_phase_sunz_reduced recipes given clear benefit of more data being retained without it, without obvious artefacts, as well as alternative tuning by CHMI to reduce saturation. --- satpy/etc/composites/fci.yaml | 38 +++-------------------------------- 1 file changed, 3 insertions(+), 35 deletions(-) diff --git a/satpy/etc/composites/fci.yaml b/satpy/etc/composites/fci.yaml index 57c8aedb10..ae3238fb98 100644 --- a/satpy/etc/composites/fci.yaml +++ b/satpy/etc/composites/fci.yaml @@ -74,7 +74,7 @@ composites: standard_name: toa_bidirectional_reflectance ndvi_hybrid_green_sunz_reduced: - description: Same as ndvi_hybrid_green, but without Sun-zenith reduction + description: Same as ndvi_hybrid_green, but with Sun-zenith reduction for smoother transition to space compositor: !!python/name:satpy.composites.spectral.NDVIHybridGreen limits: [0.15, 0.05] strength: 3.0 @@ -117,8 +117,8 @@ composites: true_color_sunz_reduced: compositor: !!python/name:satpy.composites.resolution.SelfSharpenedRGB description: > - Same as true_color, but without Sun-zenith reduction. For users that want to maintain as much data as possible - close to the terminator, at cost of some artefacts (bright limb and reddish clouds) (see issue #2643). + Same as true_color, but with Sun-zenith reduction to reduce some artefacts (bright + limb and reddish clouds) (see issue #2643). prerequisites: - name: vis_06 modifiers: [effective_solar_pathlength_corrected, rayleigh_corrected, sunz_reduced] @@ -393,22 +393,6 @@ composites: modifiers: [effective_solar_pathlength_corrected] standard_name: cimss_cloud_type - cloud_type_sunz_reduced: - description: > - Equal to cloud_type recipe, but with additional sunz_reducer modifier to avoid saturation at the terminator. - references: - EUMETRAIN Quick Guide: https://resources.eumetrain.org/rgb_quick_guides/quick_guides/CloudTypeRGB.pdf - Recipe: https://resources.eumetrain.org/RGBguide/recipes/RGB_recipes.pdf - compositor: !!python/name:satpy.composites.core.GenericCompositor - prerequisites: - - name: nir_13 - modifiers: [effective_solar_pathlength_corrected, sunz_reduced] - - name: vis_06 - modifiers: [effective_solar_pathlength_corrected, sunz_reduced] - - name: nir_16 - modifiers: [effective_solar_pathlength_corrected, sunz_reduced] - standard_name: cimss_cloud_type - day_cloud_type_chmi: description: > Equal to cloud_type recipe, but with alternative enhancement by CHMI to avoid saturation. @@ -450,22 +434,6 @@ composites: modifiers: [effective_solar_pathlength_corrected, rayleigh_corrected] standard_name: cloud_phase - cloud_phase_sunz_reduced: - description: > - Equal to cloud_phase recipe, but with additional sunz_reducer modifier to avoid saturation at the terminator. - references: - EUMETRAIN Quick Guide: https://resources.eumetrain.org/rgb_quick_guides/quick_guides/CloudPhaseRGB.pdf - Recipe: https://resources.eumetrain.org/RGBguide/recipes/RGB_recipes.pdf - compositor: !!python/name:satpy.composites.core.GenericCompositor - prerequisites: - - name: nir_16 - modifiers: [effective_solar_pathlength_corrected, sunz_reduced] - - name: nir_22 - modifiers: [effective_solar_pathlength_corrected, sunz_reduced] - - name: vis_06 - modifiers: [effective_solar_pathlength_corrected, rayleigh_corrected, sunz_reduced] - standard_name: cloud_phase - day_cloud_phase_chmi: description: > Equal to cloud_phase recipe, but with alternative enhancement by CHMI to avoid saturation. From 6d9ce8a7458d58296476479ca1ffab0f08835932 Mon Sep 17 00:00:00 2001 From: Johan Strandgren <42137969+strandgren@users.noreply.github.com> Date: Thu, 28 May 2026 15:14:17 +0200 Subject: [PATCH 39/49] Update doc/source/modifiers.rst Co-authored-by: Andrea Meraner <49722768+ameraner@users.noreply.github.com> --- doc/source/modifiers.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/source/modifiers.rst b/doc/source/modifiers.rst index f3bfab2022..c41961fc9e 100644 --- a/doc/source/modifiers.rst +++ b/doc/source/modifiers.rst @@ -43,7 +43,7 @@ on those modifiers can be found in the linked API documentation. but parameterized following Li and Shibata (2006, :doi:`10.1175/JAS3682.1`) to avoid over-correction at high solar zenith angles for better looking (RGB) imagery, also extending beyond 90 degrees solar zenith angle. This should not be used for - quantitative or scientific applications. + quantitative scientific applications beyond the visual usage of imagery. * - ``nir_reflectance`` - :class:`~satpy.modifiers.spectral.NIRReflectance` - Calculates reflective part of channels at the edge of solar and From 292ab5457f40e2fc899e98f29ce7a8febd750829 Mon Sep 17 00:00:00 2001 From: Johan Strandgren Date: Thu, 28 May 2026 13:17:08 +0000 Subject: [PATCH 40/49] Clarify docstring wrt. scientific use. --- satpy/modifiers/angles.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/satpy/modifiers/angles.py b/satpy/modifiers/angles.py index 16990ce8c6..07936c70d7 100644 --- a/satpy/modifiers/angles.py +++ b/satpy/modifiers/angles.py @@ -625,8 +625,9 @@ def atmospheric_path_length_correction(data: xr.DataArray, This function uses the correction method proposed by Li and Shibata (2006): https://doi.org/10.1175/JAS3682.1 and is recommended for computing the reflectance for (RGB) imagery to avoid over-correction at high solar zenith angles. It - shoudl not be used for quantitative/scientific applications for which the standard cosine - correction is more appropriate (see SunZenithCorrector for more details on how to use it). + should not be used for quantitative or scientific applications beyond the visual usage of + imagery for which the standard cosine correction is more appropriate (see SunZenithCorrector + for more details on how to use it). Both ``data`` and ``cos_zen`` should be 2D arrays of the same shape. From ee8161bbbfb2b1b902fca6b3c1ee193dcab23864 Mon Sep 17 00:00:00 2001 From: Johan Strandgren Date: Wed, 3 Jun 2026 12:25:11 +0000 Subject: [PATCH 41/49] Revert "Remove deprecated reduction of pre-defined `sunz_corrected` modifiers" This reverts commit f2053c028f26add5575019f4a7c9bb63736eed5b. --- satpy/etc/composites/ec_msi.yaml | 9 +++++---- satpy/etc/composites/epic.yaml | 9 +++++---- satpy/etc/composites/mersi-1.yaml | 9 +++++---- satpy/etc/composites/mersi-2.yaml | 9 +++++---- satpy/etc/composites/mersi-3.yaml | 9 +++++---- satpy/etc/composites/mersi-rm.yaml | 9 +++++---- satpy/etc/composites/seviri.yaml | 9 +++++---- satpy/etc/composites/virr.yaml | 9 +++++---- satpy/etc/composites/visir.yaml | 9 +++++---- 9 files changed, 45 insertions(+), 36 deletions(-) diff --git a/satpy/etc/composites/ec_msi.yaml b/satpy/etc/composites/ec_msi.yaml index 2650daf263..cc82df8f30 100644 --- a/satpy/etc/composites/ec_msi.yaml +++ b/satpy/etc/composites/ec_msi.yaml @@ -4,13 +4,14 @@ sensor_name: visir/ec_msi modifiers: sunz_corrected: user_warning: > - The previous default reduction of the standard Sun zenith angle correction above - 88 degrees has been deprecated in order to compute the true reflectance with the + The reduction of the standard Sun zenith angle correction above 88 degrees will + be removed in satpy v1.0 in order to compute the true reflectance with the 'sunz_corrected' modifier. To avoid overcorrection at high angles for (RGB) imagery it's recommended to use the 'effective_solar_pathlength_corrected' modifier instead. If you still want to keep the current behaviour, please set the 'correction_limit' - parameter to 88.0 and 'max_sza' to 95.0 in a local definition of the SunZenithCorrector - modifier. + parameter to 88.0 and 'max_sza' to 95.0 in a local definition of the modifier. + correction_limit: 88.0 + max_sza: 95.0 modifier: !!python/name:satpy.modifiers.SunZenithCorrector rayleigh_corrected: diff --git a/satpy/etc/composites/epic.yaml b/satpy/etc/composites/epic.yaml index 769e181112..38f9bc5646 100644 --- a/satpy/etc/composites/epic.yaml +++ b/satpy/etc/composites/epic.yaml @@ -4,13 +4,14 @@ modifiers: sunz_corrected: modifier: !!python/name:satpy.modifiers.SunZenithCorrector user_warning: > - The previous default reduction of the standard Sun zenith angle correction above - 88 degrees has been deprecated in order to compute the true reflectance with the + The reduction of the standard Sun zenith angle correction above 88 degrees will + be removed in satpy v1.0 in order to compute the true reflectance with the 'sunz_corrected' modifier. To avoid overcorrection at high angles for (RGB) imagery it's recommended to use the 'effective_solar_pathlength_corrected' modifier instead. If you still want to keep the current behaviour, please set the 'correction_limit' - parameter to 88.0 and 'max_sza' to 95.0 in a local definition of the SunZenithCorrector - modifier. + parameter to 88.0 and 'max_sza' to 95.0 in a local definition of the modifier. + correction_limit: 88.0 + max_sza: 95.0 optional_prerequisites: - solar_zenith_angle diff --git a/satpy/etc/composites/mersi-1.yaml b/satpy/etc/composites/mersi-1.yaml index 34fba394e2..f2bf8aaa82 100644 --- a/satpy/etc/composites/mersi-1.yaml +++ b/satpy/etc/composites/mersi-1.yaml @@ -17,13 +17,14 @@ modifiers: sunz_corrected: modifier: !!python/name:satpy.modifiers.SunZenithCorrector user_warning: > - The previous default reduction of the standard Sun zenith angle correction above - 88 degrees has been deprecated in order to compute the true reflectance with the + The reduction of the standard Sun zenith angle correction above 88 degrees will + be removed in satpy v1.0 in order to compute the true reflectance with the 'sunz_corrected' modifier. To avoid overcorrection at high angles for (RGB) imagery it's recommended to use the 'effective_solar_pathlength_corrected' modifier instead. If you still want to keep the current behaviour, please set the 'correction_limit' - parameter to 88.0 and 'max_sza' to 95.0 in a local definition of the SunZenithCorrector - modifier. + parameter to 88.0 and 'max_sza' to 95.0 in a local definition of the modifier. + correction_limit: 88.0 + max_sza: 95.0 prerequisites: - name: solar_zenith_angle diff --git a/satpy/etc/composites/mersi-2.yaml b/satpy/etc/composites/mersi-2.yaml index 0353a31c38..54c196cae3 100644 --- a/satpy/etc/composites/mersi-2.yaml +++ b/satpy/etc/composites/mersi-2.yaml @@ -17,13 +17,14 @@ modifiers: sunz_corrected: modifier: !!python/name:satpy.modifiers.SunZenithCorrector user_warning: > - The previous default reduction of the standard Sun zenith angle correction above - 88 degrees has been deprecated in order to compute the true reflectance with the + The reduction of the standard Sun zenith angle correction above 88 degrees will + be removed in satpy v1.0 in order to compute the true reflectance with the 'sunz_corrected' modifier. To avoid overcorrection at high angles for (RGB) imagery it's recommended to use the 'effective_solar_pathlength_corrected' modifier instead. If you still want to keep the current behaviour, please set the 'correction_limit' - parameter to 88.0 and 'max_sza' to 95.0 in a local definition of the SunZenithCorrector - modifier. + parameter to 88.0 and 'max_sza' to 95.0 in a local definition of the modifier. + correction_limit: 88.0 + max_sza: 95.0 prerequisites: - solar_zenith_angle diff --git a/satpy/etc/composites/mersi-3.yaml b/satpy/etc/composites/mersi-3.yaml index 718f4c9617..9fb8f98044 100644 --- a/satpy/etc/composites/mersi-3.yaml +++ b/satpy/etc/composites/mersi-3.yaml @@ -17,13 +17,14 @@ modifiers: sunz_corrected: modifier: !!python/name:satpy.modifiers.SunZenithCorrector user_warning: > - The previous default reduction of the standard Sun zenith angle correction above - 88 degrees has been deprecated in order to compute the true reflectance with the + The reduction of the standard Sun zenith angle correction above 88 degrees will + be removed in satpy v1.0 in order to compute the true reflectance with the 'sunz_corrected' modifier. To avoid overcorrection at high angles for (RGB) imagery it's recommended to use the 'effective_solar_pathlength_corrected' modifier instead. If you still want to keep the current behaviour, please set the 'correction_limit' - parameter to 88.0 and 'max_sza' to 95.0 in a local definition of the SunZenithCorrector - modifier. + parameter to 88.0 and 'max_sza' to 95.0 in a local definition of the modifier. + correction_limit: 88.0 + max_sza: 95.0 prerequisites: - solar_zenith_angle diff --git a/satpy/etc/composites/mersi-rm.yaml b/satpy/etc/composites/mersi-rm.yaml index 218bc90c25..78e4a69f93 100644 --- a/satpy/etc/composites/mersi-rm.yaml +++ b/satpy/etc/composites/mersi-rm.yaml @@ -17,13 +17,14 @@ modifiers: sunz_corrected: modifier: !!python/name:satpy.modifiers.SunZenithCorrector user_warning: > - The previous default reduction of the standard Sun zenith angle correction above - 88 degrees has been deprecated in order to compute the true reflectance with the + The reduction of the standard Sun zenith angle correction above 88 degrees will + be removed in satpy v1.0 in order to compute the true reflectance with the 'sunz_corrected' modifier. To avoid overcorrection at high angles for (RGB) imagery it's recommended to use the 'effective_solar_pathlength_corrected' modifier instead. If you still want to keep the current behaviour, please set the 'correction_limit' - parameter to 88.0 and 'max_sza' to 95.0 in a local definition of the SunZenithCorrector - modifier. + parameter to 88.0 and 'max_sza' to 95.0 in a local definition of the modifier. + correction_limit: 88.0 + max_sza: 95.0 prerequisites: - solar_zenith_angle diff --git a/satpy/etc/composites/seviri.yaml b/satpy/etc/composites/seviri.yaml index 68a098a04d..276167e1bb 100644 --- a/satpy/etc/composites/seviri.yaml +++ b/satpy/etc/composites/seviri.yaml @@ -4,13 +4,14 @@ modifiers: sunz_corrected: modifier: !!python/name:satpy.modifiers.SunZenithCorrector user_warning: > - The previous default reduction of the standard Sun zenith angle correction above - 88 degrees has been deprecated in order to compute the true reflectance with the + The reduction of the standard Sun zenith angle correction above 88 degrees will + be removed in satpy v1.0 in order to compute the true reflectance with the 'sunz_corrected' modifier. To avoid overcorrection at high angles for (RGB) imagery it's recommended to use the 'effective_solar_pathlength_corrected' modifier instead. If you still want to keep the current behaviour, please set the 'correction_limit' - parameter to 88.0 and 'max_sza' to 95.0 in a local definition of the SunZenithCorrector - modifier. + parameter to 88.0 and 'max_sza' to 95.0 in a local definition of the modifier. + correction_limit: 88.0 + max_sza: 95.0 co2_corrected: modifier: !!python/name:satpy.modifiers.CO2Corrector diff --git a/satpy/etc/composites/virr.yaml b/satpy/etc/composites/virr.yaml index 8fa31e911d..2bac6a5760 100644 --- a/satpy/etc/composites/virr.yaml +++ b/satpy/etc/composites/virr.yaml @@ -4,13 +4,14 @@ modifiers: sunz_corrected: modifier: !!python/name:satpy.modifiers.SunZenithCorrector user_warning: > - The previous default reduction of the standard Sun zenith angle correction above - 88 degrees has been deprecated in order to compute the true reflectance with the + The reduction of the standard Sun zenith angle correction above 88 degrees will + be removed in satpy v1.0 in order to compute the true reflectance with the 'sunz_corrected' modifier. To avoid overcorrection at high angles for (RGB) imagery it's recommended to use the 'effective_solar_pathlength_corrected' modifier instead. If you still want to keep the current behaviour, please set the 'correction_limit' - parameter to 88.0 and 'max_sza' to 95.0 in a local definition of the SunZenithCorrector - modifier. + parameter to 88.0 and 'max_sza' to 95.0 in a local definition of the modifier. + correction_limit: 88.0 + max_sza: 95.0 prerequisites: - name: solar_zenith_angle diff --git a/satpy/etc/composites/visir.yaml b/satpy/etc/composites/visir.yaml index cc1e134fbd..ebbe96956f 100644 --- a/satpy/etc/composites/visir.yaml +++ b/satpy/etc/composites/visir.yaml @@ -9,13 +9,14 @@ modifiers: sunz_corrected: modifier: !!python/name:satpy.modifiers.SunZenithCorrector user_warning: > - The previous default reduction of the standard Sun zenith angle correction above - 88 degrees has been deprecated in order to compute the true reflectance with the + The reduction of the standard Sun zenith angle correction above 88 degrees will + be removed in satpy v1.0 in order to compute the true reflectance with the 'sunz_corrected' modifier. To avoid overcorrection at high angles for (RGB) imagery it's recommended to use the 'effective_solar_pathlength_corrected' modifier instead. If you still want to keep the current behaviour, please set the 'correction_limit' - parameter to 88.0 and 'max_sza' to 95.0 in a local definition of the SunZenithCorrector - modifier. + parameter to 88.0 and 'max_sza' to 95.0 in a local definition of the modifier. + correction_limit: 88.0 + max_sza: 95.0 optional_prerequisites: - solar_zenith_angle From 1e20f11f4c45552c60e5ebcc8db6ccfe13988088 Mon Sep 17 00:00:00 2001 From: Johan Strandgren Date: Wed, 3 Jun 2026 12:39:06 +0000 Subject: [PATCH 42/49] Change VIIRS composites to use the name effective_solar_pathlength_corrected for sun zenith angle modifier --- satpy/etc/composites/viirs.yaml | 157 +++++++++++++++----------------- 1 file changed, 74 insertions(+), 83 deletions(-) diff --git a/satpy/etc/composites/viirs.yaml b/satpy/etc/composites/viirs.yaml index ca98117756..2b475d1278 100644 --- a/satpy/etc/composites/viirs.yaml +++ b/satpy/etc/composites/viirs.yaml @@ -36,7 +36,7 @@ modifiers: prerequisites: - name: I01 resolution: 371 - modifiers: [sunz_corrected_iband] + modifiers: [effective_solar_pathlength_corrected_iband] optional_prerequisites: - name: satellite_azimuth_angle resolution: 371 @@ -54,7 +54,7 @@ modifiers: prerequisites: - name: M05 resolution: 742 - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] optional_prerequisites: - name: satellite_azimuth_angle resolution: 742 @@ -72,7 +72,7 @@ modifiers: prerequisites: - name: M05 resolution: 742 - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] optional_prerequisites: - name: satellite_azimuth_angle resolution: 742 @@ -90,7 +90,7 @@ modifiers: prerequisites: - name: M05 resolution: 742 - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] optional_prerequisites: - name: satellite_azimuth_angle resolution: 742 @@ -101,22 +101,13 @@ modifiers: - name: solar_zenith_angle resolution: 742 - # Although we use the `EffectiveSolarPathLengthCorrector` for VIIRS data, we keep the - # name `sunz_corrected`. This is needed in order to be able to load composites and - # reject further corrections if loading VIIRS SDR data for which the standard - # `1/cos(sunz)` normalization is already applied, with the `sunz_modifier` attached - # to the dataset during reading. If we were to use the `effective_solar_pathlength_corrected` - # name instead, satpy would not be able to find the "base" dataset with no modifiers applied, - # but only the one with the `sunz_corrected` modifier applied, hence leading to failure - # when loading composites using VIIRS SDR data. - sunz_corrected: + effective_solar_pathlength_corrected: modifier: !!python/name:satpy.modifiers.EffectiveSolarPathLengthCorrector prerequisites: - name: solar_zenith_angle resolution: 742 - # See comment above concerning the use of the `sunz_corrected_iband` name for VIIRS data. - sunz_corrected_iband: + effective_solar_pathlength_corrected_iband: modifier: !!python/name:satpy.modifiers.EffectiveSolarPathLengthCorrector prerequisites: - name: solar_zenith_angle @@ -160,14 +151,14 @@ composites: compositor: !!python/name:satpy.composites.resolution.RatioSharpenedRGB prerequisites: - name: M05 - modifiers: [sunz_corrected, rayleigh_corrected] + modifiers: [effective_solar_pathlength_corrected, rayleigh_corrected] - name: M04 - modifiers: [sunz_corrected, rayleigh_corrected] + modifiers: [effective_solar_pathlength_corrected, rayleigh_corrected] - name: M03 - modifiers: [sunz_corrected, rayleigh_corrected] + modifiers: [effective_solar_pathlength_corrected, rayleigh_corrected] optional_prerequisites: - name: I01 - modifiers: [sunz_corrected_iband, rayleigh_corrected_iband] + modifiers: [effective_solar_pathlength_corrected_iband, rayleigh_corrected_iband] standard_name: true_color high_resolution_band: red @@ -175,14 +166,14 @@ composites: compositor: !!python/name:satpy.composites.resolution.RatioSharpenedRGB prerequisites: - name: M05 - modifiers: [sunz_corrected, rayleigh_corrected_crefl] + modifiers: [effective_solar_pathlength_corrected, rayleigh_corrected_crefl] - name: M04 - modifiers: [sunz_corrected, rayleigh_corrected_crefl] + modifiers: [effective_solar_pathlength_corrected, rayleigh_corrected_crefl] - name: M03 - modifiers: [sunz_corrected, rayleigh_corrected_crefl] + modifiers: [effective_solar_pathlength_corrected, rayleigh_corrected_crefl] optional_prerequisites: - name: I01 - modifiers: [sunz_corrected_iband, rayleigh_corrected_crefl_iband] + modifiers: [effective_solar_pathlength_corrected_iband, rayleigh_corrected_crefl_iband] standard_name: true_color high_resolution_band: red @@ -190,58 +181,58 @@ composites: compositor: !!python/name:satpy.composites.core.GenericCompositor prerequisites: - name: M05 - modifiers: [sunz_corrected, rayleigh_corrected] + modifiers: [effective_solar_pathlength_corrected, rayleigh_corrected] - name: M04 - modifiers: [sunz_corrected, rayleigh_corrected] + modifiers: [effective_solar_pathlength_corrected, rayleigh_corrected] - name: M03 - modifiers: [sunz_corrected, rayleigh_corrected] + modifiers: [effective_solar_pathlength_corrected, rayleigh_corrected] standard_name: true_color true_color_lowres_crefl: compositor: !!python/name:satpy.composites.core.GenericCompositor prerequisites: - name: M05 - modifiers: [sunz_corrected, rayleigh_corrected_crefl] + modifiers: [effective_solar_pathlength_corrected, rayleigh_corrected_crefl] - name: M04 - modifiers: [sunz_corrected, rayleigh_corrected_crefl] + modifiers: [effective_solar_pathlength_corrected, rayleigh_corrected_crefl] - name: M03 - modifiers: [sunz_corrected, rayleigh_corrected_crefl] + modifiers: [effective_solar_pathlength_corrected, rayleigh_corrected_crefl] standard_name: true_color true_color_lowres_land: compositor: !!python/name:satpy.composites.core.GenericCompositor prerequisites: - name: M05 - modifiers: [sunz_corrected, rayleigh_corrected_land] + modifiers: [effective_solar_pathlength_corrected, rayleigh_corrected_land] - name: M04 - modifiers: [sunz_corrected, rayleigh_corrected_land] + modifiers: [effective_solar_pathlength_corrected, rayleigh_corrected_land] - name: M03 - modifiers: [sunz_corrected, rayleigh_corrected_land] + modifiers: [effective_solar_pathlength_corrected, rayleigh_corrected_land] standard_name: true_color true_color_lowres_marine_tropical: compositor: !!python/name:satpy.composites.core.GenericCompositor prerequisites: - name: M05 - modifiers: [sunz_corrected, rayleigh_corrected_marine_tropical] + modifiers: [effective_solar_pathlength_corrected, rayleigh_corrected_marine_tropical] - name: M04 - modifiers: [sunz_corrected, rayleigh_corrected_marine_tropical] + modifiers: [effective_solar_pathlength_corrected, rayleigh_corrected_marine_tropical] - name: M03 - modifiers: [sunz_corrected, rayleigh_corrected_marine_tropical] + modifiers: [effective_solar_pathlength_corrected, rayleigh_corrected_marine_tropical] standard_name: true_color false_color: compositor: !!python/name:satpy.composites.resolution.RatioSharpenedRGB prerequisites: - name: M11 - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] - name: M07 - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] - name: M05 - modifiers: [sunz_corrected, rayleigh_corrected] + modifiers: [effective_solar_pathlength_corrected, rayleigh_corrected] optional_prerequisites: - name: I02 - modifiers: [sunz_corrected_iband] + modifiers: [effective_solar_pathlength_corrected_iband] standard_name: false_color high_resolution_band: green @@ -283,9 +274,9 @@ composites: - name: M12 modifiers: [nir_reflectance_lowres] - name: M11 - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] - name: M10 - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] standard_name: fire_temperature name: fire_temperature_39refl @@ -293,14 +284,14 @@ composites: compositor: !!python/name:satpy.composites.resolution.RatioSharpenedRGB prerequisites: - name: M10 - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] - name: M07 - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] - name: M05 - modifiers: [sunz_corrected, rayleigh_corrected] + modifiers: [effective_solar_pathlength_corrected, rayleigh_corrected] optional_prerequisites: - name: I01 - modifiers: [sunz_corrected_iband, rayleigh_corrected_iband] + modifiers: [effective_solar_pathlength_corrected_iband, rayleigh_corrected_iband] standard_name: natural_color high_resolution_band: blue @@ -308,11 +299,11 @@ composites: compositor: !!python/name:satpy.composites.core.RGBCompositor prerequisites: - name: I03 - modifiers: [sunz_corrected_iband] + modifiers: [effective_solar_pathlength_corrected_iband] - name: I02 - modifiers: [sunz_corrected_iband] + modifiers: [effective_solar_pathlength_corrected_iband] - name: I01 - modifiers: [sunz_corrected_iband] + modifiers: [effective_solar_pathlength_corrected_iband] standard_name: natural_color natural_color_surf: @@ -366,22 +357,22 @@ composites: compositor: !!python/name:satpy.composites.core.RGBCompositor prerequisites: - name: M10 - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] - name: M07 - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] - name: M05 - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] standard_name: natural_color true_color_raw: compositor: !!python/name:satpy.composites.core.GenericCompositor prerequisites: - name: M05 - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] - name: M04 - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] - name: M03 - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] standard_name: true_color overview: @@ -418,7 +409,7 @@ composites: compositor: !!python/name:satpy.composites.core.GenericCompositor prerequisites: - name: M07 - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] - name: M12 modifiers: [nir_reflectance_lowres] - M15 @@ -428,7 +419,7 @@ composites: compositor: !!python/name:satpy.composites.core.GenericCompositor prerequisites: - name: I02 - modifiers: [sunz_corrected_iband] + modifiers: [effective_solar_pathlength_corrected_iband] - name: I04 modifiers: [nir_reflectance_hires] - I05 @@ -519,9 +510,9 @@ composites: compositor: !!python/name:satpy.composites.core.GenericCompositor prerequisites: - name: M07 - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] - name: M10 - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] - name: M12 modifiers: [nir_reflectance_lowres] standard_name: snow @@ -530,9 +521,9 @@ composites: compositor: !!python/name:satpy.composites.core.GenericCompositor prerequisites: - name: I02 - modifiers: [sunz_corrected_iband] + modifiers: [effective_solar_pathlength_corrected_iband] - name: I03 - modifiers: [sunz_corrected_iband] + modifiers: [effective_solar_pathlength_corrected_iband] - name: I04 modifiers: [nir_reflectance_hires] standard_name: snow @@ -541,9 +532,9 @@ composites: compositor: !!python/name:satpy.composites.core.GenericCompositor prerequisites: - name: I02 - modifiers: [sunz_corrected_iband] + modifiers: [effective_solar_pathlength_corrected_iband] - name: I03 - modifiers: [sunz_corrected_iband] + modifiers: [effective_solar_pathlength_corrected_iband] - name: I04 modifiers: [nir_reflectance_hires] standard_name: snow @@ -596,29 +587,29 @@ composites: compositor: !!python/name:satpy.composites.viirs.SnowAge prerequisites: - name: M07 - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] - name: M08 - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] - name: M09 - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] - name: M10 - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] - name: M11 - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] standard_name: snow_age ocean_color: compositor: !!python/name:satpy.composites.resolution.RatioSharpenedRGB prerequisites: - name: M05 - modifiers: [sunz_corrected, rayleigh_corrected] + modifiers: [effective_solar_pathlength_corrected, rayleigh_corrected] - name: M04 - modifiers: [sunz_corrected, rayleigh_corrected] + modifiers: [effective_solar_pathlength_corrected, rayleigh_corrected] - name: M03 - modifiers: [sunz_corrected, rayleigh_corrected] + modifiers: [effective_solar_pathlength_corrected, rayleigh_corrected] optional_prerequisites: - name: I01 - modifiers: [sunz_corrected_iband, rayleigh_corrected_iband] + modifiers: [effective_solar_pathlength_corrected_iband, rayleigh_corrected_iband] standard_name: ocean_color high_resolution_band: red @@ -636,9 +627,9 @@ composites: prerequisites: - name: M15 - name: I01 - modifiers: [sunz_corrected_iband, rayleigh_corrected] + modifiers: [effective_solar_pathlength_corrected_iband, rayleigh_corrected] - name: I03 - modifiers: [sunz_corrected_iband] + modifiers: [effective_solar_pathlength_corrected_iband] standard_name: cloud_phase_distinction day_cloud_type_distinction: @@ -653,9 +644,9 @@ composites: prerequisites: - name: M15 - name: I01 - modifiers: [sunz_corrected_iband, rayleigh_corrected] + modifiers: [effective_solar_pathlength_corrected_iband, rayleigh_corrected] - name: I03 - modifiers: [sunz_corrected_iband] + modifiers: [effective_solar_pathlength_corrected_iband] standard_name: day_cloud_type_distinction cloud_phase_distinction_raw: @@ -692,9 +683,9 @@ composites: prerequisites: - name: M09 - name: I01 - modifiers: [sunz_corrected_iband, rayleigh_corrected] + modifiers: [effective_solar_pathlength_corrected_iband, rayleigh_corrected] - name: I03 - modifiers: [sunz_corrected_iband] + modifiers: [effective_solar_pathlength_corrected_iband] standard_name: day_cloud_type cloud_phase: @@ -706,11 +697,11 @@ composites: compositor: !!python/name:satpy.composites.core.GenericCompositor prerequisites: - name: I03 - modifiers: [sunz_corrected_iband] + modifiers: [effective_solar_pathlength_corrected_iband] - name: M11 - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] - name: M05 - modifiers: [sunz_corrected, rayleigh_corrected] + modifiers: [effective_solar_pathlength_corrected, rayleigh_corrected] standard_name: cloud_phase cloud_phase_raw: @@ -732,11 +723,11 @@ composites: compositor: !!python/name:satpy.composites.core.GenericCompositor prerequisites: - name: M09 - modifiers: [sunz_corrected] + modifiers: [effective_solar_pathlength_corrected] - name: I01 - modifiers: [sunz_corrected_iband] + modifiers: [effective_solar_pathlength_corrected_iband] - name: I03 - modifiers: [sunz_corrected_iband] + modifiers: [effective_solar_pathlength_corrected_iband] standard_name: cimss_cloud_type cimss_cloud_type_raw: From f3b605debaf3e94a74c6750408e508181b8f6e65 Mon Sep 17 00:00:00 2001 From: Johan Strandgren Date: Wed, 3 Jun 2026 13:04:24 +0000 Subject: [PATCH 43/49] Revert back to old default behaviour of SunZenithCorrector in order to not change any user behaviour and change back later for v1.0 --- satpy/modifiers/geometry.py | 17 +++++++++++++++-- satpy/tests/test_modifiers.py | 4 ++-- 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/satpy/modifiers/geometry.py b/satpy/modifiers/geometry.py index 9460915864..a466a0cf88 100644 --- a/satpy/modifiers/geometry.py +++ b/satpy/modifiers/geometry.py @@ -117,8 +117,8 @@ class SunZenithCorrector(SunZenithCorrectorBase): def __init__( self, - correction_limit: Optional[float] = None, - max_sza: Optional[float] = None, + correction_limit: Optional[float] = 88.0, + max_sza: Optional[float] = 95.0, user_warning: Optional[str] = None, **kwargs, ): @@ -149,6 +149,19 @@ def __init__( super(SunZenithCorrector, self).__init__(**kwargs) def _apply_correction(self, proj, coszen): + + if self.correction_limit is not None or self.max_sza is not None: + # TODO Change class defaults and remove warning in satpy v1.0 + warnings.warn( + "The default reduction of the standard Sun zenith angle correction above 88 degrees will " + "be removed in satpy v1.0 in order to compute the true reflectance with the 'sunz_corrected' modifier. " + "To avoid overcorrection at high angles for (RGB) imagery it's recommended to use the " + "'effective_solar_pathlength_corrected' modifier instead. If you still want to keep the current " + "behaviour, please set the 'correction_limit' parameter to 88.0 and 'max_sza' to 95.0 in a local " + "definition of the modifier.", + UserWarning, + stacklevel=2, + ) if self.user_warning: warnings.warn(self.user_warning, UserWarning, stacklevel=2) return sunzen_corr_cos(proj, coszen, correction_limit=self.correction_limit, max_sza=self.max_sza) diff --git a/satpy/tests/test_modifiers.py b/satpy/tests/test_modifiers.py index 5746592e83..5883fd0448 100644 --- a/satpy/tests/test_modifiers.py +++ b/satpy/tests/test_modifiers.py @@ -142,7 +142,7 @@ def test_default_with_sza_not_provided(self, sunz_ds1, as_32bit): if as_32bit: sunz_ds1 = sunz_ds1.astype(np.float32) comp = SunZenithCorrector(name="sza_test", modifiers=tuple()) - expected = np.array([[66.853256, 68.168938], [66.307419, 67.601494]]) + expected = np.array([[22.401667, 22.31777], [22.437503, 22.353533]]) res = call_sunz_modifier(comp, sunz_ds1) assert_sunz_modifier_result(res, expected, sunz_ds1) assert "y" in res.coords @@ -164,7 +164,7 @@ def test_default_with_sza_provided(self, data_arr, sunz_sza, dtype): """Test default limits when SZA is provided.""" from satpy.modifiers.geometry import SunZenithCorrector comp = SunZenithCorrector(name="sza_test", modifiers=tuple()) - expected = np.array([[5.758770, 19.107323], [57.298689, 0.0]], dtype=dtype) + expected = np.array([[5.758770, 19.107323], [23.133712, 6.372368]], dtype=dtype) res = call_sunz_modifier(comp, data_arr, sunz_sza, dtype) assert_sunz_modifier_result(res, expected, data_arr, dtype) From 83dec7b1e972b9e42e409daebca8093d43cbf3b7 Mon Sep 17 00:00:00 2001 From: Johan Strandgren Date: Wed, 3 Jun 2026 13:07:58 +0000 Subject: [PATCH 44/49] Add todo for v1.0 cleanup --- satpy/modifiers/geometry.py | 1 + 1 file changed, 1 insertion(+) diff --git a/satpy/modifiers/geometry.py b/satpy/modifiers/geometry.py index a466a0cf88..00e05c04f4 100644 --- a/satpy/modifiers/geometry.py +++ b/satpy/modifiers/geometry.py @@ -206,6 +206,7 @@ def __init__( """ if correction_limit is not None or max_sza is not None: + # TODO Remove class init input variables and warning in satpy v1.0 msg = "The ``correction_limit`` and ``max_sza`` parameters have been deprecated and are no " \ "longer used for the EffectiveSolarPathLengthCorrector and will be fully removed " \ "in satpy v1.0. This is done since the parameterization by Li and Shibata (2006) " \ From 4628c1c4b2212acc73f2ce31d0e76eebb9b70cb4 Mon Sep 17 00:00:00 2001 From: Johan Strandgren Date: Wed, 3 Jun 2026 13:19:18 +0000 Subject: [PATCH 45/49] Limit scope for warning --- satpy/modifiers/geometry.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/satpy/modifiers/geometry.py b/satpy/modifiers/geometry.py index 00e05c04f4..6eddb7267e 100644 --- a/satpy/modifiers/geometry.py +++ b/satpy/modifiers/geometry.py @@ -149,8 +149,7 @@ def __init__( super(SunZenithCorrector, self).__init__(**kwargs) def _apply_correction(self, proj, coszen): - - if self.correction_limit is not None or self.max_sza is not None: + if self.correction_limit == 88.0 or self.max_sza == 95.0: # TODO Change class defaults and remove warning in satpy v1.0 warnings.warn( "The default reduction of the standard Sun zenith angle correction above 88 degrees will " From 0c342a1a8f1d10bdabe9bed2dd46eb9eafb3320c Mon Sep 17 00:00:00 2001 From: Johan Strandgren Date: Wed, 3 Jun 2026 13:21:05 +0000 Subject: [PATCH 46/49] Remove explicit modifiers with old/current reduction parameters and corresponding warnings. this is now handled centrally in SunZenithCorrector, which will only have a change of default behaviour in v1.0 --- satpy/etc/composites/ec_msi.yaml | 9 --------- satpy/etc/composites/epic.yaml | 9 --------- satpy/etc/composites/mersi-1.yaml | 9 --------- satpy/etc/composites/mersi-2.yaml | 9 --------- satpy/etc/composites/mersi-3.yaml | 9 --------- satpy/etc/composites/mersi-rm.yaml | 9 --------- satpy/etc/composites/seviri.yaml | 9 --------- satpy/etc/composites/virr.yaml | 9 --------- satpy/etc/composites/visir.yaml | 9 --------- satpy/modifiers/geometry.py | 7 ------- satpy/tests/test_modifiers.py | 10 ---------- 11 files changed, 98 deletions(-) diff --git a/satpy/etc/composites/ec_msi.yaml b/satpy/etc/composites/ec_msi.yaml index cc82df8f30..b0ac2a710d 100644 --- a/satpy/etc/composites/ec_msi.yaml +++ b/satpy/etc/composites/ec_msi.yaml @@ -3,15 +3,6 @@ sensor_name: visir/ec_msi modifiers: sunz_corrected: - user_warning: > - The reduction of the standard Sun zenith angle correction above 88 degrees will - be removed in satpy v1.0 in order to compute the true reflectance with the - 'sunz_corrected' modifier. To avoid overcorrection at high angles for (RGB) imagery - it's recommended to use the 'effective_solar_pathlength_corrected' modifier instead. - If you still want to keep the current behaviour, please set the 'correction_limit' - parameter to 88.0 and 'max_sza' to 95.0 in a local definition of the modifier. - correction_limit: 88.0 - max_sza: 95.0 modifier: !!python/name:satpy.modifiers.SunZenithCorrector rayleigh_corrected: diff --git a/satpy/etc/composites/epic.yaml b/satpy/etc/composites/epic.yaml index 38f9bc5646..2404c73f6b 100644 --- a/satpy/etc/composites/epic.yaml +++ b/satpy/etc/composites/epic.yaml @@ -3,15 +3,6 @@ sensor_name: visir/epic modifiers: sunz_corrected: modifier: !!python/name:satpy.modifiers.SunZenithCorrector - user_warning: > - The reduction of the standard Sun zenith angle correction above 88 degrees will - be removed in satpy v1.0 in order to compute the true reflectance with the - 'sunz_corrected' modifier. To avoid overcorrection at high angles for (RGB) imagery - it's recommended to use the 'effective_solar_pathlength_corrected' modifier instead. - If you still want to keep the current behaviour, please set the 'correction_limit' - parameter to 88.0 and 'max_sza' to 95.0 in a local definition of the modifier. - correction_limit: 88.0 - max_sza: 95.0 optional_prerequisites: - solar_zenith_angle diff --git a/satpy/etc/composites/mersi-1.yaml b/satpy/etc/composites/mersi-1.yaml index f2bf8aaa82..006d9e04d3 100644 --- a/satpy/etc/composites/mersi-1.yaml +++ b/satpy/etc/composites/mersi-1.yaml @@ -16,15 +16,6 @@ modifiers: sunz_corrected: modifier: !!python/name:satpy.modifiers.SunZenithCorrector - user_warning: > - The reduction of the standard Sun zenith angle correction above 88 degrees will - be removed in satpy v1.0 in order to compute the true reflectance with the - 'sunz_corrected' modifier. To avoid overcorrection at high angles for (RGB) imagery - it's recommended to use the 'effective_solar_pathlength_corrected' modifier instead. - If you still want to keep the current behaviour, please set the 'correction_limit' - parameter to 88.0 and 'max_sza' to 95.0 in a local definition of the modifier. - correction_limit: 88.0 - max_sza: 95.0 prerequisites: - name: solar_zenith_angle diff --git a/satpy/etc/composites/mersi-2.yaml b/satpy/etc/composites/mersi-2.yaml index 54c196cae3..4408902e33 100644 --- a/satpy/etc/composites/mersi-2.yaml +++ b/satpy/etc/composites/mersi-2.yaml @@ -16,15 +16,6 @@ modifiers: sunz_corrected: modifier: !!python/name:satpy.modifiers.SunZenithCorrector - user_warning: > - The reduction of the standard Sun zenith angle correction above 88 degrees will - be removed in satpy v1.0 in order to compute the true reflectance with the - 'sunz_corrected' modifier. To avoid overcorrection at high angles for (RGB) imagery - it's recommended to use the 'effective_solar_pathlength_corrected' modifier instead. - If you still want to keep the current behaviour, please set the 'correction_limit' - parameter to 88.0 and 'max_sza' to 95.0 in a local definition of the modifier. - correction_limit: 88.0 - max_sza: 95.0 prerequisites: - solar_zenith_angle diff --git a/satpy/etc/composites/mersi-3.yaml b/satpy/etc/composites/mersi-3.yaml index 9fb8f98044..01426b20fa 100644 --- a/satpy/etc/composites/mersi-3.yaml +++ b/satpy/etc/composites/mersi-3.yaml @@ -16,15 +16,6 @@ modifiers: sunz_corrected: modifier: !!python/name:satpy.modifiers.SunZenithCorrector - user_warning: > - The reduction of the standard Sun zenith angle correction above 88 degrees will - be removed in satpy v1.0 in order to compute the true reflectance with the - 'sunz_corrected' modifier. To avoid overcorrection at high angles for (RGB) imagery - it's recommended to use the 'effective_solar_pathlength_corrected' modifier instead. - If you still want to keep the current behaviour, please set the 'correction_limit' - parameter to 88.0 and 'max_sza' to 95.0 in a local definition of the modifier. - correction_limit: 88.0 - max_sza: 95.0 prerequisites: - solar_zenith_angle diff --git a/satpy/etc/composites/mersi-rm.yaml b/satpy/etc/composites/mersi-rm.yaml index 78e4a69f93..41336c8577 100644 --- a/satpy/etc/composites/mersi-rm.yaml +++ b/satpy/etc/composites/mersi-rm.yaml @@ -16,15 +16,6 @@ modifiers: sunz_corrected: modifier: !!python/name:satpy.modifiers.SunZenithCorrector - user_warning: > - The reduction of the standard Sun zenith angle correction above 88 degrees will - be removed in satpy v1.0 in order to compute the true reflectance with the - 'sunz_corrected' modifier. To avoid overcorrection at high angles for (RGB) imagery - it's recommended to use the 'effective_solar_pathlength_corrected' modifier instead. - If you still want to keep the current behaviour, please set the 'correction_limit' - parameter to 88.0 and 'max_sza' to 95.0 in a local definition of the modifier. - correction_limit: 88.0 - max_sza: 95.0 prerequisites: - solar_zenith_angle diff --git a/satpy/etc/composites/seviri.yaml b/satpy/etc/composites/seviri.yaml index 276167e1bb..e1fd530ecd 100644 --- a/satpy/etc/composites/seviri.yaml +++ b/satpy/etc/composites/seviri.yaml @@ -3,15 +3,6 @@ sensor_name: visir/seviri modifiers: sunz_corrected: modifier: !!python/name:satpy.modifiers.SunZenithCorrector - user_warning: > - The reduction of the standard Sun zenith angle correction above 88 degrees will - be removed in satpy v1.0 in order to compute the true reflectance with the - 'sunz_corrected' modifier. To avoid overcorrection at high angles for (RGB) imagery - it's recommended to use the 'effective_solar_pathlength_corrected' modifier instead. - If you still want to keep the current behaviour, please set the 'correction_limit' - parameter to 88.0 and 'max_sza' to 95.0 in a local definition of the modifier. - correction_limit: 88.0 - max_sza: 95.0 co2_corrected: modifier: !!python/name:satpy.modifiers.CO2Corrector diff --git a/satpy/etc/composites/virr.yaml b/satpy/etc/composites/virr.yaml index 2bac6a5760..d3a109c111 100644 --- a/satpy/etc/composites/virr.yaml +++ b/satpy/etc/composites/virr.yaml @@ -3,15 +3,6 @@ sensor_name: visir/virr modifiers: sunz_corrected: modifier: !!python/name:satpy.modifiers.SunZenithCorrector - user_warning: > - The reduction of the standard Sun zenith angle correction above 88 degrees will - be removed in satpy v1.0 in order to compute the true reflectance with the - 'sunz_corrected' modifier. To avoid overcorrection at high angles for (RGB) imagery - it's recommended to use the 'effective_solar_pathlength_corrected' modifier instead. - If you still want to keep the current behaviour, please set the 'correction_limit' - parameter to 88.0 and 'max_sza' to 95.0 in a local definition of the modifier. - correction_limit: 88.0 - max_sza: 95.0 prerequisites: - name: solar_zenith_angle diff --git a/satpy/etc/composites/visir.yaml b/satpy/etc/composites/visir.yaml index ebbe96956f..a99d12a6a7 100644 --- a/satpy/etc/composites/visir.yaml +++ b/satpy/etc/composites/visir.yaml @@ -8,15 +8,6 @@ composite_identification_keys: modifiers: sunz_corrected: modifier: !!python/name:satpy.modifiers.SunZenithCorrector - user_warning: > - The reduction of the standard Sun zenith angle correction above 88 degrees will - be removed in satpy v1.0 in order to compute the true reflectance with the - 'sunz_corrected' modifier. To avoid overcorrection at high angles for (RGB) imagery - it's recommended to use the 'effective_solar_pathlength_corrected' modifier instead. - If you still want to keep the current behaviour, please set the 'correction_limit' - parameter to 88.0 and 'max_sza' to 95.0 in a local definition of the modifier. - correction_limit: 88.0 - max_sza: 95.0 optional_prerequisites: - solar_zenith_angle diff --git a/satpy/modifiers/geometry.py b/satpy/modifiers/geometry.py index 6eddb7267e..a63bb18777 100644 --- a/satpy/modifiers/geometry.py +++ b/satpy/modifiers/geometry.py @@ -119,7 +119,6 @@ def __init__( self, correction_limit: Optional[float] = 88.0, max_sza: Optional[float] = 95.0, - user_warning: Optional[str] = None, **kwargs, ): """Collect custom configuration values. @@ -135,9 +134,6 @@ def __init__( Pixels with solar zenith angles greater than ``max_sza`` are set to 0. - user_warning: - Optional user warning to be shown when applying the correction. - **kwargs: Additional keyword arguments passed to the parent class. @@ -145,7 +141,6 @@ def __init__( self.method = "sunz_corrected" self.correction_limit = correction_limit self.max_sza = max_sza - self.user_warning = user_warning super(SunZenithCorrector, self).__init__(**kwargs) def _apply_correction(self, proj, coszen): @@ -161,8 +156,6 @@ def _apply_correction(self, proj, coszen): UserWarning, stacklevel=2, ) - if self.user_warning: - warnings.warn(self.user_warning, UserWarning, stacklevel=2) return sunzen_corr_cos(proj, coszen, correction_limit=self.correction_limit, max_sza=self.max_sza) diff --git a/satpy/tests/test_modifiers.py b/satpy/tests/test_modifiers.py index 5883fd0448..b7fd26caef 100644 --- a/satpy/tests/test_modifiers.py +++ b/satpy/tests/test_modifiers.py @@ -229,16 +229,6 @@ def test_invalid_max_sza_and_correction_limit_with_sza_provided(self, data_arr, with pytest.raises(ValueError, match="`max_sza` must be larger than `correction_limit`"): call_sunz_modifier(comp, data_arr, sunz_sza, dtype) - @pytest.mark.parametrize("dtype", [np.float32, np.float64]) - @pytest.mark.parametrize("data_arr", [lazy_fixture("sunz_ds1"), lazy_fixture("sunz_ds1_stacked")]) - def test_custom_warning_with_sza_provided(self, data_arr, sunz_sza, dtype): - """Test custom warning when SZA is provided.""" - from satpy.modifiers.geometry import SunZenithCorrector - msg = "This is a custom warning." - comp = SunZenithCorrector(name="sza_test", modifiers=tuple(), user_warning=msg) - with pytest.warns(UserWarning, match=msg): - call_sunz_modifier(comp, data_arr, sunz_sza, dtype) - def test_incompatible_areas(self, sunz_ds2, sunz_sza): """Test sunz correction on incompatible areas.""" from satpy.composites.core import IncompatibleAreas From 466d0bcb3db000ffffca19ecc49b42dd52eb712c Mon Sep 17 00:00:00 2001 From: Johan Strandgren Date: Wed, 3 Jun 2026 13:25:52 +0000 Subject: [PATCH 47/49] Add legacy viirs sunz_corrected modifiers --- satpy/etc/composites/viirs.yaml | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/satpy/etc/composites/viirs.yaml b/satpy/etc/composites/viirs.yaml index 2b475d1278..a5dae09c7a 100644 --- a/satpy/etc/composites/viirs.yaml +++ b/satpy/etc/composites/viirs.yaml @@ -101,6 +101,18 @@ modifiers: - name: solar_zenith_angle resolution: 742 + sunz_corrected: + modifier: !!python/name:satpy.modifiers.SunZenithCorrector + prerequisites: + - name: solar_zenith_angle + resolution: 742 + + sunz_corrected_iband: + modifier: !!python/name:satpy.modifiers.SunZenithCorrector + prerequisites: + - name: solar_zenith_angle + resolution: 371 + effective_solar_pathlength_corrected: modifier: !!python/name:satpy.modifiers.EffectiveSolarPathLengthCorrector prerequisites: From e8e8853bb19d443d894de96ca5a50fea5875e43b Mon Sep 17 00:00:00 2001 From: Johan Strandgren Date: Wed, 3 Jun 2026 13:27:33 +0000 Subject: [PATCH 48/49] Remove unintended white-space --- satpy/etc/composites/visir.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/satpy/etc/composites/visir.yaml b/satpy/etc/composites/visir.yaml index a99d12a6a7..f169e0c8a7 100644 --- a/satpy/etc/composites/visir.yaml +++ b/satpy/etc/composites/visir.yaml @@ -9,7 +9,7 @@ modifiers: sunz_corrected: modifier: !!python/name:satpy.modifiers.SunZenithCorrector optional_prerequisites: - - solar_zenith_angle + - solar_zenith_angle effective_solar_pathlength_corrected: modifier: !!python/name:satpy.modifiers.EffectiveSolarPathLengthCorrector From af7a080a440edb841ea54bffea067746dd39fd34 Mon Sep 17 00:00:00 2001 From: Johan Strandgren Date: Wed, 3 Jun 2026 14:07:07 +0000 Subject: [PATCH 49/49] Update modifier documentation given (no) change to default behaviour --- doc/source/modifiers.rst | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/doc/source/modifiers.rst b/doc/source/modifiers.rst index c41961fc9e..294fa329ed 100644 --- a/doc/source/modifiers.rst +++ b/doc/source/modifiers.rst @@ -36,7 +36,9 @@ on those modifiers can be found in the linked API documentation. - :class:`~satpy.modifiers.geometry.SunZenithCorrector` - Normalizes solar channels for the solar zenith angle using ``1/cos(sza)`` to compute the true reflectance. This leads to zero reflectance for - solar zenith angles of 90 degrees and above. + solar zenith angles of 90 degrees and above. For Satpy < 1.0 a reduction + of the correction is applied between 88-95 degrees in order to avoid + over-correction for (RGB) imagery and retain imagery beyond 90 degrees. * - ``effective_solar_pathlength_corrected`` - :class:`~satpy.modifiers.geometry.EffectiveSolarPathLengthCorrector` - Normalizes solar channels for the solar zenith angle to compute the reflectance,