Skip to content
Snippets Groups Projects
test_spectral_tests.py 23.21 KiB
"""Spectral tests."""

import os

import numpy as np
import pytest
import xarray as xr
from ruamel.yaml import YAML

import mvcm.spectral_tests as tst

_scene_list = [
    "Land_Day",
    "Land_Day_Coast",
    "Land_Day_Desert",
    "Land_Day_Desert_Coast",
    "Ocean_Day",
    # "Ocean_Night",
    # "Polar_Day_Ocean",
    # "Polar_Night_Ocean",
    # "Polar_Day_Land",
    # "Polar_Day_Coast",
    # "Polar_Day_Desert",
    # "Polar_Day_Desert_Coast",
    # "Polar_Day_Snow",
    # "Land_Night",
    # "Polar_Night_Land",
    # "Polar_Night_Snow",
    # "Day_Snow",
    # "Night_Snow",
]


# CREATE PATHS
@pytest.fixture(scope="class")
def fixturepath():
    """Get fixture path."""
    return os.path.join(os.path.dirname(__file__), "fixtures")


@pytest.fixture(scope="class")
def data_path():
    """Get data path."""
    return "/ships19/hercules/pveglio/mvcm_git_tests"


# SET FILENAME FIXTURES
@pytest.fixture(scope="class")
def thresholds_file(fixturepath):
    """Set thresholds file name."""
    return os.path.join(fixturepath, "thresholds.mvcm.snpp.v0.0.1.yaml")


class Files:
    """Class that contains names for input and reference files."""

    def __init__(self, ref_file, test_file):
        """Initialize attributes."""
        self.ref_file = ref_file
        self.test_file = test_file


@pytest.fixture(scope="class", params=_scene_list)
def files(data_path, request):
    """Create files."""
    ref_file = f"{data_path}/ref_confidence_{request.param}.nc"
    test_file = f"{data_path}/test_scene_{request.param}.nc"
    return Files(ref_file, test_file)


# SET DATA FIXTURES
@pytest.fixture(scope="class", autouse=True)
def thresholds(thresholds_file):
    """Load thresholds file."""
    yaml = YAML(typ="safe")
    return yaml.load(open(thresholds_file))


@pytest.fixture(scope="class")
def test_data(files):
    """Load data."""
    return xr.open_dataset(files.test_file)


@pytest.fixture(scope="class")
def reference(files):
    """Load reference data."""
    return xr.open_dataset(files.ref_file)


# DEFINE TESTS
class Test11umTest:
    """Test 11um_test function."""

    @pytest.fixture(scope="class")
    def run_11um_test(self, test_data, thresholds):
        """Run the 11um_test function."""
        cmin = np.ones(test_data.latitude.shape)
        bits = {
            "qa": np.zeros(test_data.latitude.shape),
            "test": np.zeros(test_data.latitude.shape),
        }
        scene_name = test_data.scene_name
        if scene_name not in ["Ocean_Day", "Ocean_Night", "Polar_Day_Ocean", "Polar_Night_Ocean"]:
            assert True

        scene_type = tst.CloudTests(data=test_data, scene_name=scene_name, thresholds=thresholds)

        cmin, bits = scene_type.test_11um("M15", cmin, bits)
        return {"cmin": cmin, "bits": bits}

    def test_qa_bit(self, run_11um_test, reference):
        """Test qa bit value."""
        assert np.allclose(run_11um_test["bits"]["qa"], reference.qa_bit_11um.values)

    def test_test_bit(self, run_11um_test, reference):
        """Test test bit value."""
        assert np.allclose(run_11um_test["bits"]["test"], reference.test_bit_11um.values)

    def test_confidence(self, run_11um_test, reference):
        """Test confidence value."""
        assert np.allclose(run_11um_test["cmin"], reference.confidence_11um.values)


