|
| 1 | +from __future__ import annotations |
| 2 | + |
| 3 | +import logging |
| 4 | +from typing import Any, final |
| 5 | + |
| 6 | +from meteole.clients import BaseClient, MeteoFranceClient |
| 7 | +from meteole.forecast import WeatherForecast |
| 8 | + |
| 9 | +logger = logging.getLogger(__name__) |
| 10 | + |
| 11 | +AVAILABLE_ARPEGE_TERRITORY: list[str] = ["EUROPE", "GLOBE"] |
| 12 | + |
| 13 | +ARPEGE_INSTANT_INDICATORS: list[str] = [ |
| 14 | + "GEOMETRIC_HEIGHT__GROUND_OR_WATER_SURFACE", |
| 15 | + "ISOTHERMAL_LEVEL_TW27315__GROUND_OR_WATER_SURFACE", |
| 16 | + "ISOTHERMAL_LEVEL_TW27415__GROUND_OR_WATER_SURFACE", |
| 17 | + "ISOTHERMAL_LEVEL_TW27465__GROUND_OR_WATER_SURFACE", |
| 18 | + "ISOTHERMAL_LEVEL_T27315__GROUND_OR_WATER_SURFACE", |
| 19 | + "CLOUD_BASE_HEIGHT__GROUND_OR_WATER_SURFACE", |
| 20 | + "CONVECTIVE_AVAILABLE_POTENTIAL_ENERGY_MAX__GROUND_OR_WATER_SURFACE", |
| 21 | + "CONVECTIVE_AVAILABLE_POTENTIAL_ENERGY_MODEL__GROUND_OR_WATER_SURFACE", |
| 22 | + "INHIBITION_CONVECTIVE__GROUND_OR_WATER_SURFACE", |
| 23 | + "TOTAL_WATER_VAPOUR__GROUND_OR_WATER_SURFACE", |
| 24 | + "DIVERGENCE__ISOBARIC_SURFACE", |
| 25 | + "RELATIVE_HUMIDITY__SPECIFIC_HEIGHT_LEVEL_ABOVE_GROUND", |
| 26 | + "RELATIVE_HUMIDITY__ISOBARIC_SURFACE", |
| 27 | + "PLANETARY_BOUNDARY_LAYER_HEIGHT__GROUND_OR_WATER_SURFACE", |
| 28 | + "LIGHTNING_DENSITY_MEAN_3H__GROUND_OR_WATER_SURFACE", |
| 29 | + "CONVECTIVE_AVAILABLE_POTENTIAL_ENERGY_MEAN_LAYER__GROUND_OR_WATER_SURFACE", |
| 30 | + "LOW_CLOUD_COVER__GROUND_OR_WATER_SURFACE", |
| 31 | + "CONVECTIVE_CLOUD_COVER__GROUND_OR_WATER_SURFACE", |
| 32 | + "HIGH_CLOUD_COVER__GROUND_OR_WATER_SURFACE", |
| 33 | + "MEDIUM_CLOUD_COVER__GROUND_OR_WATER_SURFACE", |
| 34 | + "TOTAL_CLOUD_COVER__GROUND_OR_WATER_SURFACE", |
| 35 | + "PRESSURE__GROUND_OR_WATER_SURFACE", |
| 36 | + "PRESSURE__MEAN_SEA_LEVEL", |
| 37 | + "POTENTIAL_TEMPERATURE__POTENTIAL_VORTICITY_SURFACE_1500", |
| 38 | + "POTENTIAL_TEMPERATURE__POTENTIAL_VORTICITY_SURFACE_2000", |
| 39 | + "MAXIMUM_TEMPERATURE__SPECIFIC_HEIGHT_LEVEL_ABOVE_GROUND", |
| 40 | + "MINIMUM_TEMPERATURE__SPECIFIC_HEIGHT_LEVEL_ABOVE_GROUND", |
| 41 | + "PSEUDO_ADIABATIC_POTENTIAL_TEMPERATURE__ISOBARIC_SURFACE", |
| 42 | + "TEMPERATURE__GROUND_OR_WATER_SURFACE", |
| 43 | + "TEMPERATURE__SPECIFIC_HEIGHT_LEVEL_ABOVE_GROUND", |
| 44 | + "TEMPERATURE__ISOBARIC_SURFACE", |
| 45 | + "U_COMPONENT_OF_WIND_GUST__SPECIFIC_HEIGHT_LEVEL_ABOVE_GROUND", |
| 46 | + "U_COMPONENT_OF_WIND__SPECIFIC_HEIGHT_LEVEL_ABOVE_GROUND", |
| 47 | + "U_COMPONENT_OF_WIND__ISOBARIC_SURFACE", |
| 48 | + "U_COMPONENT_OF_WIND__POTENTIAL_VORTICITY_SURFACE_1500", |
| 49 | + "U_COMPONENT_OF_WIND__POTENTIAL_VORTICITY_SURFACE_2000", |
| 50 | + "MINIMUM_VISIBILITY_180_PRECIPITATING_HYDROMETEORS__GROUND_OR_WATER_SURFACE", |
| 51 | + "MINIMUM_VISIBILITY_PRECIPITATING_HYDROMETEORS__GROUND_OR_WATER_SURFACE", |
| 52 | + "MINIMUM_VISIBILITY_180_NON_PRECIPITATING_HYDROMETEORS__GROUND_OR_WATER_SURFACE", |
| 53 | + "MINIMUM_VISIBILITY_NON_PRECIPITATING_HYDROMETEORS__GROUND_OR_WATER_SURFACE", |
| 54 | + "VERTICAL_VELOCITY_PRESSURE__ISOBARIC_SURFACE", |
| 55 | + "V_COMPONENT_OF_WIND_GUST__SPECIFIC_HEIGHT_LEVEL_ABOVE_GROUND", |
| 56 | + "V_COMPONENT_OF_WIND__SPECIFIC_HEIGHT_LEVEL_ABOVE_GROUND", |
| 57 | + "V_COMPONENT_OF_WIND__ISOBARIC_SURFACE", |
| 58 | + "V_COMPONENT_OF_WIND__POTENTIAL_VORTICITY_SURFACE_1500", |
| 59 | + "V_COMPONENT_OF_WIND__POTENTIAL_VORTICITY_SURFACE_2000", |
| 60 | + "GEOPOTENTIAL__ISOBARIC_SURFACE", |
| 61 | + "GEOPOTENTIAL__POTENTIAL_VORTICITY_SURFACE_1500", |
| 62 | + "GEOPOTENTIAL__POTENTIAL_VORTICITY_SURFACE_2000", |
| 63 | +] |
| 64 | + |
| 65 | +ARPEGE_OTHER_INDICATORS: list[str] = [ |
| 66 | + "TOTAL_WATER_PRECIPITATION__GROUND_OR_WATER_SURFACE", |
| 67 | + "LIGHTNING_DENSITY_CUMULATED__GROUND_OR_WATER_SURFACE", |
| 68 | + "TOTAL_SNOW_PRECIPITATION__GROUND_OR_WATER_SURFACE", |
| 69 | + "TOTAL_PRECIPITATION__GROUND_OR_WATER_SURFACE", |
| 70 | +] |
| 71 | + |
| 72 | + |
| 73 | +@final |
| 74 | +class ArpegePEForecast(WeatherForecast): |
| 75 | + """Access the ARPEGE numerical weather forecast data from Meteo-France API. |
| 76 | +
|
| 77 | + Doc: |
| 78 | + - https://portail-api.meteofrance.fr/web/fr/api/pe-arpege |
| 79 | +
|
| 80 | + Attributes: |
| 81 | + territory: Covered area (e.g., FRANCE, EUROPE, ...). |
| 82 | + precision: Precision value of the forecast. |
| 83 | + capabilities: DataFrame containing details on all available coverage ids. |
| 84 | + """ |
| 85 | + |
| 86 | + MODEL_NAME: str = "pearpege" |
| 87 | + BASE_ENTRY_POINT: str = "wcs/MF-NWP-GLOBAL-PEARP" |
| 88 | + MODEL_TYPE: str = "ENSEMBLE" |
| 89 | + ENSEMBLE_NUMBERS: int = 35 |
| 90 | + DEFAULT_TERRITORY: str = "EUROPE" |
| 91 | + RELATION_TERRITORY_TO_PREC_ARPEGE: dict[str, float] = {"EUROPE": 0.1, "GLOBE": 0.25} |
| 92 | + CLIENT_CLASS: type[BaseClient] = MeteoFranceClient |
| 93 | + INDICATORS: list[str] = ARPEGE_INSTANT_INDICATORS + ARPEGE_OTHER_INDICATORS |
| 94 | + INSTANT_INDICATORS: list[str] = ARPEGE_INSTANT_INDICATORS |
| 95 | + |
| 96 | + def __init__( |
| 97 | + self, |
| 98 | + client: BaseClient | None = None, |
| 99 | + *, |
| 100 | + territory: str = "EUROPE", |
| 101 | + **kwargs: Any, |
| 102 | + ): |
| 103 | + """Initializes an ArpegeForecast object. |
| 104 | +
|
| 105 | + The `precision` of the forecast is inferred from the specified `territory`. |
| 106 | +
|
| 107 | + Args: |
| 108 | + territory: The ARPEGE territory to fetch. Defaults to "EUROPE". |
| 109 | + api_key: The API key for authentication. Defaults to None. |
| 110 | + token: The API token for authentication. Defaults to None. |
| 111 | + application_id: The Application ID for authentication. Defaults to None. |
| 112 | +
|
| 113 | + Notes: |
| 114 | + - See `MeteoFranceClient` for additional details on the parameters `api_key`, `token`, |
| 115 | + and `application_id`. |
| 116 | + - Available territories are listed in the `AVAILABLE_TERRITORY` constant. |
| 117 | + """ |
| 118 | + super().__init__( |
| 119 | + client=client, |
| 120 | + territory=territory, |
| 121 | + precision=self.RELATION_TERRITORY_TO_PREC_ARPEGE[territory], |
| 122 | + **kwargs, |
| 123 | + ) |
| 124 | + |
| 125 | + def _validate_parameters(self) -> None: |
| 126 | + """Check the territory and the precision parameters. |
| 127 | +
|
| 128 | + Raise: |
| 129 | + ValueError: At least, one parameter is not good. |
| 130 | + """ |
| 131 | + if self.territory not in AVAILABLE_ARPEGE_TERRITORY: |
| 132 | + raise ValueError(f"The parameter precision must be in {AVAILABLE_ARPEGE_TERRITORY}") |
0 commit comments