示例#1
0
def test_ckd_basic(modes_all_ckd):
    """
    CKD correctness check
    =====================

    We check for correctness when using CKD modes with atmosphere-free scenes.
    This test is designed to check that the CKD infrastructure
    (preprocessing, spectral loop, postprocessing) works.
    """

    # Configure experiment, run and postprocess results
    exp = OneDimExperiment(
        atmosphere=None,
        surface=LambertianSurface(reflectance=1.0),
        measures=[
            MultiDistantMeasure.from_viewing_angles(
                zeniths=np.arange(-60, 61, 5) * ureg.deg,
                azimuths=0.0 * ureg.deg,
                spectral_cfg={
                    "bin_set": "10nm",
                    "bins": [
                        "550",
                        "560",
                        "570",
                        "510",
                    ],  # We specify bins in arbitrary order on purpose
                },
            )
        ],
    )
    exp.run()

    # Reflectance is uniform, equal to 1
    assert np.allclose(exp.results["measure"].data_vars["brf"], 1.0)
示例#2
0
def test_add_illumination(modes_all_single, illumination_type, expected_dims):
    # Initialise test data
    if eradiate.mode().has_flags(ModeFlags.ANY_MONO):
        spectral_cfg = {"wavelengths": [540.0, 550.0, 560.0]}
    elif eradiate.mode().has_flags(ModeFlags.ANY_CKD):
        spectral_cfg = {"bins": ["540", "550", "560"]}
    else:
        pytest.skip(f"Please add test for '{eradiate.mode().id}' mode")

    exp = OneDimExperiment(
        atmosphere=None,
        illumination={"type": illumination_type},
        measures=MultiDistantMeasure(spectral_cfg=spectral_cfg),
    )
    exp.process()
    measure = exp.measures[0]

    # Apply basic post-processing
    values = Pipeline(steps=[
        ("gather", Gather(var="radiance")),
        ("aggregate_ckd_quad",
         AggregateCKDQuad(var="radiance", measure=measure)),
    ]).transform(measure.results)

    step = AddIllumination(illumination=exp.illumination, measure=measure)
    result = step.transform(values)
    # Irradiance is here and is indexed in Sun angles and spectral coordinate
    irradiance = result.data_vars["irradiance"]
    assert set(irradiance.dims) == {"w"}.union(set(expected_dims))
示例#3
0
def test_add_srf(modes_all_single):
    if eradiate.mode().has_flags(ModeFlags.ANY_MONO):
        spectral_cfg = {"wavelengths": [550.0]}
    elif eradiate.mode().has_flags(ModeFlags.ANY_CKD):
        spectral_cfg = {"bins": ["550"]}
    else:
        pytest.skip(f"Please add test for '{eradiate.mode().id}' mode")

    exp = OneDimExperiment(
        atmosphere=None,
        measures=MultiDistantMeasure.from_viewing_angles(
            zeniths=[-60, -45, 0, 45, 60],
            azimuths=0.0,
            spp=1,
            spectral_cfg=spectral_cfg,
        ),
    )
    exp.process()
    measure = exp.measures[0]

    # Apply basic post-processing
    values = Pipeline([
        Gather(var="radiance"),
        AggregateCKDQuad(var="radiance", measure=measure)
    ]).transform(measure.results)

    step = AddSpectralResponseFunction(measure=measure)
    result = step.transform(values)

    # The spectral response function is added to the dataset as a data variable
    assert "srf" in result.data_vars
    # Its only dimension is wavelength
    assert set(result.srf.dims) == {"srf_w"}
示例#4
0
def test_add_viewing_angles(mode_mono, measure_type, expected_zenith,
                            expected_azimuth):
    # Initialise test data
    if measure_type == "multi_distant-nohplane":
        measure = MultiDistantMeasure.from_viewing_angles(
            zeniths=[-60, -45, 0, 45, 60],
            azimuths=0.0,
            auto_hplane=False,
            spp=1,
        )

    elif measure_type == "multi_distant-hplane":
        measure = MultiDistantMeasure.from_viewing_angles(
            zeniths=[-60, -45, 0, 45, 60],
            azimuths=0.0,
            auto_hplane=True,
            spp=1,
        )

    elif measure_type == "hemispherical_distant":
        measure = HemisphericalDistantMeasure(
            film_resolution=(2, 2),
            spp=1,
        )

    else:
        assert False

    exp = OneDimExperiment(atmosphere=None, measures=measure)
    exp.process()
    measure = exp.measures[0]

    # Apply basic post-processing
    values = Gather(var="radiance").transform(measure.results)

    step = AddViewingAngles(measure=measure)
    result = step.transform(values)

    # Produced dataset has viewing angle coordinates
    assert "vza" in result.coords
    assert "vaa" in result.coords

    # Viewing angles are set to appropriate values
    assert np.allclose(expected_zenith, result.coords["vza"].values.squeeze())
    assert np.allclose(expected_azimuth, result.coords["vaa"].values.squeeze())
