Source code for satpy.modifiers._crefl

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

import logging
import warnings

import numpy as np

from satpy.aux_download import DataDownloadMixin, retrieve
from satpy.modifiers import ModifierBase
from satpy.modifiers.angles import get_angles

LOG = logging.getLogger(__name__)


[docs] class ReflectanceCorrector(ModifierBase, DataDownloadMixin): """Corrected Reflectance (crefl) modifier. Uses a python rewrite of the C CREFL code written for VIIRS and MODIS. """ def __init__(self, *args, dem_filename=None, dem_sds="averaged elevation", # noqa: D417 url=None, known_hash=None, **kwargs): """Initialize the compositor with values from the user or from the configuration file. If `dem_filename` can't be found or opened then correction is done assuming TOA or sealevel options. Args: dem_filename (str): DEPRECATED url (str): URL or local path to the Digital Elevation Model (DEM) HDF4 file. If unset (None or empty string), then elevation is assumed to be 0 everywhere. known_hash (str): Optional SHA256 checksum to verify the download of ``url``. dem_sds (str): Name of the variable in the elevation file to load. """ if dem_filename is not None: warnings.warn( "'dem_filename' for 'ReflectanceCorrector' is " "deprecated. Use 'url' instead.", DeprecationWarning, stacklevel=2 ) super(ReflectanceCorrector, self).__init__(*args, **kwargs) self.dem_sds = dem_sds self.url = url self.known_hash = known_hash self.dem_cache_key = self._get_registered_dem_cache_key()
[docs] def _get_registered_dem_cache_key(self): if not self.url: return reg_files = self.register_data_files([{ "url": self.url, "known_hash": self.known_hash} ]) return reg_files[0]
def __call__(self, datasets, optional_datasets, **info): """Create modified DataArray object by applying the crefl algorithm.""" refl_data, angles = self._extract_angle_data_arrays(datasets, optional_datasets) results = self._call_crefl(refl_data, angles) info.update(refl_data.attrs) info["rayleigh_corrected"] = True results.attrs = info self.apply_modifier_info(refl_data, results) return results
[docs] def _call_crefl(self, refl_data, angles): from satpy.modifiers._crefl_utils import run_crefl avg_elevation = self._get_average_elevation() results = run_crefl(refl_data, *angles, avg_elevation=avg_elevation, ) return results
[docs] def _get_average_elevation(self): if self.dem_cache_key is None: return LOG.debug("Loading CREFL averaged elevation information from: %s", self.dem_cache_key) local_filename = retrieve(self.dem_cache_key) avg_elevation = self._read_var_from_hdf4_file(local_filename, self.dem_sds).astype(np.float64) if isinstance(avg_elevation, np.ma.MaskedArray): avg_elevation = avg_elevation.filled(np.nan) return avg_elevation
[docs] @staticmethod def _read_var_from_hdf4_file(local_filename, var_name): try: return ReflectanceCorrector._read_var_from_hdf4_file_pyhdf(local_filename, var_name) except (ImportError, OSError): return ReflectanceCorrector._read_var_from_hdf4_file_netcdf4(local_filename, var_name)
[docs] @staticmethod def _read_var_from_hdf4_file_netcdf4(local_filename, var_name): from netCDF4 import Dataset as NCDataset # HDF4 file, NetCDF library needs to be compiled with HDF4 support nc = NCDataset(local_filename, "r") # average elevation is stored as a 16-bit signed integer but with # scale factor 1 and offset 0, convert it to float here return nc.variables[var_name][:]
[docs] @staticmethod def _read_var_from_hdf4_file_pyhdf(local_filename, var_name): from pyhdf.SD import SD, SDC f = SD(local_filename, SDC.READ) var = f.select(var_name) data = var[:] fill = ReflectanceCorrector._read_fill_value_from_hdf4(var, data.dtype) return np.ma.MaskedArray(data, data == fill)
[docs] @staticmethod def _read_fill_value_from_hdf4(var, dtype): from pyhdf.error import HDF4Error try: return var.getfillvalue() except HDF4Error: return np.iinfo(dtype).min
[docs] def _extract_angle_data_arrays(self, datasets, optional_datasets): all_datasets = datasets + optional_datasets if len(all_datasets) == 1: vis = self.match_data_arrays(datasets)[0] return vis, get_angles(vis) if len(all_datasets) == 5: vis, *angles = self.match_data_arrays( datasets + optional_datasets) return vis, angles raise ValueError("Not sure how to handle provided dependencies. " "Either all 4 angles must be provided or none of " "of them.")