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

Fix rotated coordinate grids and tas and pr for CORDEX datasets #1765

Merged
merged 88 commits into from
Dec 19, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
88 commits
Select commit Hold shift + click to select a range
ab66c08
Add derivation of siextent
sloosvel Aug 2, 2022
079767b
Set proper units
sloosvel Aug 8, 2022
2834028
Fix tests
sloosvel Aug 8, 2022
119cec1
Fix flake
sloosvel Aug 8, 2022
6d7b963
Attempt to improve test coverage
sloosvel Aug 9, 2022
7b0ff11
Merge remote-tracking branch 'origin/main' into dev_siextent
sloosvel Sep 15, 2022
7690b59
Improve test coverage
sloosvel Sep 15, 2022
b8b6248
Change units in table
sloosvel Sep 15, 2022
0838466
Consider using siconca
sloosvel Oct 3, 2022
58b0916
Merge branch 'dev_siextent' of https://github.com/ESMValGroup/ESMValC…
sloosvel Oct 3, 2022
9bf7580
Merge remote-tracking branch 'origin/main' into dev_siextent
sloosvel Oct 3, 2022
09a6da7
Fix tests
sloosvel Oct 3, 2022
022aec2
Fix tests
sloosvel Oct 3, 2022
85c1f0c
Add missing line
sloosvel Oct 3, 2022
44ed216
Add cordex fixes
sloosvel Oct 17, 2022
7e81922
Load cordex fixes module
sloosvel Oct 17, 2022
f086c67
clean fixes strings and format
Oct 18, 2022
3f2a08e
delete unneeded fix
Oct 18, 2022
4cc84e5
Add more fixes
sloosvel Oct 19, 2022
0643677
Merge branch 'dev_cordex_fixes' of https://github.com/ESMValGroup/ESM…
sloosvel Oct 19, 2022
301eed5
Remove unrelated files
sloosvel Oct 19, 2022
4d921cc
Delete unrelated test
sloosvel Oct 19, 2022
c3b1bc1
Remove dataset that may not need fix
sloosvel Oct 19, 2022
43e3139
Fix style issues
sloosvel Oct 19, 2022
7325d62
Fix style issues
sloosvel Oct 19, 2022
84aca13
Merge remote-tracking branch 'origin/main' into dev_cordex_fixes
sloosvel Oct 19, 2022
bce8fc6
Reorder HadREM fixes
sloosvel Oct 19, 2022
3df519b
Generalise time coord fix
sloosvel Oct 19, 2022
2417b9d
Generalise CLM com fix
sloosvel Oct 19, 2022
02e795a
Fix imports
sloosvel Oct 19, 2022
ca921ac
Change imports
sloosvel Oct 20, 2022
d804e67
Fix style issues
sloosvel Oct 20, 2022
61e15bb
Change imports in more files
sloosvel Oct 20, 2022
05d9b28
Change more imports
sloosvel Oct 20, 2022
870aa86
Improve test coverage of check.py
sloosvel Oct 20, 2022
0f6108e
Remove whitespace
sloosvel Oct 20, 2022
5e89d0f
Fix test
sloosvel Oct 20, 2022
729151d
Improve test coverage in fix.py
sloosvel Oct 21, 2022
f31d762
Fix flake
sloosvel Oct 21, 2022
9e6f9b8
Merge remote-tracking branch 'origin/main' into dev_cordex_fixes
sloosvel Oct 21, 2022
140a681
Add tests
sloosvel Oct 23, 2022
052a575
Fix test
sloosvel Oct 23, 2022
4d2c85d
Add test for bounds
sloosvel Oct 24, 2022
a8f28ff
Fix codacy
sloosvel Oct 24, 2022
f8bbeed
Fix docstring
sloosvel Oct 24, 2022
7899214
Remove whitespace
sloosvel Oct 24, 2022
04b4bfc
Merge remote-tracking branch 'origin/main' into dev_cordex_fixes
sloosvel Nov 16, 2022
7132ac5
Apply suggestions from code review
sloosvel Nov 21, 2022
1ac59ae
First attempt at boundary fix
sloosvel Dec 2, 2022
683ca8d
Add general grid fix for rotated datasets
sloosvel Dec 3, 2022
c63e76a
Add tas fix for UHOH-WRF361H
sloosvel Dec 3, 2022
39b8198
Fix flake
sloosvel Dec 5, 2022
a3560f4
Remove blank line
sloosvel Dec 5, 2022
603db38
Fix tests
sloosvel Dec 5, 2022
8b57ea4
Fix conflicts
sloosvel Dec 5, 2022
d394c64
Update calendar names
sloosvel Dec 5, 2022
78f45c3
Add grid fix test
sloosvel Dec 5, 2022
60901f8
Fix flake
sloosvel Dec 5, 2022
29614b2
Fix flake
sloosvel Dec 5, 2022
72638d2
Add tests for UHOH-WRF361H
sloosvel Dec 5, 2022
0f3a139
Fix tests
sloosvel Dec 5, 2022
ac3fe85
Improve code coverage
sloosvel Dec 6, 2022
5e7fadf
Add docstrings
sloosvel Dec 6, 2022
9942728
Merge remote-tracking branch 'origin/main' into dev_cordex_fixes
sloosvel Dec 6, 2022
f926981
Merge remote-tracking branch 'origin/main' into dev_cordex_fixes
sloosvel Dec 13, 2022
ebbaaf8
Address review comments
sloosvel Dec 14, 2022
7cc3c70
Fix flake
sloosvel Dec 14, 2022
e39bb43
Fix codacy
sloosvel Dec 14, 2022
6033ad1
Merge remote-tracking branch 'origin/main' into dev_cordex_fixes
sloosvel Dec 14, 2022
33f9e29
Remove unused import
sloosvel Dec 14, 2022
6e52386
Format log message properly
sloosvel Dec 14, 2022
40692af
Add dataset in extra_facets dict for cordex
sloosvel Dec 14, 2022
e54e862
Add warning for Lambert Conformal datasets
sloosvel Dec 16, 2022
67c877f
Remove blank line
sloosvel Dec 16, 2022
af968d3
Update esmvalcore/cmor/_fixes/cordex/cordex_fixes.py
sloosvel Dec 19, 2022
ed89cc4
Update tests/integration/cmor/_fixes/cordex/test_cordex_fixes.py
sloosvel Dec 19, 2022
6112c96
Address review comments
sloosvel Dec 19, 2022
f303b40
Merge branch 'dev_cordex_fixes' of https://github.com/ESMValGroup/ESM…
sloosvel Dec 19, 2022
1b89aa2
Add comment in init file
sloosvel Dec 19, 2022
ab74aeb
Fix flake
sloosvel Dec 19, 2022
52fd459
Merge remote-tracking branch 'origin/main' into dev_cordex_fixes
sloosvel Dec 19, 2022
c7cda80
Improve test
sloosvel Dec 19, 2022
33c5d1e
Safer calendar change
sloosvel Dec 19, 2022
3480152
Fix flake
sloosvel Dec 19, 2022
fb9f634
Fix test
sloosvel Dec 19, 2022
99c4214
Cache domain retrieval
sloosvel Dec 19, 2022
e5d48cc
Fix spelling
sloosvel Dec 19, 2022
684ebc2
Apply suggestions from code review
sloosvel Dec 19, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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:
bouweandela marked this conversation as resolved.
Show resolved Hide resolved
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(
sloosvel marked this conversation as resolved.
Show resolved Hide resolved
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 = {}
bouweandela marked this conversation as resolved.
Show resolved Hide resolved

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