Source code for matheo.band_integration.srf_utils

"""
Functions to read spectral response function data with pyspectral
"""

import numpy as np
from pyspectral.rsr_reader import RelativeSpectralResponse
from typing import Union, List, Tuple, Iterator, Optional


"""___Authorship___"""
__author__ = "Sam Hunt"
__created__ = "5/11/2020"


[docs] def return_band_names( platform_name: str, sensor_name: str, band_names: Optional[List[str]] = None, min_wl: Optional[float] = None, max_wl: Optional[float] = None, ) -> List[str]: """ Returns band names for specified sensor from `pyspectral <https://pyspectral.readthedocs.io/en/master/installation.html#static-data>`_ library. :param platform_name: satellite name :param sensor_name: name of instrument on satellite :param band_names: (optional) if omitted all sensor band names are returned, otherwise submitted band names validated and returned :param min_wl: minimum wavelength to include in range :param max_wl: maximum wavelength to include in range :return: band names """ srf_util = SensorSRFUtil(platform_name, sensor_name) return srf_util.return_band_names( band_names=band_names, min_wl=min_wl, max_wl=max_wl )
[docs] def return_band_centres( platform_name: str, sensor_name: str, band_names: Optional[List[str]] = None, detector_name: Optional[str] = None, min_wl: Optional[float] = None, max_wl: Optional[float] = None, ) -> np.ndarray: """ Returns band centres for specified sensor from `pyspectral <https://pyspectral.readthedocs.io/en/master/installation.html#static-data>`_ library. :param platform_name: satellite name :param sensor_name: name of instrument on satellite :param band_names: name of bands to return band centres of, if omitted all band returned :param detector_name: name of sensor detector. Can be used in sensor has SRF data for for different detectors separately - if not specified in this case different :param min_wl: minimum wavelength to include in range :param max_wl: maximum wavelength to include in range :return: band centres in nm """ srf_util = SensorSRFUtil( platform_name, sensor_name, detector_name, band_names=band_names ) return srf_util.return_band_centres(min_wl=min_wl, max_wl=max_wl)
[docs] def return_srf( platform_name: str, sensor_name: str, band_name: str = None, detector_name: Union[None, str] = None, ) -> Tuple[np.ndarray, np.ndarray]: """ Returns srf data for named band of for specified sensor from `pyspectral <https://pyspectral.readthedocs.io/en/master/installation.html#static-data>`_ library. :param platform_name: satellite name :param sensor_name: name of instrument on satellite :param band_name: name of sensor band :param detector_name: (optional) name of sensor detector. Can be used in sensor has SRF data for for different detectors separately - if not specified in this case different :return: band srf :return: band srf wavelength coordinates """ srf_util = SensorSRFUtil(platform_name, sensor_name, detector_name) return srf_util.return_srf(band_name)
[docs] def return_iter_srf( platform_name: str, sensor_name: str, band_names: Optional[List[str]] = None, detector_name: Optional[str] = None, ) -> Iterator: """ Returns iterable of band srfs for specified sensor from `pyspectral <https://pyspectral.readthedocs.io/en/master/installation.html#static-data>`_ library. :param platform_name: satellite name :param sensor_name: name of instrument on satellite :param band_names: name of bands to iterate through, if omitted all bands included :param detector_name: name of sensor detector. Can be used in sensor has SRF data for for different detectors separately - if not specified in this case different :return: iterable that returns band srf and srf wavelength coordinates at each iteration """ srf_util = SensorSRFUtil( platform_name, sensor_name, detector_name, band_names=band_names ) return iter(srf_util)
[docs] class SensorSRFUtil: """ Helper class to define repeating functions along a coordinate axis from `pyspectral <https://pyspectral.readthedocs.io/en/master/installation.html#static-data>`_ library. :param platform_name: satellite name :param sensor_name: name of instrument on satellite :param detector_name: (optional) name of sensor detector. Can be used in sensor has SRF data for for different detectors separately - if not specified in this case different :param band_names: (optional) sensor bands to evaluate band integral for, if omitted band integral evaluated for all bands within spectral range of datar """ def __init__( self, platform_name, sensor_name, detector_name: Union[None, str] = "det-1", band_names: Union[None, List[str]] = None, ): # Set attributes from arguments self.sensor = RelativeSpectralResponse(platform_name, sensor_name) self.detector_name = "det-1" if detector_name is None else detector_name # Unpack and validate selected bands self.band_names = self.return_band_names(band_names) self.band_centres = self.return_band_centres()
[docs] def return_band_names( self, band_names: Optional[str] = None, min_wl: Optional[float] = None, max_wl: Optional[float] = None, ) -> List[str]: """ Returns band names for specified sensor bands :param band_names: if omitted all sensor band names are returned, otherwise submitted band names validated and returned :param min_wl: minimum wavelength to include in range :param max_wl: maximum wavelength to include in range :return: band names """ sensor_band_names = self.return_sensor_band_names() sensor_band_centres = self.return_band_centres() selected_band_centres = self.return_band_centres(min_wl=min_wl, max_wl=max_wl) selected_band_names = [ b for b, c in zip(sensor_band_names, sensor_band_centres) if c in selected_band_centres ] if band_names is None: band_names = selected_band_names else: if not set(band_names).issubset(set(selected_band_names)): raise ValueError( "band names must be one of - " + str(selected_band_names) ) band_names = band_names return band_names
[docs] def return_band_centres( self, min_wl: Optional[float] = None, max_wl: Optional[float] = None ) -> np.ndarray: """ Returns band centres for specified sensor bands :param min_wl: minimum wavelength to include in range :param max_wl: maximum wavelength to include in range :return: band centres in nm """ band_names = self.return_sensor_band_names() band_centres = [ self.sensor.rsr[band_name][self.detector_name]["central_wavelength"] * self.sensor.si_scale / 1e-9 for band_name in band_names ] if min_wl is not None: band_centres = [b for b in band_centres if (b > min_wl)] if max_wl is not None: band_centres = [b for b in band_centres if (b < max_wl)] band_centres = np.array(band_centres) return band_centres
[docs] def return_sensor_band_names(self) -> List[str]: """ Returns list of all sensor band names :return: sensor band names """ return list(self.sensor.rsr.keys())
[docs] def return_srf(self, band_name: str) -> Tuple[np.ndarray, np.ndarray]: """ Returns srf data for specified sensor band :param band_name: sensor band name :return: band srf :return: band srf wavelength coordinates """ srf = self.sensor.rsr[band_name][self.detector_name][ "response" ] # gets rsr for given band wl_srf = 1000 * self.sensor.rsr[band_name][self.detector_name]["wavelength"] return srf, wl_srf
def __iter__(self): # Define counter self.i = 0 return self def __next__(self) -> Tuple[np.ndarray, np.ndarray]: """ Returns ith function :return: band srf :return: band srf wavelength coordinates """ # Iterate through bands if self.i < len(self.band_names): # Update counter self.i += 1 return self.return_srf(self.band_names[self.i - 1]) else: raise StopIteration
if __name__ == "__main__": pass