diff --git a/Aforc_ERA5/ERA5_parallel_request.py b/Aforc_ERA5/ERA5_parallel_request.py new file mode 100644 index 0000000000000000000000000000000000000000..62072a922933ee2ac0a9125c8a4d2a4e3af67bfc --- /dev/null +++ b/Aforc_ERA5/ERA5_parallel_request.py @@ -0,0 +1,211 @@ +#!/usr/bin/env python + +# Script to download ECMWF ERA5 reanalysis datasets from the Climate Data +# Store (CDS) of Copernicus https://cds.climate.copernicus.eu +# +# This script use the CDS Phyton API[*] to connect and download specific ERA5 +# variables, for a chosen area and monthly date interval, required by CROCO to +# perform simulations with atmospheric forcing. Furthermore, this script use +# ERA5 parameter names and not parameter IDs as these did not result in stable +# downloads. +# +# Tested using Python 3.8.6 and Python 3.9.1. This script need the following +# python libraries pre-installed: "calendar", "datetime", "json" and "os". +# +# [*] https://cds.climate.copernicus.eu/api-how-to +# +# Copyright (c) DDONOSO February 2021 +# e-mail:ddonoso@dgeo.udec.cl +# + +# You may see all available ERA5 variables at the following website +# https://confluence.ecmwf.int/display/CKB/ERA5%3A+data+documentation#ERA5:datadocumentation-Parameterlistings + +# ------------------------------------------------- +# Getting libraries and utilities +# ------------------------------------------------- +import cdsapi +from ERA5_utilities import * +import calendar +import datetime +import json +import os +from multiprocessing import Pool + +# Importing addmonths4date function from ERA5_utilities +from ERA5_utilities import addmonths4date + +# Function to download data for a single variable +def download_data(variable, options, product, output): + c = cdsapi.Client() + c.retrieve(product, options, output) + +# Main function to process tasks in parallel +def process_parallel(tasks): + with Pool() as pool: + pool.starmap(download_data, tasks) + + +# ------------------------------------------------- +# Import my crocotools_param_python file +from era5_crocotools_param import * +print('year_start is '+str(year_start)) + +# ------------------------------------------------- +dl=2 +if ownArea == 0: + lines = [line.rstrip('\n') for line in open(paramFile)] + for line in lines: + if "lonmin" in line: + iStart=line.find('=')+1 + iEnd=line.find(';') + lonmin = line[iStart:iEnd] + elif "lonmax" in line: + iStart=line.find('=')+1 + iEnd=line.find(';') + lonmax = line[iStart:iEnd] + elif "latmin" in line: + iStart=line.find('=')+1 + iEnd=line.find(';') + latmin = line[iStart:iEnd] + elif "latmax" in line: + iStart=line.find('=')+1 + iEnd=line.find(';') + latmax = line[iStart:iEnd] + +lonmin = str(float(lonmin)-dl) +lonmax = str(float(lonmax)+dl) +latmin = str(float(latmin)-dl) +latmax = str(float(latmax)+dl) +print ('lonmin-dl = ', lonmin) +print ('lonmax+dl =', lonmax) +print ('latmin-dl =', latmin) +print ('latmax+dl =', latmax) +# ------------------------------------------------- + +area = [latmax, lonmin, latmin, lonmax] + +# ------------------------------------------------- +# Setting raw output directory +# ------------------------------------------------- +# Get the current directory +os.makedirs(era5_dir_raw,exist_ok=True) + + +# ------------------------------------------------- +# Loading ERA5 variables's information as +# python Dictionary from JSON file +# ------------------------------------------------- +with open('ERA5_variables.json', 'r') as jf: + era5 = json.load(jf) + + +# ------------------------------------------------- +# Downloading ERA5 datasets +# ------------------------------------------------- +# Monthly dates limits +monthly_date_start = datetime.datetime(year_start,month_start,1) +monthly_date_end = datetime.datetime(year_end,month_end,1) + +# Length of monthly dates loop +len_monthly_dates = (monthly_date_end.year - monthly_date_start.year) * 12 + \ + (monthly_date_end.month - monthly_date_start.month) + 1 + +# Initial monthly date +monthly_date = monthly_date_start + +# Construct tasks for parallel processing +tasks = [] + +# Monthly dates loop +for j in range(len_monthly_dates): + + # Year and month + year = monthly_date.year + month = monthly_date.month + + # Number of days in month + days_in_month = calendar.monthrange(year,month)[1] + + # Date limits + date_start = datetime.datetime(year,month,1) + date_end = datetime.datetime(year,month,days_in_month) + + # Ordinal date limits (days) + n_start = datetime.date.toordinal(date_start) + n_end = datetime.date.toordinal(date_end) + + # Overlapping date string limits (yyyy-mm-dd) + datestr_start_overlap = datetime.date.fromordinal(n_start - n_overlap).strftime('%Y-%m-%d') + datestr_end_overlap = datetime.date.fromordinal(n_end + n_overlap).strftime('%Y-%m-%d') + + # Overlapping date string interval + vdate = datestr_start_overlap + '/' + datestr_end_overlap + + # Variables/Parameters loop + for k in range(len(variables)): + + # Variable's name, long-name and level-type + vname = variables[k] + vlong = era5[vname][0] + vlevt = era5[vname][3] + + # Request options + options = { + 'product_type': 'reanalysis', + 'type': 'an', + 'date': vdate, + 'variable': vlong, + 'levtype': vlevt, + 'area': area, + 'format': 'netcdf', + } + + if vlong == 'sea_surface_temperature': + options['time'] = '00' + elif vlong == 'land_sea_mask': + options['time'] = '00:00' + else: + options['time'] = time + + if vlong == 'specific_humidity' or vlong == 'relative_humidity': + options['pressure_level'] = '1000' + product = 'reanalysis-era5-pressure-levels' + else: + product = 'reanalysis-era5-single-levels' + + # Output filename + fname = 'ERA5_ecmwf_' + vname.upper() + '_Y' + str(year) + 'M' + str(month).zfill(2) + '.nc' + output = era5_dir_raw + '/' + fname + + # Information strings + info_time_clock = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S") + info_monthly_date = monthly_date.strftime('%Y-%b') + info_n_overlap = ' with ' + str(n_overlap) + ' overlapping day(s) ' + + # Printing message on screen + print(' ') + print('-----------------------------------------------------------') + print('',info_time_clock,' ') + print(' Performing ERA5 data request, please wait... ') + print(' Date [yyyy-mmm] =',info_monthly_date + info_n_overlap,' ') + print(' Variable =',vlong,' ') + print('-----------------------------------------------------------') + print('Request options: ') + print(options) + + tasks.append((vname, options, product, output)) + + monthly_date = addmonths4date(monthly_date, 1) + +# Process tasks in parallel +process_parallel(tasks) + +# Print output message on screen +print(' ') +print(' ERA5 data request has been done successfully! ') +print(' ') + + + +