# WARNING: THIS TEST IS NOT RUNNING BECAUSE THE FUNCTION BEING TESTED IS NOT IMPLEMENTED
class NoTestSurfaceTemperatureTest:
    """Test surface_temperature_test function."""

    @pytest.fixture(scope="class")
    def run_surface_temperature_test(self, test_data, thresholds):
        """Run the surface_temperature_test function."""
        cmin = np.ones(test_data.latitude.shape)
        bits = {
            "qa": np.zeros(test_data.latitude.shape),
            "test": np.zeros(test_data.latitude.shape),
        }
        scene_name = test_data.scene_name
        if scene_name not in ["Land_Night", "Polar_Night_Land"]:
            assert True

        scene_type = tst.CloudTests(data=test_data, scene_name=scene_name, thresholds=thresholds)

        cmin, bits = scene_type.test_surface_temperature("M15", cmin, bits)
        return {"cmin": cmin, "bits": bits}

    def test_qa_bit(self, run_surface_temperature_test, reference):
        """Test qa bit value."""
        assert np.allclose(run_surface_temperature_test["bits"]["qa"], reference.qa_bit.values)

    def test_test_bit(self, run_surface_temperature_test, reference):
        """Test test bit value."""
        assert np.allclose(run_surface_temperature_test["bits"]["test"], reference.test_bit.values)

    def test_confidence(self, run_surface_temperature_test, reference):
        """Test confidence value."""
        assert np.allclose(run_surface_temperature_test["cmin"], reference.confidence.values)


class TestSeaSurfTemperatureTest:
    """Test sst_test function."""

    @pytest.fixture(scope="class")
    def run_sst_test(self, test_data, thresholds):
        """Run the sst_test function."""
        cmin = np.ones(test_data.latitude.shape)
        bits = {
            "qa": np.zeros(test_data.latitude.shape),
            "test": np.zeros(test_data.latitude.shape),
        }
        scene_name = test_data.scene_name
        if scene_name not in ["Ocean_Day", "Ocean_Night", "Polar_Day_Ocean", "Polar_Night_Ocean"]:
            assert True

        scene_type = tst.CloudTests(data=test_data, scene_name=scene_name, thresholds=thresholds)

        cmin, bits = scene_type.sst_test("M15", "M16", cmin, bits)
        return {"cmin": cmin, "bits": bits}

    def test_qa_bit(self, run_sst_test, reference):
        """Test qa bit value."""
        assert np.allclose(run_sst_test["bits"]["qa"], reference.qa_bit_sst.values)

    def test_test_bit(self, run_sst_test, reference):
        """Test test bit value."""
        assert np.allclose(run_sst_test["bits"]["test"], reference.test_bit_sst.values)

    def test_confidence(self, run_sst_test, reference):
        """Test confidence value."""
        assert np.allclose(run_sst_test["cmin"], reference.confidence_sst.values)


class Test86Minus11umBTTest:
    """Test bt_diff_86_11um function."""

    @pytest.fixture(scope="class")
    def run_86_11um_diff_test(self, test_data, thresholds):
        """Run the bt_diff_86_11um function."""
        cmin = np.ones(test_data.latitude.shape)
        bits = {
            "qa": np.zeros(test_data.latitude.shape),
            "test": np.zeros(test_data.latitude.shape),
        }
        scene_name = test_data.scene_name
        if scene_name not in ["Ocean_Day", "Ocean_Night", "Polar_Day_Ocean", "Polar_Night_Ocean"]:
            assert True

        scene_type = tst.CloudTests(data=test_data, scene_name=scene_name, thresholds=thresholds)

        cmin, bits = scene_type.bt_diff_86_11um("M14-M15", cmin, bits)
        return {"cmin": cmin, "bits": bits}

    def test_qa_bit(self, run_86_11um_diff_test, reference):
        """Test qa bit value."""
        assert np.allclose(
            run_86_11um_diff_test["bits"]["qa"], reference.qa_bit_86_11um_diff.values
        )

    def test_test_bit(self, run_86_11um_diff_test, reference):
        """Test test bit value."""
        assert np.allclose(
            run_86_11um_diff_test["bits"]["test"], reference.test_bit_86_11um_diff.values
        )

    def test_confidence(self, run_86_11um_diff_test, reference):
        """Test confidence value."""
        assert np.allclose(run_86_11um_diff_test["cmin"], reference.confidence_86_11um_diff.values)


