Skip to content

Commit

Permalink
Fix rotated coordinate grids and tas and pr for CORDEX datasets (#…
Browse files Browse the repository at this point in the history
…1765)

Co-authored-by: Pep Cos <[email protected]>
Co-authored-by: Klaus Zimmermann <[email protected]>
  • Loading branch information
3 people authored Dec 19, 2022
1 parent aba81fd commit 7b5e40f
Show file tree
Hide file tree
Showing 43 changed files with 1,060 additions and 6 deletions.
1 change: 1 addition & 0 deletions environment.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ dependencies:
- pip!=21.3
- prov
- psutil
- py-cordex
- pybtex
- python>=3.8
- python-stratify
Expand Down
1 change: 1 addition & 0 deletions esmvalcore/cmor/_fixes/cordex/__init__ .py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
"""Fixes for CORDEX data."""
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
"""Fixes for CORDEX data."""
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
"""Fixes for rcm CNRM-ALADIN63 driven by CNRM-CERFACS-CNRM-CM5."""
import numpy as np

from esmvalcore.cmor._fixes.cordex.cordex_fixes import TimeLongName as BaseFix
from esmvalcore.cmor._fixes.shared import add_scalar_height_coord
from esmvalcore.cmor.fix import Fix


class Tas(Fix):
"""Fixes for tas."""

def fix_metadata(self, cubes):
"""Add height (2m) coordinate and correct long_name for time.
Parameters
----------
cubes : iris.cube.CubeList
Input cubes.
Returns
-------
iris.cube.CubeList
"""
for cube in cubes:
add_scalar_height_coord(cube)
if cube.coord('height').points != 2.:
cube.coord('height').points = np.ma.array([2.0])
cube.coord('time').long_name = 'time'

return cubes


Pr = BaseFix
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
"""Fixes for rcm MOHC-HadREM3-GA7-05 driven by CNRM-CERFACS-CNRM-CM5."""
from esmvalcore.cmor._fixes.cordex.cordex_fixes import (
MOHCHadREM3GA705 as BaseFix)

Tas = BaseFix

Pr = BaseFix
206 changes: 206 additions & 0 deletions esmvalcore/cmor/_fixes/cordex/cordex_fixes.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,206 @@
"""Fixes that are shared between datasets and drivers."""
import logging
from functools import lru_cache

import cordex as cx
import iris
import numpy as np
from cf_units import Unit
from iris.coord_systems import LambertConformal, RotatedGeogCS

from esmvalcore.cmor.fix import Fix
from esmvalcore.exceptions import RecipeError

logger = logging.getLogger(__name__)


@lru_cache
def _get_domain(data_domain):
domain = cx.cordex_domain(data_domain, add_vertices=True)
return domain


@lru_cache
def _get_domain_info(data_domain):
domain_info = cx.domain_info(data_domain)
return domain_info


class MOHCHadREM3GA705(Fix):
"""General fix for MOHC-HadREM3-GA7-05."""

def fix_metadata(self, cubes):
"""Fix time long_name, and latitude and longitude var_name.
Parameters
----------
cubes : iris.cube.CubeList
Input cubes.
Returns
-------
iris.cube.CubeList
"""
for cube in cubes:
cube.coord('latitude').var_name = 'lat'
cube.coord('longitude').var_name = 'lon'
cube.coord('time').long_name = 'time'

return cubes


class TimeLongName(Fix):
"""Fixes for time coordinate."""

def fix_metadata(self, cubes):
"""Fix time long_name.
Parameters
----------
cubes : iris.cube.CubeList
Input cubes.
Returns
-------
iris.cube.CubeList
"""
for cube in cubes:
cube.coord('time').long_name = 'time'

return cubes


class CLMcomCCLM4817(Fix):
"""Fixes for CLMcom-CCLM4-8-17."""

def fix_metadata(self, cubes):
"""Fix calendars.
Set calendar to 'proleptic_gregorian' to avoid
concatenation issues between historical and
scenario runs.
Fix dtype value of coordinates and coordinate bounds.
Parameters
----------
cubes : iris.cube.CubeList
Input cubes.
Returns
-------
iris.cube.CubeList
"""
for cube in cubes:
time_unit = cube.coord('time').units
if time_unit.calendar == 'standard':
new_unit = time_unit.change_calendar('proleptic_gregorian')
cube.coord('time').units = new_unit
for coord in cube.coords():
if coord.dtype in ['>f8', '>f4']:
coord.points = coord.core_points().astype(
np.float64, casting='same_kind')
if coord.bounds is not None:
coord.bounds = coord.core_bounds().astype(
np.float64, casting='same_kind')
return cubes


