Source code for climada.util.dwd_icon_loader

"""
This file is part of CLIMADA.

Copyright (C) 2017 ETH Zurich, CLIMADA contributors listed in AUTHORS.

CLIMADA is free software: you can redistribute it and/or modify it under the
terms of the GNU General Public License as published by the Free
Software Foundation, version 3.

CLIMADA is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
PARTICULAR PURPOSE.  See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License along
with CLIMADA. If not, see <https://www.gnu.org/licenses/>.

---

Functions to download weather forecasts of the ICON weather forecast model
from the German Weather Service DWD (opendata.dwd.de). Currently used for wind
gust forecast in climada.hazard.storm_europe. Other parameters like rainfall or
temperature are available.
"""

__all__ = [
    'download_icon_grib',
    'delete_icon_grib',
    'download_icon_centroids_file',
]


import logging
from pathlib import Path
import bz2
import datetime as dt
import numpy as np

from climada.util.config import CONFIG
from climada.util.files_handler import download_file

LOGGER = logging.getLogger(__name__)



[docs] def download_icon_grib(run_datetime, model_name='icon-eu-eps', parameter_name='vmax_10m', max_lead_time=None, download_dir=None): """download the gribfiles of a weather forecast run for a certain weather parameter from opendata.dwd.de/weather/nwp/. Parameters ---------- run_datetime : datetime The starting timepoint of the forecast run model_name : str the name of the forecast model written as it appears in the folder structure in opendata.dwd.de/weather/nwp/ or 'test' parameter_name : str the name of the meteorological parameter written as it appears in the folder structure in opendata.dwd.de/weather/nwp/ max_lead_time : int number of hours for which files should be downloaded, will default to maximum available data download_dir: : str or Path directory where the downloaded files should be saved in Returns ------- file_names : list a list of filenames that link to all just downloaded or available files from the forecast run, defined by the input parameters """ LOGGER.info('Downloading icon grib files of model %s for parameter %s with starting date %s.', model_name, parameter_name, run_datetime.strftime('%Y%m%d%H')) url, file_name, lead_times = _create_icon_grib_name(run_datetime, model_name, parameter_name, max_lead_time) download_path = CONFIG.local_data.save_dir.dir() if download_dir is None else Path(download_dir) #download all files file_names = [] for lead_i in lead_times: file_name_i = file_name.format(lead_i=lead_i) bz2_pathfile_i = download_path.absolute().joinpath(file_name_i) # download file if it does not exist already if not bz2_pathfile_i.exists(): try: download_file(url + file_name_i, download_dir=download_dir) except Exception as err: err_msg = "" if run_datetime > (dt.datetime.utcnow()-dt.timedelta(hours=6)): err_msg += (f'Forecast file {file_name_i} might not yet be available ' f'on {url}. Wait a few hours. ') elif run_datetime < (dt.datetime.utcnow() -dt.timedelta(hours=24)): err_msg += (f'Forecast file {file_name_i} might no longer be available ' f'on {url}. Files are only openly available for 24 hours. ') err_msg += f"Error while downloading {url + file_name_i}: " raise type(err)(err_msg + str(err)) from err file_names.append(str(bz2_pathfile_i)) return file_names
[docs] def delete_icon_grib(run_datetime, model_name='icon-eu-eps', parameter_name='vmax_10m', max_lead_time=None, download_dir=None): """delete the downloaded gribfiles of a weather forecast run for a certain weather parameter from opendata.dwd.de/weather/nwp/. Parameters ---------- run_datetime : datetime The starting timepoint of the forecast run model_name : str the name of the forecast model written as it appears in the folder structure in opendata.dwd.de/weather/nwp/ parameter_name : str the name of the meteorological parameter written as it appears in the folder structure in opendata.dwd.de/weather/nwp/ max_lead_time : int number of hours for which files should be deleted, will default to maximum available data download_dir : str or Path directory where the downloaded files are stored at the moment """ _, file_name, lead_times = _create_icon_grib_name(run_datetime, model_name, parameter_name, max_lead_time) download_path = CONFIG.local_data.save_dir.dir() if download_dir is None else Path(download_dir) #delete all files for lead_i in lead_times: file_name_i = file_name.format(lead_i=lead_i) full_path_name_i = download_path.absolute().joinpath(file_name_i) if full_path_name_i.exists(): full_path_name_i.unlink() else: LOGGER.warning('File %s does not exist and could not be deleted.', full_path_name_i)
def _create_icon_grib_name(run_datetime, model_name='icon-eu-eps', parameter_name='vmax_10m', max_lead_time=None): """create all parameters to download or delete gribfiles of a weather forecast run for a certain weather parameter from opendata.dwd.de/weather/nwp/. Parameters ---------- run_datetime : datetime The starting timepoint of the forecast run model_name : str the name of the forecast model written as it appears in the folder structure in opendata.dwd.de/weather/nwp/ parameter_name : str the name of the meteorological parameter written as it appears in the folder structure in opendata.dwd.de/weather/nwp/ max_lead_time : int number of hours for which files should be selected, will default to maximum available data Returns ------- url : str url where the gribfiles are stored on opendata.dwd.de file_name : str filenames of gribfiles (lead_time missing) lead_times : np.array array of integers representing the leadtimes in hours, which are available for download """ # define defaults of the url for each model and parameter combination if (model_name == 'icon-eu-eps') & (parameter_name == 'vmax_10m'): file_extension = '_europe_icosahedral_single-level_' #this string completes the filename on the server file_extension_2 = '' #this string completes the filename on the server max_lead_time_default = 120 # maximum available data lead_times = np.concatenate((np.arange(1, 49), np.arange(51, 73, 3), np.arange(78, 121, 6) )) elif (model_name == 'icon-d2-eps') & (parameter_name == 'vmax_10m'): file_extension = '_germany_icosahedral_single-level_' #this string completes the filename on the server file_extension_2 = '_2d' #this string completes the filename on the server max_lead_time_default = 48 # maximum available data lead_times = np.concatenate((np.arange(1, 49), )) elif model_name == 'test': file_extension = '_storm_europe_icon_' #this string completes the filename on the server file_extension_2 = '' #this string completes the filename on the server max_lead_time_default = 2 # maximum available data lead_times = np.concatenate((np.arange(1, 49), np.arange(51, 73, 3), np.arange(78, 121, 6) )) else: raise ValueError(f'Download for model {model_name} and parameter {parameter_name} ' 'is not yet implemented. ' 'Please define the default values in the code first.') # create the url for download url = ('https://opendata.dwd.de/weather/nwp/' + model_name + '/grib/' + run_datetime.strftime('%H') + '/' + parameter_name + '/') file_name = (model_name + file_extension + run_datetime.strftime('%Y%m%d%H') + '_' + '{lead_i:03}' + file_extension_2 + '_' + parameter_name + '.grib2.bz2') # define the leadtimes if not max_lead_time: max_lead_time = max_lead_time_default elif max_lead_time > max_lead_time_default: LOGGER.warning('Parameter max_lead_time %s is bigger than maximum ' 'available files. max_lead_time is adjusted to %s.', max_lead_time, max_lead_time_default) max_lead_time = max_lead_time_default lead_times = lead_times[lead_times<=max_lead_time] return url, file_name, lead_times
[docs] def download_icon_centroids_file(model_name='icon-eu-eps', download_dir = None): """ create centroids based on netcdf files provided by dwd, links found here: https://www.dwd.de/DE/leistungen/opendata/neuigkeiten/opendata_dez2018_02.html https://www.dwd.de/DE/leistungen/opendata/neuigkeiten/opendata_aug2020_01.html Parameters ---------- model_name : str the name of the forecast model written as it appears in the folder structure in opendata.dwd.de/weather/nwp/ download_dir : str or Path directory where the downloaded files should be saved in Returns ------- file_name : str absolute path and filename of the downloaded and decompressed netcdf file """ # define url and filename url = 'https://opendata.dwd.de/weather/lib/cdo/' if model_name == 'icon-eu-eps': file_name = 'icon_grid_0028_R02B07_N02.nc.bz2' elif model_name == 'icon-eu': file_name = 'icon_grid_0024_R02B06_G.nc.bz2' elif model_name in ('icon-d2-eps', 'icon-d2'): file_name = 'icon_grid_0047_R19B07_L.nc.bz2' elif model_name == 'test': file_name = 'test_storm_europe_icon_grid.nc.bz2' else: raise ValueError(f'Creation of centroids for the icon model {model_name} ' 'is not yet implemented. Please define ' 'the default values in the code first.') download_path = CONFIG.local_data.save_dir.dir() if download_dir is None else Path(download_dir) bz2_pathfile = download_path.absolute().joinpath(file_name) nc_pathfile = bz2_pathfile.with_suffix('') # download and unzip file if not nc_pathfile.exists(): if not bz2_pathfile.exists(): try: download_file(url + file_name, download_dir=download_path) except ValueError as err: raise ValueError(f'Error while downloading {url + file_name}.') from err with open(bz2_pathfile, 'rb') as source, open(nc_pathfile, 'wb') as dest: dest.write(bz2.decompress(source.read())) bz2_pathfile.unlink() return str(nc_pathfile)