Source code for eradiate.scenes.biosphere._rami_scenarios

from __future__ import annotations

import itertools
from enum import Enum
from pathlib import Path
from typing import Optional, Union
from urllib.parse import urljoin

import pooch

from ._canopy_loader import load_scenario

_DATA_URL_ROOT = "https://eradiate.eu/data/store/unstable/scenarios/rami5/"


[docs] class RAMIActualCanopies(Enum): """Enumeration of RAMI actual canopies.""" JARVSELJA_PINE_STAND = "HET07_JPS_SUM" # Summer OFENPASS_PINE_STAND = "HET08_OPS_WIN" # Winter JARVSELJA_BIRCH_STAND_SUMMER = "HET09_JBS_SUM" # Summer WELLINGTON_CITRUS_ORCHARD = "HET14_WCO_UND" JARVSELJA_BIRCH_STAND_WINTER = "HET15_JBS_WIN" # Winter AGRICULTURAL_CROPS = "HET16_SRF_UND" # Short Rotation Forest SAVANNA_PRE_FIRE = "HET50_SAV_PRE" # Semi-empirical WYTHAM_WOOD = "HET51_WWO_TLS" # Empirical
[docs] class RAMIHeterogeneousAbstractCanopies(Enum): """Enumeration of RAMI heterogeneous abstract canopies.""" ANISOTROPIC_BACKGROUND_OVERSTOREY_SPARSE_BRF_MODEL_A = "HET10_DIS_S1A" ANISOTROPIC_BACKGROUND_OVERSTOREY_SPARSE_BRF_MODEL_B = "HET11_DIS_S1B" ANISOTROPIC_BACKGROUND_OVERSTOREY_SPARSE_BRF_MODEL_C = "HET12_DIS_S1C" ANISOTROPIC_BACKGROUND_OVERSTOREY_DENSE_BRF_MODEL_A = "HET20_DIS_D1A" ANISOTROPIC_BACKGROUND_OVERSTOREY_DENSE_BRF_MODEL_B = "HET21_DIS_D1B" ANISOTROPIC_BACKGROUND_OVERSTOREY_DENSE_BRF_MODEL_C = "HET22_DIS_D1C" TWO_LAYER_CANOPY_OVERSTORIES_SPARSE_UNDERSTORIES_SPARSE = "HET16_DIS_S2S" TWO_LAYER_CANOPY_OVERSTORIES_MEDIUM_UNDERSTORIES_SPARSE = "HET17_DIS_M2S" TWO_LAYER_CANOPY_OVERSTORIES_DENSE_UNDERSTORIES_SPARSE = "HET18_DIS_D2S" TWO_LAYER_CANOPY_OVERSTORIES_SPARSE_UNDERSTORIES_DENSE = "HET26_DIS_S2D" TWO_LAYER_CANOPY_OVERSTORIES_MEDIUM_UNDERSTORIES_DENSE = "HET27_DIS_M2D" TWO_LAYER_CANOPY_OVERSTORIES_DENSE_UNDERSTORIES_DENSE = "HET28_DIS_D2D" CONSTANT_SLOPE_DISTRIBUTION_SPARSE_INCLINATION_15 = "HET23_DIS_S15" CONSTANT_SLOPE_DISTRIBUTION_DENSE_INCLINATION_15 = "HET24_DIS_D15" CONSTANT_SLOPE_DISTRIBUTION_SPARSE_INCLINATION_30 = "HET33_DIS_S30" CONSTANT_SLOPE_DISTRIBUTION_DENSE_INCLINATION_30 = "HET34_DIS_D30"
[docs] class RAMIHomogeneousAbstractCanopies(Enum): """Enumeration of RAMI homogeneous abstract canopies.""" ANISOTROPIC_BACKGROUND_PLANOPHILE_A = "HOM23_DIS_P1A" ANISOTROPIC_BACKGROUND_PLANOPHILE_B = "HOM24_DIS_P1B" ANISOTROPIC_BACKGROUND_PLANOPHILE_C = "HOM25_DIS_P1C" # ANISOTROPIC_BACKGROUND_ERECTOPHILE_A = "HOM33_DIS_E1A" ANISOTROPIC_BACKGROUND_ERECTOPHILE_B = "HOM34_DIS_E1B" ANISOTROPIC_BACKGROUND_ERECTOPHILE_C = "HOM35_DIS_E1C" TWO_LAYER_CANOPY_ERECTOPHILE_SPARSE_PLANOPHILE_DENSE = "HOM26_DIS_EPD" TWO_LAYER_CANOPY_ERECTOPHILE_SPARSE_PLANOPHILE_MEDIUM = "HOM27_DIS_EPM" TWO_LAYER_CANOPY_ERECTOPHILE_SPARSE_PLANOPHILE_SPARSE = "HOM28_DIS_EPS" TWO_LAYER_CANOPY_PLANOPHILE_SPARSE_ERECTOPHILE_DENSE = "HOM36_DIS_PED" TWO_LAYER_CANOPY_PLANOPHILE_SPARSE_ERECTOPHILE_MEDIUM = "HOM37_DIS_PEM" TWO_LAYER_CANOPY_PLANOPHILE_SPARSE_ERECTOPHILE_SPARSE = "HOM38_DIS_PES" ADJACENT_CANOPIES_SPARSE_ERECTOPHILE_DENSE_PLANOPHILE = "HOM29_DIS_EM0" ADJACENT_CANOPIES_MEDIUM_ERECTOPHILE_SPARSE_PLANOPHILE = "HOM30_DIS_ED0"
RAMICanopies = Union[ RAMIActualCanopies, RAMIHomogeneousAbstractCanopies, RAMIHeterogeneousAbstractCanopies, ] #: Type alias to a union of all RAMI canopy enumerations.
[docs] class RAMIScenarioVariant(Enum): """Enumeration of RAMI scenario variants (original or simplified).""" ORIGINAL = "original" SIMPLIFIED = "simplified"
def generate_name( scenario_name: RAMICanopies, variant: RAMIScenarioVariant = RAMIScenarioVariant.ORIGINAL, ) -> str: """ Generate a name for a scenario based on its name and variant. Parameters ---------- scenario_name : RAMIActualCanopies or RAMIHeterogeneousAbstractCanopies or RAMIHomogeneousAbstractCanopies The name of the scenario. variant : ScenarioVersion The variant of the scenario. Returns ------- str The name of the scenario. """ return ( f"{scenario_name.value}-{variant.value}" if variant == RAMIScenarioVariant.SIMPLIFIED else scenario_name.value ) def _convert_to_enum(scenario_name: str | RAMICanopies) -> RAMICanopies: """ Convert a scenario name to an enum if it is a string. Parameters ---------- scenario_name : str or RAMICanopies The name of the scenario. Returns ------- (RAMIActualCanopies | RAMIHeterogeneousAbstractCanopies | RAMIHomogeneousAbstractCanopies) The name of the scenario as an enum. """ if isinstance(scenario_name, str): for member in itertools.chain.from_iterable( [ RAMIActualCanopies, RAMIHeterogeneousAbstractCanopies, RAMIHomogeneousAbstractCanopies, ] ): if scenario_name == member.value: return member else: raise ValueError(f"Scenario {scenario_name} not found") else: return scenario_name
[docs] def load_rami_scenario( scenario_name: str | RAMICanopies, variant: RAMIScenarioVariant = RAMIScenarioVariant.ORIGINAL, padding: int = 0, unpack_folder: Optional[Path] = None, spectral_data: Optional[dict] = None, ) -> dict: """ Load a scenario based on its name and variant. This function will check if scenario data can be found at the target location; if not, it will download them automatically. Parameters ---------- scenario_name : str or RAMIActualCanopies or RAMIHeterogeneousAbstractCanopies or RAMIHomogeneousAbstractCanopies The name of the RAMI-V scenario. If a string is provided, it will automatically be converted to the appropriate enum. variant : RAMIScenarioVariant The variant of the scenario. padding : int, optional The padding to apply to the scenario, defaults to 0. unpack_folder : path-like, optional Directory where scenario data is expected to be stored — and where downloaded data will be unpacked. Defaults to ``$PWD``. spectral_data : dict[str, Any or dict[str, Any]] or None Spectral data to apply to the scenario, defaults to None (keep original). Returns ------- dict The scenario. See Also -------- load_scenario """ unpack_folder = Path.cwd() if unpack_folder is None else Path(unpack_folder) name = generate_name(_convert_to_enum(scenario_name), variant) fname = f"{name}.zip" # Check for data availability scenario_folder = unpack_folder / name if not (scenario_folder / "scenario.json").exists(): pooch.retrieve( urljoin(_DATA_URL_ROOT, fname), fname=fname, path=unpack_folder, processor=pooch.processors.Unzip(extract_dir=name), known_hash=None, progressbar=True, ) (unpack_folder / fname).unlink(missing_ok=True) # Load the scenario return load_scenario(scenario_folder, padding, spectral_data=spectral_data)