class AllVars(Fix):
"""General CORDEX grid fix."""

def _check_grid_differences(self, old_coord, new_coord):
"""Check differences between coords."""
diff = np.max(np.abs(old_coord.points - new_coord.points))
logger.debug(
"Maximum difference between original %s"
"points and standard %s domain points "
"for dataset %s and driver %s is: %s.", new_coord.var_name,
self.extra_facets['domain'], self.extra_facets['dataset'],
self.extra_facets['driver'], str(diff))

if diff > 10e-4:
raise RecipeError(
"Differences between the original grid and the "
f"standardised grid are above 10e-4 {new_coord.units}.")

def _fix_rotated_coords(self, cube, domain, domain_info):
"""Fix rotated coordinates."""
for dim_coord in ['rlat', 'rlon']:
old_coord = cube.coord(domain[dim_coord].standard_name)
old_coord_dims = old_coord.cube_dims(cube)
points = domain[dim_coord].data
coord_system = iris.coord_systems.RotatedGeogCS(
grid_north_pole_latitude=domain_info['pollat'],
grid_north_pole_longitude=domain_info['pollon'])
new_coord = iris.coords.DimCoord(
points,
var_name=dim_coord,
standard_name=domain[dim_coord].standard_name,
long_name=domain[dim_coord].long_name,
units=Unit('degrees'),
coord_system=coord_system,
)
self._check_grid_differences(old_coord, new_coord)
new_coord.guess_bounds()
cube.remove_coord(old_coord)
cube.add_dim_coord(new_coord, old_coord_dims)

def _fix_geographical_coords(self, cube, domain):
"""Fix geographical coordinates."""
for aux_coord in ['lat', 'lon']:
old_coord = cube.coord(domain[aux_coord].standard_name)
cube.remove_coord(old_coord)
points = domain[aux_coord].data
bounds = domain[f'{aux_coord}_vertices'].data
new_coord = iris.coords.AuxCoord(
points,
var_name=aux_coord,
standard_name=domain[aux_coord].standard_name,
long_name=domain[aux_coord].long_name,
units=Unit(domain[aux_coord].units),
bounds=bounds,
)
self._check_grid_differences(old_coord, new_coord)
aux_coord_dims = (cube.coord(var_name='rlat').cube_dims(cube) +
cube.coord(var_name='rlon').cube_dims(cube))
cube.add_aux_coord(new_coord, aux_coord_dims)

def fix_metadata(self, cubes):
"""Fix CORDEX rotated grids.
Set rotated and geographical coordinates to the
values given by each domain specification.
The domain specifications are retrieved from the
py-cordex package.
Parameters
----------
cubes : iris.cube.CubeList
Input cubes.
Returns
-------
iris.cube.CubeList
"""
data_domain = self.extra_facets['domain']
domain = _get_domain(data_domain)
domain_info = _get_domain_info(data_domain)
for cube in cubes:
coord_system = cube.coord_system()
if isinstance(coord_system, RotatedGeogCS):
self._fix_rotated_coords(cube, domain, domain_info)
self._fix_geographical_coords(cube, domain)
elif isinstance(coord_system, LambertConformal):
logger.warning(
"Support for CORDEX datasets in a Lambert Conformal "
"coordinate system is ongoing. Certain preprocessor "
"functions may fail.")
else:
raise RecipeError(
f"Coordinate system {coord_system.grid_mapping_name} "
"not supported in CORDEX datasets. Must be "
"rotated_latitude_longitude or lambert_conformal_conic.")

return cubes
1 change: 1 addition & 0 deletions esmvalcore/cmor/_fixes/cordex/ichec_ec_earth/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
"""Fixes for CORDEX data."""
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
"""Fixes for rcm CLMcom-CCLM4-8-17 driven by ICHEC-EC-EARTH."""
from esmvalcore.cmor._fixes.cordex.cordex_fixes import (
CLMcomCCLM4817 as BaseFix)

AllVars = BaseFix
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
"""Fixes for rcm GERICS-REMO2015 driven by ICHEC-EC-EARTH."""
from esmvalcore.cmor._fixes.cordex.cordex_fixes import (
TimeLongName as BaseFix)

Pr = BaseFix
5 changes: 5 additions & 0 deletions esmvalcore/cmor/_fixes/cordex/ichec_ec_earth/knmi_racmo22e.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
"""Fixes for rcm KNMI-RACMO22E driven by ICHEC-EC-EARTH."""
from esmvalcore.cmor._fixes.cordex.cordex_fixes import (
TimeLongName as BaseFix)

