Skip to content

Commit 9229ce1

Browse files
authored
Merge pull request #462 from ESMValGroup/fix_sit_gfdl_cm2p1
Fix for bad time bounds in CMIP5 GFDL-CM2p1 sit
2 parents 6bbdcbd + 322c306 commit 9229ce1

File tree

2 files changed

+111
-2
lines changed

2 files changed

+111
-2
lines changed

esmvalcore/cmor/_fixes/cmip5/gfdl_cm2p1.py

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
"""Fixes for GFDL CM2p1 model."""
22
from copy import deepcopy
3+
import numpy as np
4+
import cftime
35

46
from ..fix import Fix
57
from ..cmip5.gfdl_esm2g import AllVars as BaseAllVars
@@ -56,6 +58,48 @@ def fix_data(self, cube):
5658
return cube
5759

5860

61+
class Sit(Fix):
62+
"""Fixes for sit"""
63+
64+
def fix_metadata(self, cubes):
65+
"""
66+
Fix metadata.
67+
68+
Fixes bad bounds
69+
70+
Parameters
71+
----------
72+
cube: iris.cube.Cube
73+
74+
Returns
75+
-------
76+
iris.cube.Cube
77+
78+
"""
79+
cube = self.get_cube_from_list(cubes)
80+
time = cube.coord('time')
81+
if self._fix_required(time):
82+
times = time.units.num2date(time.points)
83+
starts = [
84+
cftime.DatetimeJulian(c.year, c.month, 1)
85+
for c in times
86+
]
87+
ends = [
88+
cftime.DatetimeJulian(c.year, c.month + 1, 1)
89+
if c.month < 12
90+
else cftime.DatetimeJulian(c.year + 1, 1, 1)
91+
for c in times
92+
]
93+
time.bounds = time.units.date2num(np.stack([starts, ends], -1))
94+
return cubes
95+
96+
def _fix_required(self, time):
97+
return (
98+
self.vardef.frequency == 'mon' and
99+
not (time.bounds[-1, 0] < time.points[-1] < time.bounds[-1, 1])
100+
)
101+
102+
59103
class Tos(Fix):
60104
"""Fixes for tos"""
61105

tests/integration/cmor/_fixes/cmip5/test_gfdl_cm2p1.py

Lines changed: 67 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,14 @@
11
"""Test GDL-CM2P1 fixes."""
22
import unittest
3+
from unittest import mock
34

45
from cf_units import Unit
6+
import iris
57
from iris.cube import Cube
68

79
from esmvalcore.cmor.fix import Fix
8-
from esmvalcore.cmor._fixes.cmip5.gfdl_cm2p1 import Sftof, AllVars, Areacello
10+
from esmvalcore.cmor._fixes.cmip5.gfdl_cm2p1 import (Sftof, AllVars,
11+
Areacello, Sit)
912

1013

1114
class TestSftof(unittest.TestCase):
@@ -29,7 +32,8 @@ def test_fix_data(self):
2932

3033

3134
class TestAreacello(unittest.TestCase):
32-
"""Test sftof fixes."""
35+
"""Test areacello fixes."""
36+
3337
def setUp(self):
3438
"""Prepare tests."""
3539
self.cube = Cube([1.0], var_name='areacello', units='m-2')
@@ -53,3 +57,64 @@ def test_fix_data(self):
5357
cube = self.fix.fix_metadata((self.cube, ))[0]
5458
self.assertEqual(cube.data[0], 1.0)
5559
self.assertEqual(cube.units, Unit('m2'))
60+
61+
62+
class TestSit(unittest.TestCase):
63+
"""Test sit fixes."""
64+
65+
def setUp(self):
66+
"""Prepare tests."""
67+
self.cube = Cube([1.0, 2.0], var_name='sit', units='m')
68+
self.cube.add_dim_coord(
69+
iris.coords.DimCoord(
70+
points=[45000.5, 45031.5],
71+
var_name='time',
72+
standard_name='time',
73+
long_name='time',
74+
units='days since 1850-01-01',
75+
bounds=[[1e8, 1.1e8], [1.1e8, 1.2e8]]
76+
),
77+
0
78+
)
79+
self.var_info_mock = mock.Mock()
80+
self.var_info_mock.frequency = 'mon'
81+
self.fix = Sit(self.var_info_mock)
82+
83+
def test_get(self):
84+
"""Test fix get"""
85+
self.assertListEqual(
86+
Fix.get_fixes('CMIP5', 'GFDL-CM2P1', 'OImon', 'sit'),
87+
[Sit(self.var_info_mock), AllVars(None)])
88+
89+
def test_fix_metadata_day_do_nothing(self):
90+
"""Test data fix."""
91+
self.var_info_mock.frequency = 'day'
92+
fix = Sit(self.var_info_mock)
93+
cube = fix.fix_metadata((self.cube,))[0]
94+
time = cube.coord('time')
95+
self.assertEqual(time.bounds[0, 0], 1e8)
96+
self.assertEqual(time.bounds[0, 1], 1.1e8)
97+
self.assertEqual(time.bounds[1, 0], 1.1e8)
98+
self.assertEqual(time.bounds[1, 1], 1.2e8)
99+
100+
def test_fix_metadata(self):
101+
"""Test data fix."""
102+
fix = Sit(self.var_info_mock)
103+
cube = fix.fix_metadata((self.cube,))[0]
104+
time = cube.coord('time')
105+
self.assertEqual(time.bounds[0, 0], 44984)
106+
self.assertEqual(time.bounds[0, 1], 45015)
107+
self.assertEqual(time.bounds[1, 0], 45015)
108+
self.assertEqual(time.bounds[1, 1], 45045)
109+
110+
def test_fix_metadata_not_needed(self):
111+
"""Test data fix."""
112+
fix = Sit(self.var_info_mock)
113+
cube = fix.fix_metadata((self.cube,))[0]
114+
time = cube.coord('time')
115+
new_bounds = [[44985., 45014.], [45016., 45044.]]
116+
time.bounds = new_bounds
117+
self.assertEqual(time.bounds[0, 0], 44985)
118+
self.assertEqual(time.bounds[0, 1], 45014)
119+
self.assertEqual(time.bounds[1, 0], 45016)
120+
self.assertEqual(time.bounds[1, 1], 45044)

0 commit comments

Comments
 (0)