Source code for eoreader.products.sar.csg_product

# -*- coding: utf-8 -*-
# Copyright 2022, SERTIT-ICube - France, https://sertit.unistra.fr/
# This file is part of eoreader project
#     https://github.com/sertit/eoreader
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""
COSMO-SkyMed 2nd Generation products.
More info `here <https://egeos.my.salesforce.com/sfc/p/#1r000000qoOc/a/69000000JXxZ/WEEbowzi5cmY8vLqyfAAMKZ064iN1eWw_qZAgUkTtXI>`_.
"""
import logging
from enum import unique
from pathlib import Path
from typing import Union

import rasterio
import xarray as xr
from cloudpathlib import CloudPath
from sertit.misc import ListEnum

from eoreader.bands.bands import BandNames
from eoreader.exceptions import InvalidProductError
from eoreader.products import CosmoProduct
from eoreader.utils import EOREADER_NAME

LOGGER = logging.getLogger(EOREADER_NAME)


[docs]@unique class CsgSensorMode(ListEnum): """ COSMO-SkyMed 2nd Generation sensor mode. More info `here <https://egeos.my.salesforce.com/sfc/p/#1r000000qoOc/a/69000000JXxZ/WEEbowzi5cmY8vLqyfAAMKZ064iN1eWw_qZAgUkTtXI>`_. """ S1A = "SPOTLIGHT-1A" """SPOTLIGHT-1A""" S1B = "SPOTLIGHT-1B" """SPOTLIGHT-1B""" S2A = "SPOTLIGHT-2A" """SPOTLIGHT-2A (standard and apodized)""" S2B = "SPOTLIGHT-2B" """SPOTLIGHT-2B (standard and apodized)""" S2C = "SPOTLIGHT-2C" """SPOTLIGHT-2C (standard and apodized)""" S1_MSOR = "SPOTLIGHT-1-MSOR" """SPOTLIGHT-1-MSOR""" S2_MSOS = "SPOTLIGHT-2-MSOS" """SPOTLIGHT-2-MSOS""" S2_MSJN = "SPOTLIGHT-2-MSJN" """SPOTLIGHT-2-MSJN""" S1_OQR = "SPOTLIGHT-1-OQR" """SPOTLIGHT-1-OQR""" S2_OQS = "SPOTLIGHT-2-OQS" """SPOTLIGHT-2-OQS""" S1_EQR = "SPOTLIGHT-1-EQR" """SPOTLIGHT-1-EQR""" S2_EQS = "SPOTLIGHT-2-EQS" """SPOTLIGHT-2-EQS""" SM = "STRIPMAP" """SPOTLIGHT-2C (standard and apodized). Resolution: Natural""" PP = "PINGPONG" """PingPong. Resolution: 8.0m""" QP = "QUADPOL" """QuadPol. Resolution: Natural""" SC1 = "SCANSAR-1" """ScanSar-1. Resolution: 14.0m""" SC2 = "SCANSAR-2" """ScanSar-2. Resolution: 27.0m""" NA = "N/A" """N/A"""
[docs]class CsgProduct(CosmoProduct): """ Class for COSMO-SkyMed 2nd Generation Products More info `here <https://egeos.my.salesforce.com/sfc/p/#1r000000qoOc/a/69000000JXxZ/WEEbowzi5cmY8vLqyfAAMKZ064iN1eWw_qZAgUkTtXI>`_. """ def _get_resolution(self) -> float: """ Get product default resolution (in meters) See here <here](https://earth.esa.int/eogateway/documents/20142/37627/COSMO-SkyMed-Second-Generation-Mission-Products-Description.pdf>`_ for more information (tables 20). Taking the :code:`CSK legacy` values """ if self.sensor_mode == CsgSensorMode.S2A: def_res = 0.4 elif self.sensor_mode == CsgSensorMode.S2B: def_res = 0.63 elif self.sensor_mode == CsgSensorMode.S2C: def_res = 0.8 elif self.sensor_mode == CsgSensorMode.PP: def_res = 12.0 elif self.sensor_mode == CsgSensorMode.SC1: def_res = 20.0 elif self.sensor_mode == CsgSensorMode.SC2: def_res = 40.0 elif self.sensor_mode in [CsgSensorMode.SM, CsgSensorMode.QP]: def_res = 3.0 else: # Complex data has an empty field and its resolution is not known def_res = -1.0 return def_res def _set_instrument(self) -> None: """ Set instrument CSG: https://earth.esa.int/eogateway/missions/cosmo-skymed-second-generation """ self.instrument = "SAR X-band" def _set_sensor_mode(self) -> None: """ Get products type from S2 products name (could check the metadata too) """ # Get MTD XML file root, _ = self.read_mtd() # Open identifier acq_mode = root.findtext(".//AcquisitionMode") if not acq_mode: raise InvalidProductError("AcquisitionMode not found in metadata!") # Get sensor mode self.sensor_mode = CsgSensorMode.from_value(acq_mode) if not self.sensor_mode: raise InvalidProductError( f"Invalid {self.constellation.value} name: {self.name}" ) def _read_band( self, path: Union[CloudPath, Path], band: BandNames = None, resolution: Union[tuple, list, float] = None, size: Union[list, tuple] = None, **kwargs, ) -> xr.DataArray: """ Read band from disk. .. WARNING:: CSG SCS Products do not have a default resolution Args: path (Union[CloudPath, Path]): Band path band (BandNames): Band to read resolution (Union[tuple, list, float]): Resolution of the wanted band, in dataset resolution unit (X, Y) size (Union[tuple, list]): Size of the array (width, height). Not used if resolution is provided. kwargs: Other arguments used to load bands Returns: xr.DataArray: Band xarray """ # In case of SCS data that doesn't have any resolution in the mtd if self.resolution < 0.0: with rasterio.open(path) as ds: self.resolution = ds.res[0] try: if resolution < 0.0: resolution = self.resolution except TypeError: pass return super()._read_band( path=path, band=band, resolution=resolution, size=size, **kwargs )