class Test11Minus12umBTTest:
    """Test bt_diff_11_12um function."""

    @pytest.fixture(scope="class")
    def run_11_12um_diff_test(self, test_data, thresholds):
        """Run the bt_diff_11_12um function."""
        cmin = np.ones(test_data.latitude.shape)
        bits = {
            "qa": np.zeros(test_data.latitude.shape),
            "test": np.zeros(test_data.latitude.shape),
        }
        scene_name = test_data.scene_name
        if scene_name not in [
            "Land_Day",
            "Land_Day_Coast",
            "Land_Day_Desert",
            "Land_Day_Desert_Coast",
            "Ocean_Day",
            "Ocean_Night",
            "Polar_Day_Ocean",
            "Polar_Night_Ocean",
            "Polar_Day_Land",
            "Polar_Day_Coast",
            "Polar_Day_Desert",
            "Polar_Day_Desert_Coast",
            "Polar_Day_Snow",
            "Land_Night",
            "Polar_Night_Land",
            "Polar_Night_Snow",
            "Day_Snow",
            "Night_Snow",
        ]:
            assert True

        scene_type = tst.CloudTests(data=test_data, scene_name=scene_name, thresholds=thresholds)

        cmin, bits = scene_type.test_11_12um_diff("M15-M16", cmin, bits)
        return {"cmin": cmin, "bits": bits}

    def test_qa_bit(self, run_11_12um_diff_test, reference):
        """Test qa bit value."""
        assert np.allclose(
            run_11_12um_diff_test["bits"]["qa"], reference.qa_bit_11_12um_diff.values
        )

    def test_test_bit(self, run_11_12um_diff_test, reference):
        """Test test bit value."""
        assert np.allclose(
            run_11_12um_diff_test["bits"]["test"], reference.test_bit_11_12um_diff.values
        )

    def test_confidence(self, run_11_12um_diff_test, reference):
        """Test confidence value."""
        assert np.allclose(run_11_12um_diff_test["cmin"], reference.confidence_11_12um_diff.values)


def test_bt_difference_11_4um_test_ocean():
    """Test bt_difference_11_4um_test_ocean function."""
    pass


def test_bt_difference_11_4um_test_land():
    """Test bt_difference_11_4um_test_land function."""
    pass


class Test11umVariabilityTest:
    """Test variability_11um_test function."""

    @pytest.fixture(scope="class")
    def run_variability_11um_test(self, test_data, thresholds):
        """Run the variability_11um_test function."""
        cmin = np.ones(test_data.latitude.shape)
        bits = {
            "qa": np.zeros(test_data.latitude.shape),
            "test": np.zeros(test_data.latitude.shape),
        }
        scene_name = test_data.scene_name
        if scene_name not in ["Polar_Day_Ocean", "Polar_Night_Ocean"]:
            assert True

        scene_type = tst.CloudTests(data=test_data, scene_name=scene_name, thresholds=thresholds)

        cmin, bits = scene_type.variability_11um_test("M15", cmin, bits)
        return {"cmin": cmin, "bits": bits}

    def test_qa_bit(self, run_variability_11um_test, reference):
        """Test qa bit value."""
        assert np.allclose(
            run_variability_11um_test["bits"]["qa"], reference.qa_bit_variability_11um.values
        )

    def test_test_bit(self, run_variability_11um_test, reference):
        """Test test bit value."""
        assert np.allclose(
            run_variability_11um_test["bits"]["test"], reference.test_bit_variability_11um.values
        )

    def test_confidence(self, run_variability_11um_test, reference):
        """Test confidence value."""
        assert np.allclose(
            run_variability_11um_test["cmin"], reference.confidence_variability_11um.values
        )


