Source code for eradiate.scenes.biosphere._rami_scenarios

from __future__ import annotations

import itertools
import typing
import zipfile
from enum import Enum
from pathlib import Path

from ._canopy_loader import load_scenario

DEFAULT_SCENARIO_FOLDER_NAME = ".scenarios"


[docs] class RAMIActualCanopies(Enum): 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): 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): 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"
[docs] class RAMIScenarioVersion(Enum): ORIGINAL = "original" SIMPLIFIED = "simplified"
def generate_name( scenario_name: ( RAMIActualCanopies | RAMIHeterogeneousAbstractCanopies | RAMIHomogeneousAbstractCanopies ), version: RAMIScenarioVersion = RAMIScenarioVersion.ORIGINAL, ) -> str: """ Generate a name for a scenario based on its name and version. Parameters ---------- scenario_name : RAMIActualCanopies or RAMIHeterogeneousAbstractCanopies or RAMIHomogeneousAbstractCanopies The name of the scenario. version : ScenarioVersion The version of the scenario. Returns ------- str The name of the scenario. """ return ( f"{scenario_name.value}-{version.value}" if version == RAMIScenarioVersion.SIMPLIFIED else scenario_name.value ) def _convert_to_enum( scenario_name: ( str | RAMIActualCanopies | RAMIHeterogeneousAbstractCanopies | RAMIHomogeneousAbstractCanopies ), ) -> ( RAMIActualCanopies | RAMIHeterogeneousAbstractCanopies | RAMIHomogeneousAbstractCanopies ): """ Convert a scenario name to an enum if it is a string. Parameters ---------- scenario_name : str or RAMIActualCanopies or RAMIHeterogeneousAbstractCanopies or RAMIHomogeneousAbstractCanopies 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 | RAMIActualCanopies | RAMIHeterogeneousAbstractCanopies | RAMIHomogeneousAbstractCanopies ), version: RAMIScenarioVersion = RAMIScenarioVersion.ORIGINAL, padding: int = 0, unpack_folder: typing.Optional[Path] = None, spectral_data: typing.Optional[dict] = None, ) -> dict: """ Load a scenario based on its name and version. 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. version : RAMIScenarioVersion The version of the scenario. padding : int, optional The padding to apply to the scenario, defaults to 0. unpack_folder : Path, optional The folder to unpack the scenario to, defaults to None (current working directory). spectral_data : dict[str, t.Any or dict[str, t.Any]] or None Spectral data to apply to the scenario, defaults to None (keep original). Returns ------- dict The scenario. """ from eradiate.data import data_store name = f"scenarios/rami5/{generate_name(_convert_to_enum(scenario_name), version)}" if unpack_folder is None: unpack_folder = Path.cwd() / DEFAULT_SCENARIO_FOLDER_NAME scenario_folder = unpack_folder / name if not scenario_folder.exists(): local_path = data_store.fetch(f"{name}.zip") # Unzip the scenario with zipfile.ZipFile(local_path, "r") as zip_ref: zip_ref.extractall(scenario_folder) # Load the scenario return load_scenario(scenario_folder, padding, spectral_data=spectral_data)