Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cmorize eobs #1554

Merged
merged 21 commits into from May 7, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 2 additions & 0 deletions doc/sphinx/source/input.rst
Expand Up @@ -98,6 +98,8 @@ A list of the datasets for which a cmorizers is available is provided in the fol
+------------------------------+------------------------------------------------------------------------------------------------------+------+-----------------+
| Duveiller2018 | albDiffiTr13 | 2 | Python |
+------------------------------+------------------------------------------------------------------------------------------------------+------+-----------------+
| E-OBS | tas, tasmin, tasmax, pr, psl (day, Amon) | 2 | Python |
+------------------------------+------------------------------------------------------------------------------------------------------+------+-----------------+
| Eppley-VGPM-MODIS | intpp (Omon) | 2 | Python |
+------------------------------+------------------------------------------------------------------------------------------------------+------+-----------------+
| ERA5 | clt, evspsbl, evspsblpot, mrro, pr, prsn, ps, psl, ptype, rls, rlds, rsds, rsdt, rss, uas, vas, tas, | 3 | Python |
Expand Down
45 changes: 45 additions & 0 deletions esmvaltool/cmorizers/obs/cmor_config/E-OBS.yml
@@ -0,0 +1,45 @@
---
# Filename (will be extended by variable name, resolutions and version)
filename: '{raw_name}_ens_mean_{resolution}deg_reg_v{version}.nc'

# Common global attributes for Cmorizer output
attributes:
dataset_id: E-OBS
version: '20.0e'
resolution:
r1: 0.1
r2: 0.25
tier: 2
modeling_realm: ground
project_id: OBS
source: 'https://www.ecad.eu/download/ensembles/download.php'
reference: 'e-obs'
comment: ''

# Variables to cmorize
variables:
tas:
mip: day
raw: tg
raw_units: celsius
add_mon: true
pr:
mip: day
raw: rr
raw_units: kg m-2 day-1
add_mon: true
tasmax:
mip: day
raw: tx
raw_units: celsius
add_mon: true
tasmin:
mip: day
raw: tn
raw_units: celsius
add_mon: true
psl:
mip: day
raw: pp
raw_units: hPa
add_mon: true
152 changes: 152 additions & 0 deletions esmvaltool/cmorizers/obs/cmorize_obs_e_obs.py
@@ -0,0 +1,152 @@
"""ESMValTool CMORizer for E-OBS data.

Tier
Tier 2: other freely-available dataset.

Source
http://surfobs.climate.copernicus.eu/dataaccess/access_eobs.php#datafiles

Last access
20200225

Download and processing instructions
Download the ensemble mean files for:
TG TN TX RR PP
"""

import logging
import os
import iris
import numpy as np
from cf_units import Unit

from esmvalcore.preprocessor import monthly_statistics
from . import utilities as utils

logger = logging.getLogger(__name__)


def fix_coords_non_symetric_lon(cube):
"""Fix the time units and values to CMOR standards."""

# first fix any completely missing coord var names
utils._fix_dim_coordnames(cube)
# fix individual coords
for cube_coord in cube.coords():
# fix time
if cube_coord.var_name == 'time':
logger.info("Fixing time...")
cube.coord('time').convert_units(
Unit('days since 1950-1-1 00:00:00', calendar='gregorian'))
utils._fix_bounds(cube, cube.coord('time'))

# fix longitude
if cube_coord.var_name == 'lon':
logger.info("Fixing longitude...")
if cube_coord.ndim == 1:
if cube_coord.points[0] < 0. and \
cube_coord.points[-1] < 181.:
lon_coord = cube.coord('longitude').copy()
lons_below_0 = lon_coord.points[lon_coord.points < 0.] + \
360.
lons_above_0 = lon_coord.points[lon_coord.points >= 0.]
lons = np.hstack((lons_above_0, lons_below_0))
cube_coord.points = lons

utils._fix_bounds(cube, cube_coord)
cube.attributes['geospatial_lon_min'] = 0.
cube.attributes['geospatial_lon_max'] = 360.
utils._roll_cube_data(cube, len(lons_above_0), -1)

# fix latitude
if cube_coord.var_name == 'lat':
logger.info("Fixing latitude...")
utils._fix_bounds(cube, cube.coord('latitude'))

# fix depth
if cube_coord.var_name == 'lev':
logger.info("Fixing depth...")
utils._fix_bounds(cube, cube.coord('depth'))