class TestOceanicStratus11Minus4umTest:
    """Test bt_diff_11_4um function."""

    @pytest.fixture(scope="class")
    def run_oceanic_stratus_11_4um_test(self, test_data, thresholds):
        """Run the bt_diff_11_4um function."""
        cmin = np.ones(test_data.latitude.shape)
        bits = {
            "qa": np.zeros(test_data.latitude.shape),
            "test": np.zeros(test_data.latitude.shape),
        }
        scene_name = test_data.scene_name
        if scene_name not in [
            "Land_Day",
            "Land_Day_Coast",
            "Land_Day_Desert",
            "Land_Day_Desert_Coast",
            "Ocean_Day",
            "Ocean_Night",
            "Polar_Day_Land",
            "Polar_Day_Coast",
            "Polar_Day_Desert",
            "Polar_Day_Desert_Coast",
            "Polar_Day_Ocean",
            "Polar_Night_Ocean",
        ]:
            assert True

        scene_type = tst.CloudTests(data=test_data, scene_name=scene_name, thresholds=thresholds)

        cmin, bits = scene_type.oceanic_stratus_11_4um_test("M15-M12", cmin, bits)
        return {"cmin": cmin, "bits": bits}

    def test_qa_bit(self, run_oceanic_stratus_11_4um_test, reference):
        """Test qa bit value."""
        assert np.allclose(
            run_oceanic_stratus_11_4um_test["bits"]["qa"],
            reference.qa_bit_oceanic_stratus_11_4um.values,
        )

    def test_test_bit(self, run_oceanic_stratus_11_4um_test, reference):
        """Test test bit value."""
        assert np.allclose(
            run_oceanic_stratus_11_4um_test["bits"]["test"],
            reference.test_bit_oceanic_stratus_11_4um.values,
        )

    def test_confidence(self, run_oceanic_stratus_11_4um_test, reference):
        """Test confidence value."""
        assert np.allclose(
            run_oceanic_stratus_11_4um_test["cmin"],
            reference.confidence_oceanic_stratus_11_4um.values,
        )


class TestNIRReflectanceTest:
    """Test nir_reflectance_test function."""

    @pytest.fixture(scope="class")
    def run_nir_reflectance_test(self, test_data, thresholds):
        """Run the nir_reflectance_test function."""
        cmin = np.ones(test_data.latitude.shape)
        bits = {
            "qa": np.zeros(test_data.latitude.shape),
            "test": np.zeros(test_data.latitude.shape),
        }
        scene_name = test_data.scene_name
        if scene_name not in ["Ocean_Day", "Polar_Day_Ocean"]:
            assert True

        scene_type = tst.CloudTests(data=test_data, scene_name=scene_name, thresholds=thresholds)

        cmin, bits = scene_type.nir_reflectance_test("M07", cmin, bits)
        return {"cmin": cmin, "bits": bits}

    def test_qa_bit(self, run_nir_reflectance_test, reference):
        """Test qa bit value."""
        assert np.allclose(
            run_nir_reflectance_test["bits"]["qa"], reference.qa_bit_nir_reflectance.values
        )

    def test_test_bit(self, run_nir_reflectance_test, reference):
        """Test test bit value."""
        assert np.allclose(
            run_nir_reflectance_test["bits"]["test"], reference.test_bit_nir_reflectance.values
        )

    def test_confidence(self, run_nir_reflectance_test, reference):
        """Test confidence value."""
        assert np.allclose(
            run_nir_reflectance_test["cmin"], reference.confidence_nir_reflectance.values
        )


class TestVisNirRatioTest:
    """Test vis_nir_ratio_test function."""

    @pytest.fixture(scope="class")
    def run_vis_nir_ratio_test(self, test_data, thresholds):
        """Run the vis_nir_ratio_test function."""
        cmin = np.ones(test_data.latitude.shape)
        bits = {
            "qa": np.zeros(test_data.latitude.shape),
            "test": np.zeros(test_data.latitude.shape),
        }
        scene_name = test_data.scene_name
        if scene_name not in ["Ocean_Day", "Polar_Day_Ocean"]:
            assert True

        scene_type = tst.CloudTests(data=test_data, scene_name=scene_name, thresholds=thresholds)

        cmin, bits = scene_type.vis_nir_ratio_test("M07-M05ratio", cmin, bits)
        return {"cmin": cmin, "bits": bits}

    def test_qa_bit(self, run_vis_nir_ratio_test, reference):
        """Test qa bit value."""
        assert np.allclose(
            run_vis_nir_ratio_test["bits"]["qa"], reference.qa_bit_vis_nir_ratio.values
        )

    def test_test_bit(self, run_vis_nir_ratio_test, reference):
        """Test test bit value."""
        assert np.allclose(
            run_vis_nir_ratio_test["bits"]["test"], reference.test_bit_vis_nir_ratio.values
        )

    def test_confidence(self, run_vis_nir_ratio_test, reference):
        """Test confidence value."""
        assert np.allclose(
            run_vis_nir_ratio_test["cmin"], reference.confidence_vis_nir_ratio.values
        )


