You are looking the documentation of a development version. The release version is available at master.

Source code for iota2.common.external_code

"""S2 tests utilities functions."""
# =========================================================================
#   Program:   iota2
#
#   Copyright (c) CESBIO. All rights reserved.
#
#   See LICENSE for details.
#
#   This software is distributed WITHOUT ANY WARRANTY; without even
#   the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
#   PURPOSE.  See the above copyright notices for more information.
#
# =========================================================================
from typing import Union

import numpy as np
import numpy.ma as ma
from iota2.learning.utils import I2Label, I2TemporalLabel


def raise_label_exception(self):
    """Utility function"""
    labels = [
        I2TemporalLabel(sensor_name="sentinel2", feat_name="new_b2", date=date)
        for date in self.interpolated_dates["Sentinel2"]
    ]
    return self.get_interpolated_Sentinel2_B2(), labels


def get_identity(self):
    """Utility function"""
    labels = [
        I2TemporalLabel(sensor_name="sentinel2", feat_name="newb2", date=date)
        for date in self.interpolated_dates["Sentinel2"]
    ]
    return self.get_interpolated_Sentinel2_B2(), labels


def get_mnt(self):
    """Utility function"""
    data = self.get_interpolated_userfeatures_mnt()
    _, _, mnt_bands = data.shape
    return data, [I2Label(sensor_name="mnt", feat_name=num) for num in range(mnt_bands)]


def test_get_band(self, band: int = 0, label: str = "none"):
    """
    Get the band defined by integer with a label given by the string

    Parameters
    ----------
    band:
        must be an integer among 2,3,4
    label:
        the string you want
    """
    if band not in [2, 3, 4]:
        raise ValueError(f"band must be 2, 3 or 4, not {band}")
    if band == 2:
        return self.get_interpolated_Sentinel2_B2(), [label]
    if band == 3:
        return self.get_interpolated_Sentinel2_B3(), [label]
    if band == 4:
        return self.get_interpolated_Sentinel2_B4(), [label]


def get_exception(self):
    """this function raises an exception
    it is used to simulate an external feature that fails"""
    raise Exception("I'm a bad external feature")


def test_index_sum(self):
    """
    Get a sum of test indexes
    """
    coef = self.get_interpolated_Sentinel2_B2() + self.get_interpolated_Sentinel2_B4()
    labels = []
    return np.sum(coef, axis=2), labels


def test_index(self):
    """
    Get a test index
    """
    coef = self.get_interpolated_Sentinel2_B2() + self.get_interpolated_Sentinel2_B4()
    labels = []
    return coef, labels


def duplicate_ndvi(self):
    """Utility function"""
    ndvi = self.get_interpolated_Sentinel2_NDVI()
    labels = [f"dupndvi_{i+1}" for i in range(ndvi.shape[2])]
    return ndvi, labels


def get_ndvi(self):
    """Utility function"""
    coef = (self.get_interpolated_Sentinel2_B8() - self.get_interpolated_Sentinel2_B4()) / (
        self.get_interpolated_Sentinel2_B4() + self.get_interpolated_Sentinel2_B8() + 1e-9
    )
    labels = [I2Label(sensor_name="ndvi", feat_name=i + 1) for i in range(coef.shape[2])]
    return coef, labels


def custom_function(self):
    """Utility function"""
    print(dir(self))
    print(self.get_interpolated_Sentinel2_b1(), self.get_interpolated_Sentinel2_b2())
    return self.get_interpolated_Sentinel2_b1() + self.get_interpolated_Sentinel2_b2()


def custom_function_inv(self):
    """Utility function"""
    print(dir(self))
    print(self.get_interpolated_Sentinel2_b1(), self.get_interpolated_Sentinel2_b2())
    return self.get_interpolated_Sentinel2_b1() - self.get_interpolated_Sentinel2_b2()


def get_ndsi(self):
    """Utility function"""
    coef = (self.get_interpolated_Sentinel2_B3() - self.get_interpolated_Sentinel2_B11()) / (
        self.get_interpolated_Sentinel2_B3() + self.get_interpolated_Sentinel2_B11()
    )
    labels = [f"ndsi_{i+1}" for i in range(coef.shape[2])]
    print("out custom features")
    return coef, labels


def get_cari(self):
    """Utility function"""
    a = (
        ((self.get_interpolated_Sentinel2_B5() - self.get_interpolated_Sentinel2_B3()) / 150) * 670
        + self.get_interpolated_Sentinel2_B4()
        + (
            self.get_interpolated_Sentinel2_B3()
            - ((self.get_interpolated_Sentinel2_B5() - self.get_interpolated_Sentinel2_B3()) / 150)
            * 550
        )
    )
    b = (
        (self.get_interpolated_Sentinel2_B5() - self.get_interpolated_Sentinel2_B3()) / (150 * 150)
    ) + 1
    coef = (self.get_interpolated_Sentinel2_B5() / self.get_interpolated_Sentinel2_B4()) * (
        (np.sqrt(a * a)) / (np.sqrt(b))
    )
    labels = [f"cari_{i+1}" for i in range(coef.shape[2])]

    return coef, labels


def get_red_edge2(self):
    """Utility function"""
    coef = (self.get_interpolated_Sentinel2_B5() - self.get_interpolated_Sentinel2_B4()) / (
        self.get_interpolated_Sentinel2_B5() + self.get_interpolated_Sentinel2_B4()
    )
    labels = [f"rededge2_{i+1}" for i in range(coef.shape[2])]
    return coef, labels


def get_gndvi(self):
    """
    compute the Green Normalized Difference Vegetation Index
    DO NOT USE this except for test as Sentinel2 has not B9
    """
    coef = (self.get_interpolated_Sentinel2_B9() - self.get_interpolated_Sentinel2_B3()) / (
        self.get_interpolated_Sentinel2_B9() + self.get_interpolated_Sentinel2_B3()
    )
    labels = [f"gndvi_{i+1}" for i in range(coef.shape[2])]
    return coef, labels