# fix air_pressure
if cube_coord.var_name == 'air_pressure':
logger.info("Fixing air pressure...")
utils._fix_bounds(cube, cube.coord('air_pressure'))

# remove CS
cube.coord('latitude').coord_system = None
cube.coord('longitude').coord_system = None

return cube


def _extract_variable(short_name, var, res, cfg, filepath, out_dir):
"""Extract variable."""
raw_var = var.get('raw', short_name)
cube = iris.load_cube(filepath, utils.var_name_constraint(raw_var))

# Fix units
cmor_info = cfg['cmor_table'].get_variable(var['mip'], short_name)
cube.units = var.get('raw_units', short_name)
cube.convert_units(cmor_info.units)
utils.convert_timeunits(cube, 1950)

# Fix coordinates
fix_coords_non_symetric_lon(cube)
if 'height2m' in cmor_info.dimensions:
utils.add_height2m(cube)

# Fix metadata
utils.fix_var_metadata(cube, cmor_info)
attrs = cfg['attributes'].copy()
attrs['version'] = 'v' + attrs['version'] + '-' + str(res)
attrs.pop('resolution')
attrs['mip'] = var['mip']
utils.set_global_atts(cube, attrs)

# Save variable
utils.save_variable(cube,
short_name,
out_dir,
attrs,
unlimited_dimensions=['time'])

#####
# also derive monthly data
if 'add_mon' in var:
if var['add_mon']:
logger.info("Building monthly means")

# Calc monthly
cube = monthly_statistics(cube)
cube.remove_coord('month_number')
cube.remove_coord('year')

# Fix metadata
attrs['mip'] = 'Amon'

# Fix coordinates
fix_coords_non_symetric_lon(cube)

# Save variable
utils.save_variable(cube,
short_name,
out_dir,
attrs,
unlimited_dimensions=['time'])


def cmorization(in_dir, out_dir, cfg, _):
"""Cmorization func call."""
raw_filepath = os.path.join(in_dir, cfg['filename'])

# Run the cmorization
ver = cfg['attributes']['version']
for res in cfg['attributes']['resolution'].values():
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
for res in cfg['attributes']['resolution'].values():
for _, res in cfg['attributes']['resolution'].items():

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why would you want to change this? It looks fine as it is?

for (short_name, var) in cfg['variables'].items():
logger.info("CMORizing variable '%s' on %s°x%s°",
short_name, res, res)
raw_var = var.get('raw', short_name)
filepath = raw_filepath.format(raw_name=raw_var, resolution=res,
version=ver)
_extract_variable(short_name, var, res, cfg, filepath, out_dir)
20 changes: 20 additions & 0 deletions esmvaltool/recipes/examples/recipe_check_obs.yml
Expand Up @@ -109,6 +109,26 @@ diagnostics:
scripts: null


E-OBS:
description: E-OBS check
variables:
tas:
tasmax:
tasmin:
pr:
psl:
additional_datasets:
- {dataset: E-OBS, project: OBS, mip: day, tier: 2, type: ground,
version: v20.0e-0.1, start_year: 1950, end_year: 2019, end_month: 07}
- {dataset: E-OBS, project: OBS, mip: day, tier: 2, type: ground,
version: v20.0e-0.25, start_year: 1950, end_year: 2019, end_month: 07}
- {dataset: E-OBS, project: OBS, mip: Amon, tier: 2, type: ground,
version: v20.0e-0.1, start_year: 1950, end_year: 2019, end_month: 07}
- {dataset: E-OBS, project: OBS, mip: Amon, tier: 2, type: ground,
version: v20.0e-0.25, start_year: 1950, end_year: 2019, end_month: 07}
scripts: null


Eppley-VGPM-MODIS:
description: Eppley-VGPM-MODIS check
variables:
Expand Down
12 changes: 12 additions & 0 deletions esmvaltool/references/e-obs.bibtex
@@ -0,0 +1,12 @@
@article{e-obs,
author = {Cornes, Richard C. and van der Schrier, Gerard and van den Besselaar, Else J. M. and Jones, Philip D.},
title = {An Ensemble Version of the E-OBS Temperature and Precipitation Data Sets},
journal = {Journal of Geophysical Research: Atmospheres},
volume = {123},
number = {17},
pages = {9391-9409},
doi = {10.1029/2017JD028200},
url = {https://agupubs.onlinelibrary.wiley.com/doi/abs/10.1029/2017JD028200},
eprint = {https://agupubs.onlinelibrary.wiley.com/doi/pdf/10.1029/2017JD028200},
year = {2018}
}