class Test16Minus21umReflectanceTest:
    """Test 16_21um_reflectance_test function."""

    @pytest.fixture(scope="class")
    def run_16_21um_reflectance_test(self, test_data, thresholds):
        """Run the 16_21um_reflectance_test function."""
        cmin = np.ones(test_data.latitude.shape)
        bits = {
            "qa": np.zeros(test_data.latitude.shape),
            "test": np.zeros(test_data.latitude.shape),
        }
        scene_name = test_data.scene_name
        if scene_name not in ["Ocean_Day", "Polar_Day_Ocean"]:
            assert True

        scene_type = tst.CloudTests(data=test_data, scene_name=scene_name, thresholds=thresholds)

        cmin, bits = scene_type.test_16_21um_reflectance("M10", cmin, bits)
        return {"cmin": cmin, "bits": bits}

    def test_qa_bit(self, run_16_21um_reflectance_test, reference):
        """Test qa bit value."""
        assert np.allclose(
            run_16_21um_reflectance_test["bits"]["qa"], reference.qa_bit_16_21um_reflectance.values
        )

    def test_test_bit(self, run_16_21um_reflectance_test, reference):
        """Test test bit value."""
        assert np.allclose(
            run_16_21um_reflectance_test["bits"]["test"],
            reference.test_bit_16_21um_reflectance.values,
        )

    def test_confidence(self, run_16_21um_reflectance_test, reference):
        """Test confidence value."""
        assert np.allclose(
            run_16_21um_reflectance_test["cmin"], reference.confidence_16_21um_reflectance.values
        )


class TestVisibleReflectanceTest:
    """Test visible_reflectance_test function."""

    @pytest.fixture(scope="class")
    def run_visible_reflectance_test(self, test_data, thresholds):
        """Run the visible_reflectance_test function."""
        cmin = np.ones(test_data.latitude.shape)
        bits = {
            "qa": np.zeros(test_data.latitude.shape),
            "test": np.zeros(test_data.latitude.shape),
        }
        scene_name = test_data.scene_name
        if scene_name not in [
            "Land_Day",
            "Land_Day_Coast",
            "Land_Day_Desert",
            "Land_Day_Desert_Coast",
            "Polar_Day_Land",
            "Polar_Day_Coast",
            "Polar_Day_Desert",
            "Polar_Day_Desert_Coast",
        ]:
            assert True

        scene_type = tst.CloudTests(data=test_data, scene_name=scene_name, thresholds=thresholds)

        cmin, bits = scene_type.visible_reflectance_test("M128", cmin, bits)
        return {"cmin": cmin, "bits": bits}

    def test_qa_bit(self, run_visible_reflectance_test, reference):
        """Test qa bit value."""
        assert np.allclose(
            run_visible_reflectance_test["bits"]["qa"], reference.qa_bit_vis_refl.values
        )

    def test_test_bit(self, run_visible_reflectance_test, reference):
        """Test test bit value."""
        assert np.allclose(
            run_visible_reflectance_test["bits"]["test"], reference.test_bit_vis_refl.values
        )

    def test_confidence(self, run_visible_reflectance_test, reference):
        """Test confidence value."""
        assert np.allclose(
            run_visible_reflectance_test["cmin"], reference.confidence_vis_refl.values
        )


class TestGEMI:
    """Test GEMI function."""

    @pytest.fixture(scope="class")
    def run_gemi(self, test_data, thresholds):
        """Run the GEMI function."""
        cmin = np.ones(test_data.latitude.shape)
        bits = {
            "qa": np.zeros(test_data.latitude.shape),
            "test": np.zeros(test_data.latitude.shape),
        }
        scene_name = test_data.scene_name
        if scene_name not in ["Land_Day_Desert", "Polar_Day_Desert"]:
            assert True

        scene_type = tst.CloudTests(data=test_data, scene_name=scene_name, thresholds=thresholds)

        cmin, bits = scene_type.gemi_test("GEMI", cmin, bits)
        return {"cmin": cmin, "bits": bits}

    def test_qa_bit(self, run_gemi, reference):
        """Test qa bit value."""
        assert np.allclose(run_gemi["bits"]["qa"], reference.qa_bit_gemi.values)

    def test_test_bit(self, run_gemi, reference):
        """Test test bit value."""
        assert np.allclose(run_gemi["bits"]["test"], reference.test_bit_gemi.values)

    def test_confidence(self, run_gemi, reference):
        """Test confidence value."""
        assert np.allclose(run_gemi["cmin"], reference.confidence_gemi.values)