[docs]def get_soi(self) -> tuple[np.ndarray, Union[I2Label, I2TemporalLabel]]: """Compute the Soil Composition Index. Functions get_interpolated_Sentinel2_B2() returns numpy array of size N * M * D where: - N the number of row, computed by iota2 - M the number of columns, computed by iota2 - D the number of dimension == the number of dates (being masked or not) The output is a tuple of coef and labels. - Labels must be a list of I2Label or I2TemporalLabel (could be empty) - Coef is a numpy array, with an expected shape of N * M * X Where X is a dimension, which can be different to D, from 1 to infinite The user can force the output data type by converting it using `astype` built-in numpy array function. The user must manage numerically issues in their codes, such as division by 0 or type overflow. Parameters ---------- self: self is the only parameter for external functions """ coef = (self.get_interpolated_Sentinel2_B11() - self.get_interpolated_Sentinel2_B8()) / ( self.get_interpolated_Sentinel2_B11() + self.get_interpolated_Sentinel2_B8() ) labels = [I2Label(sensor_name="soi", feat_name=i + 1) for i in range(coef.shape[2])] return coef, labels
def get_raw_data(self): """Utility function""" coef, labels_refl = self.get_filled_stack() masks, label_masks = self.get_filled_masks() coef = np.concatenate((coef, masks), axis=2) labels = labels_refl + label_masks return coef, labels def use_raw_data(self): """Utility function""" coef = self.get_raw_Sentinel2_B2() labels = [] return coef, labels def use_exogeneous_data(self): """Utility function""" exo_data = self.get_exogeneous_data() _, _, nb_exo_bands = exo_data.shape labels = [I2Label(sensor_name="exo", feat_name=exo_ind) for exo_ind in range(nb_exo_bands)] return exo_data, labels def use_raw_and_masks_data(self): """ This function use raw data and masks This test function get the B2 from Sentinel2 and set to -1000 all pixels masked The output is converted to int16. """ band = self.get_raw_Sentinel2_B2() mask = self.get_Sentinel2_binary_masks() coef = ma.masked_array(band, mask=mask) coef = coef.filled(-1000) return coef.astype("int16"), [] # ############################################################################ # DHI INDEX # ############################################################################ def get_cumulative_productivity(self): """Utility function""" coef = np.sum(self.get_interpolated_Sentinel2_NDVI(), axis=2) return coef, [I2Label(sensor_name="cumul", feat_name="prod")] def get_minimum_productivity(self): """Utility function""" coef = np.min(self.get_interpolated_Sentinel2_NDVI(), axis=2) return coef, [I2Label(sensor_name="min", feat_name="prod")] def get_seasonal_variation(self): """Utility function""" coef = np.std(self.get_interpolated_Sentinel2_NDVI(), axis=2) / ( np.mean(self.get_interpolated_Sentinel2_NDVI(), axis=2) + 1e-6 ) return coef, [I2Label(sensor_name="var", feat_name="prod")] # ########################################################################### # Functions for testing all sensors # ########################################################################### def test_index_sum_l5_old(self): """Utility function""" coef = self.get_interpolated_Landsat5Old_B2() + self.get_interpolated_Landsat5Old_B4() labels = [] return np.sum(coef, axis=2), labels def test_index_l5_old(self): """Utility function""" coef = self.get_interpolated_Landsat5Old_B2() + self.get_interpolated_Landsat5Old_B4() labels = [] return coef, labels def test_index_sum_l8_old(self): """Utility function""" coef = self.get_interpolated_Landsat8Old_B2() + self.get_interpolated_Landsat8Old_B4() labels = [] return np.sum(coef, axis=2), labels def test_index_l8_old(self): """Utility function""" coef = self.get_interpolated_Landsat8Old_B2() + self.get_interpolated_Landsat8Old_B4() labels = [] return coef, labels def test_index_sum_l8(self): """Utility function""" coef = self.get_interpolated_Landsat8_B2() + self.get_interpolated_Landsat8_B4() labels = [] return np.sum(coef, axis=2), labels def test_index_l8(self): """Utility function""" coef = self.get_interpolated_Landsat8_B2() + self.get_interpolated_Landsat8_B4() labels = [] return coef, labels def test_index_sum_s2_s2c(self): """Utility function""" coef = self.get_interpolated_Sentinel2S2C_B02() + self.get_interpolated_Sentinel2S2C_B04() labels = [] return np.sum(coef, axis=2), labels def test_index_s2_s2c(self): """Utility function""" coef = self.get_interpolated_Sentinel2S2C_B02() + self.get_interpolated_Sentinel2S2C_B04() labels = [] return coef, labels def test_index_sum_s2_l3a(self): """Utility function""" coef = self.get_interpolated_Sentinel2L3A_B2() + self.get_interpolated_Sentinel2L3A_B4() labels = [] return np.sum(coef, axis=2), labels def test_index_s2_l3a(self): """Utility function""" coef = self.get_interpolated_Sentinel2L3A_B2() + self.get_interpolated_Sentinel2L3A_B4() labels = [] return coef, labels def get_soi_s2(self): """ compute the Soil Composition Index """ dates = self.get_interpolated_dates() coef = (self.get_interpolated_Sentinel2_B11() - self.get_interpolated_Sentinel2_B8()) / ( self.get_interpolated_Sentinel2_B11() + self.get_interpolated_Sentinel2_B8() + 1.0e-6 ) labels = [ I2TemporalLabel(sensor_name="sentinel2", feat_name="soi", date=date) for date in dates["Sentinel2"] ] return coef, labels