示例#5
0
def test_spectral_loop(mode_mono, cls, wavelengths, irradiance):
    """
    Spectral loop
    =============

    This test case checks if the spectral loop implementation and
    post-processing behaves as intended.

    Rationale
    ---------

    The scene consists of a square Lambertian surface with reflectance
    :math:`\\rho = 1` illuminated by a directional emitter positioned at the
    zenith. The reflected radiance is computed in monochromatic mode for a
    single wavelength and for multiple wavelength. The experiment is repeated:

    * for all solver applications supporting this type of scene;
    * for several spectral configurations (single wavenlength, multiple
      ascending, multiple descending);
    * for several irradiance spectra (uniform, solar).

    Expected behaviour
    ------------------

    All BRF values are equal to 1.
    """
    if cls == "onedim":
        cls_exp = OneDimExperiment
        kwargs = {"atmosphere": None}
    elif cls == "rami":
        cls_exp = RamiExperiment
        kwargs = {"canopy": None}
    else:
        raise ValueError

    if irradiance == "uniform":
        illumination = DirectionalIllumination(irradiance=1.0)
    elif irradiance == "solar":
        illumination = DirectionalIllumination(
            irradiance=SolarIrradianceSpectrum())

    exp = cls_exp(
        surface=LambertianSurface(reflectance=1.0),
        illumination=illumination,
        measures=[
            MultiDistantMeasure(
                spp=1,
                spectral_cfg={"wavelengths": wavelengths},
            )
        ],
        **kwargs,
    )

    exp.run()
    assert np.allclose(np.squeeze(exp.results["measure"].brf.values), 1.0)
示例#6
0
def test_rami4atm_experiment_construct_normalize_measures(mode_mono, padding):

    # When canopy is not None, measure target matches canopy unit cell
    exp = Rami4ATMExperiment(
        atmosphere=None,
        canopy=DiscreteCanopy.homogeneous(
            lai=3.0,
            leaf_radius=0.1 * ureg.m,
            l_horizontal=10.0 * ureg.m,
            l_vertical=2.0 * ureg.m,
            padding=padding,
        ),
        measures=MultiDistantMeasure(),
    )
    target = exp.measures[0].target
    canopy = exp.canopy
    assert np.isclose(target.xmin, -0.5 * canopy.size[0])
    assert np.isclose(target.xmax, 0.5 * canopy.size[0])
    assert np.isclose(target.ymin, -0.5 * canopy.size[1])
    assert np.isclose(target.ymax, 0.5 * canopy.size[1])
    assert np.isclose(target.z, canopy.size[2])

    # The measure target does not depend on the atmosphere
    exp = Rami4ATMExperiment(
        atmosphere=HomogeneousAtmosphere(width=ureg.Quantity(42.0, "km")),
        canopy=DiscreteCanopy.homogeneous(
            lai=3.0,
            leaf_radius=0.1 * ureg.m,
            l_horizontal=10.0 * ureg.m,
            l_vertical=2.0 * ureg.m,
            padding=padding,
        ),
        measures=MultiDistantMeasure(),
    )
    target = exp.measures[0].target
    canopy = exp.canopy
    assert np.isclose(target.xmin, -0.5 * canopy.size[0])
    assert np.isclose(target.xmax, 0.5 * canopy.size[0])
    assert np.isclose(target.ymin, -0.5 * canopy.size[1])
    assert np.isclose(target.ymax, 0.5 * canopy.size[1])
    assert np.isclose(target.z, canopy.size[2])
示例#7
0
def test_onedim_experiment_construct_measures(modes_all):
    """
    A variety of measure specifications are acceptable
    """
    # Init with a single measure (not wrapped in a sequence)
    assert OneDimExperiment(measures=MultiDistantMeasure())

    # Init from a dict-based measure spec
    # -- Correctly wrapped in a sequence
    assert OneDimExperiment(measures=[{"type": "distant"}])
    # -- Not wrapped in a sequence
    assert OneDimExperiment(measures={"type": "distant"})
示例#8
0
def test_rami_experiment_construct_normalize_measures(mode_mono, padding):
    """
    When canopy is not None, measure target matches canopy unit cell
    """
    exp = RamiExperiment(
        canopy=DiscreteCanopy.homogeneous(
            lai=3.0,
            leaf_radius=0.1 * ureg.m,
            l_horizontal=10.0 * ureg.m,
            l_vertical=2.0 * ureg.m,
            padding=padding,
        ),
        measures=MultiDistantMeasure(),
    )
    target = exp.measures[0].target
    canopy = exp.canopy
    assert np.isclose(target.xmin, -0.5 * canopy.size[0])
    assert np.isclose(target.xmax, 0.5 * canopy.size[0])
    assert np.isclose(target.ymin, -0.5 * canopy.size[1])
    assert np.isclose(target.ymax, 0.5 * canopy.size[1])
示例#9
0
def test_apply_spectral_response_function_transform(mode_id, spectral_cfg):
    """
    Unit tests for ApplySpectralResponseFunction.transform().
    """
    # Prepare basic data
    eradiate.set_mode(mode_id)

    exp = OneDimExperiment(
        atmosphere=None,
        measures=MultiDistantMeasure.from_viewing_angles(
            id="measure",
            zeniths=[-60, -45, 0, 45, 60],
            azimuths=0.0,
            spp=1,
            spectral_cfg=spectral_cfg,
        ),
    )
    measure = exp.measures[0]
    exp.process(measure)

    # Apply first steps of post-processing
    pipeline = exp.pipeline(measure)
    values = pipeline.transform(measure.results, stop_after="add_viewing_angles")

    # Apply tested pipeline step
    step = ApplySpectralResponseFunction(measure=measure, vars=["radiance"])

    if eradiate.mode().has_flags(ModeFlags.ANY_MONO):
        # In mono modes, the dataset produced by previous steps is missing
        # bin data required for the step to run successfully
        with pytest.raises(ValueError):
            step.transform(values)
        return

    # In binned modes, computation goes through
    result = step.transform(values)

    # The step adds a SRF-weighted variable
    assert "radiance_srf" in result.data_vars
    assert np.all(result.radiance_srf > 0.0)