class Test138umHighCloudsTest:
    """Test 1_38um_high_clouds_test function."""

    @pytest.fixture(scope="class")
    def run_138um_high_clouds_test(self, test_data, thresholds):
        """Run the 1_38um_high_clouds_test function."""
        cmin = np.ones(test_data.latitude.shape)
        bits = {
            "qa": np.zeros(test_data.latitude.shape),
            "test": np.zeros(test_data.latitude.shape),
        }
        scene_name = test_data.scene_name
        if scene_name not in [
            "Land_Day",
            "Land_Day_Coast",
            "Land_Day_Desert",
            "Land_Day_Desert_Coast",
            "Polar_Day_Land",
            "Polar_Day_Coast",
            "Polar_Day_Desert",
            "Polar_Day_Desert_Coast",
            "Day_Snow",
            "Ocean_Day",
            "Polar_Day_Ocean",
        ]:
            assert True

        scene_type = tst.CloudTests(data=test_data, scene_name=scene_name, thresholds=thresholds)

        cmin, bits = scene_type.test_1_38um_high_clouds("M09", cmin, bits)
        return {"cmin": cmin, "bits": bits}

    def test_qa_bit(self, run_138um_high_clouds_test, reference):
        """Test qa bit value."""
        assert np.allclose(
            run_138um_high_clouds_test["bits"]["qa"], reference.qa_bit_high_clouds.values
        )

    def test_test_bit(self, run_138um_high_clouds_test, reference):
        """Test test bit value."""
        assert np.allclose(
            run_138um_high_clouds_test["bits"]["test"], reference.test_bit_high_clouds.values
        )

    def test_confidence(self, run_138um_high_clouds_test, reference):
        """Test confidence value."""
        assert np.allclose(
            run_138um_high_clouds_test["cmin"], reference.confidence_high_clouds.values
        )


class TestThinCirrusTest:
    """Test thin_cirrus_4_12um_BTD_test function."""

    @pytest.fixture(scope="class")
    def run_4_12um_thin_cirrus_btd(self, test_data, thresholds):
        """Run the thin_cirrus_4_12um_BTD_test function."""
        cmin = np.ones(test_data.latitude.shape)
        bits = {
            "qa": np.zeros(test_data.latitude.shape),
            "test": np.zeros(test_data.latitude.shape),
        }
        scene_name = test_data.scene_name
        if scene_name not in [
            "Land_Night",
            "Polar_Night_Land",
            "Polar_Night_Snow",
            "Night_Snow",
        ]:
            assert True

        scene_type = tst.CloudTests(data=test_data, scene_name=scene_name, thresholds=thresholds)

        cmin, bits = scene_type.thin_cirrus_4_12um_BTD_test("M13-M16", cmin, bits)
        return {"cmin": cmin, "bits": bits}

    def test_qa_bit(self, run_4_12um_thin_cirrus_btd, reference):
        """Test qa bit value."""
        assert np.allclose(
            run_4_12um_thin_cirrus_btd["bits"]["qa"], reference.qa_bit_thin_cirrus.values
        )

    def test_test_bit(self, run_4_12um_thin_cirrus_btd, reference):
        """Test test bit value."""
        assert np.allclose(
            run_4_12um_thin_cirrus_btd["bits"]["test"], reference.test_bit_thin_cirrus.values
        )

    def test_confidence(self, run_4_12um_thin_cirrus_btd, reference):
        """Test confidence value."""
        assert np.allclose(
            run_4_12um_thin_cirrus_btd["cmin"], reference.confidence_thin_cirrus.values
        )