Pr = BaseFix
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
"""Fixes for rcm MOHC-HadREM3-GA7-05 driven by ICHEC-EC-EARTH."""
from esmvalcore.cmor._fixes.cordex.cordex_fixes import (
MOHCHadREM3GA705 as BaseFix)

Tas = BaseFix

Pr = BaseFix
7 changes: 7 additions & 0 deletions esmvalcore/cmor/_fixes/cordex/ichec_ec_earth/smhi_rca4.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
"""Fixes for rcm SMHI-RCA4 driven by ICHEC-EC-EARTH."""
from esmvalcore.cmor._fixes.cordex.cordex_fixes import (
TimeLongName as BaseFix)

Pr = BaseFix

Tas = BaseFix
1 change: 1 addition & 0 deletions esmvalcore/cmor/_fixes/cordex/miroc_miroc5/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
"""Fixes for CORDEX data."""
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
"""Fixes for rcm CLMcom-CCLM4-8-17 driven by MIROC-MIROC5."""
from esmvalcore.cmor._fixes.cordex.cordex_fixes import (
CLMcomCCLM4817 as BaseFix)

AllVars = BaseFix
5 changes: 5 additions & 0 deletions esmvalcore/cmor/_fixes/cordex/miroc_miroc5/gerics_remo2015.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
"""Fixes for rcm GERICS-REMO2015 driven by MIROC-MIROC5."""
from esmvalcore.cmor._fixes.cordex.cordex_fixes import (
TimeLongName as BaseFix)

Pr = BaseFix
34 changes: 34 additions & 0 deletions esmvalcore/cmor/_fixes/cordex/miroc_miroc5/uhoh_wrf361h.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
"""Fixes for rcm UHOH-WRF361H driven by MIROC-MIROC5."""
import iris
from esmvalcore.cmor.fix import Fix


class Tas(Fix):
"""Fixes for tas."""

def fix_metadata(self, cubes):
"""Fix tas coordinates.
Set height as an auxiliary coordinate instead
of as a dimensional coordinate.
Parameters
----------
cubes : iris.cube.CubeList
Input cubes.
Returns
-------
iris.cube.CubeList
"""
fixed_cubes = iris.cube.CubeList()
for cube in cubes:
height = cube.coord('height')
if isinstance(height, iris.coords.DimCoord):
iris.util.demote_dim_coord_to_aux_coord(
cube,
height
)
fixed_cubes.append(iris.util.squeeze(cube))
return fixed_cubes
1 change: 1 addition & 0 deletions esmvalcore/cmor/_fixes/cordex/mohc_hadgem2_es/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
"""Fixes for CORDEX data."""
25 changes: 25 additions & 0 deletions esmvalcore/cmor/_fixes/cordex/mohc_hadgem2_es/dmi_hirham5.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
"""Fixes for rcm DMI-HIRHAM driven by MOHC-HadGEM2."""
from esmvalcore.cmor.fix import Fix


class Pr(Fix):
"""Fixes for pr."""

def fix_metadata(self, cubes):
"""Remove latitude and longitude attributes.
Parameters
----------
cubes : iris.cube.CubeList
Input cubes.
Returns
-------
iris.cube.CubeList
"""
for cube in cubes:
cube.coord('latitude').attributes = {}
cube.coord('longitude').attributes = {}

return cubes
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
"""Fixes for rcm GERICS-REMO2015 driven by MOHC-HadGEM2."""
from esmvalcore.cmor._fixes.cordex.cordex_fixes import (
TimeLongName as BaseFix)

Pr = BaseFix

Tas = BaseFix
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
"""Fixes for rcm MOHC-HadREM3-GA7-05 driven by MOHC-HadGEM2-ES."""
from esmvalcore.cmor._fixes.cordex.cordex_fixes import (
MOHCHadREM3GA705 as BaseFix)

Tas = BaseFix

Pr = BaseFix
7 changes: 7 additions & 0 deletions esmvalcore/cmor/_fixes/cordex/mohc_hadgem2_es/smhi_rca4.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
"""Fixes for rcm SMHI-RCA4 driven by MOHC-HadGEM2-ES."""
from esmvalcore.cmor._fixes.cordex.cordex_fixes import (
TimeLongName as BaseFix)

Pr = BaseFix

Tas = BaseFix
1 change: 1 addition & 0 deletions esmvalcore/cmor/_fixes/cordex/mpi_m_mpi_esm_lr/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
"""Fixes for CORDEX data."""
Loading

0 comments on commit 7b5e40f

Please sign in to comment.