Skip to content

Commit e5e2e9d

Browse files
committed
Avoid copying input data in CESM2 fixes
1 parent 951ea29 commit e5e2e9d

2 files changed

Lines changed: 86 additions & 75 deletions

File tree

esmvalcore/cmor/_fixes/cmip6/cesm2.py

Lines changed: 49 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,13 @@
22

33
from __future__ import annotations
44

5-
from shutil import copyfile
65
from typing import TYPE_CHECKING
76

87
import iris
98
import iris.coords
9+
import ncdata
10+
import ncdata.netcdf4
1011
import numpy as np
11-
from netCDF4 import Dataset
1212

1313
from esmvalcore.cmor._fixes.common import SiconcFixScalarCoord
1414
from esmvalcore.cmor._fixes.fix import Fix
@@ -19,40 +19,36 @@
1919
add_scalar_typesea_coord,
2020
fix_ocean_depth_coord,
2121
)
22+
from esmvalcore.iris_helpers import dataset_to_iris
2223

2324
if TYPE_CHECKING:
25+
from collections.abc import Sequence
2426
from pathlib import Path
2527

28+
from iris.cube import Cube
29+
2630

2731
class Cl(Fix):
2832
"""Fixes for ``cl``."""
2933

30-
def _fix_formula_terms(
31-
self,
32-
file: str | Path,
33-
output_dir: str | Path,
34-
add_unique_suffix: bool = False,
35-
) -> Path:
34+
@staticmethod
35+
def _fix_formula_terms(dataset: ncdata.NcData) -> None:
3636
"""Fix ``formula_terms`` attribute."""
37-
new_path = self.get_fixed_filepath(
38-
output_dir,
39-
file,
40-
add_unique_suffix=add_unique_suffix,
37+
lev = dataset.variables["lev"]
38+
lev.set_attrval("formula_terms", "p0: p0 a: a b: b ps: ps")
39+
lev.set_attrval(
40+
"standard_name",
41+
"atmosphere_hybrid_sigma_pressure_coordinate",
4142
)
42-
copyfile(file, new_path)
43-
with Dataset(new_path, mode="a") as dataset:
44-
dataset.variables["lev"].formula_terms = "p0: p0 a: a b: b ps: ps"
45-
dataset.variables[
46-
"lev"
47-
].standard_name = "atmosphere_hybrid_sigma_pressure_coordinate"
48-
return new_path
43+
lev.set_attrval("units", "1")
44+
dataset.variables["lev_bnds"].attributes.pop("units")
4945

5046
def fix_file(
5147
self,
52-
file: str | Path,
53-
output_dir: str | Path,
54-
add_unique_suffix: bool = False,
55-
) -> Path:
48+
file: Path,
49+
output_dir: Path, # noqa: ARG002
50+
add_unique_suffix: bool = False, # noqa: ARG002
51+
) -> Path | Sequence[Cube]:
5652
"""Fix hybrid pressure coordinate.
5753
5854
Adds missing ``formula_terms`` attribute to file.
@@ -79,45 +75,38 @@ def fix_file(
7975
Path to the fixed file.
8076
8177
"""
82-
new_path = self._fix_formula_terms(
78+
dataset = ncdata.netcdf4.from_nc4(
8379
file,
84-
output_dir,
85-
add_unique_suffix=add_unique_suffix,
80+
# Use iris-style chunks to avoid mismatching chunks between data
81+
# and derived coordinates, as the latter are automatically rechunked
82+
# by iris.
83+
dim_chunks={
84+
"time": "auto",
85+
"lev": None,
86+
"lat": None,
87+
"lon": None,
88+
"nbnd": None,
89+
},
8690
)
87-
with Dataset(new_path, mode="a") as dataset:
88-
dataset.variables["a_bnds"][:] = dataset.variables["a_bnds"][
89-
::-1,
90-
:,
91-
]
92-
dataset.variables["b_bnds"][:] = dataset.variables["b_bnds"][
93-
::-1,
94-
:,
95-
]
96-
return new_path
97-
98-
def fix_metadata(self, cubes):
99-
"""Fix ``atmosphere_hybrid_sigma_pressure_coordinate``.
100-
101-
See discussion in #882 for more details on that.
102-
103-
Parameters
104-
----------
105-
cubes : iris.cube.CubeList
106-
Input cubes.
107-
108-
Returns
109-
-------
110-
iris.cube.CubeList
111-
112-
"""
113-
cube = self.get_cube_from_list(cubes)
114-
lev_coord = cube.coord(var_name="lev")
115-
a_coord = cube.coord(var_name="a")
116-
b_coord = cube.coord(var_name="b")
117-
lev_coord.points = a_coord.core_points() + b_coord.core_points()
118-
lev_coord.bounds = a_coord.core_bounds() + b_coord.core_bounds()
119-
lev_coord.units = "1"
120-
return cubes
91+
self._fix_formula_terms(dataset)
92+
93+
# Correct order of bounds data
94+
a_bnds = dataset.variables["a_bnds"]
95+
a_bnds.data = a_bnds.data[::-1, :]
96+
b_bnds = dataset.variables["b_bnds"]
97+
b_bnds.data = b_bnds.data[::-1, :]
98+
99+
# Correct lev and lev_bnds data
100+
lev = dataset.variables["lev"]
101+
lev.data = dataset.variables["a"].data + dataset.variables["b"].data
102+
lev_bnds = dataset.variables["lev_bnds"]
103+
lev_bnds.data = (
104+
dataset.variables["a_bnds"].data + dataset.variables["b_bnds"].data
105+
)
106+
# Remove 'title' attribute that duplicates long name
107+
for var_name in dataset.variables:
108+
dataset.variables[var_name].attributes.pop("title", None)
109+
return [self.get_cube_from_list(dataset_to_iris(dataset, file))]
121110

122111

123112
Cli = Cl

esmvalcore/cmor/_fixes/cmip6/cesm2_waccm.py

Lines changed: 37 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,13 @@
11
"""Fixes for CESM2-WACCM model."""
22

3-
from netCDF4 import Dataset
3+
from __future__ import annotations
4+
5+
from typing import TYPE_CHECKING
6+
7+
import ncdata.netcdf4
48

59
from esmvalcore.cmor._fixes.common import SiconcFixScalarCoord
10+
from esmvalcore.iris_helpers import dataset_to_iris
611

712
from .cesm2 import Cl as BaseCl
813
from .cesm2 import Fgco2 as BaseFgco2
@@ -12,11 +17,22 @@
1217
from .cesm2 import Tasmax as BaseTasmax
1318
from .cesm2 import Tasmin as BaseTasmin
1419

20+
if TYPE_CHECKING:
21+
from collections.abc import Sequence
22+
from pathlib import Path
23+
24+
from iris.cube import Cube
25+
1526

1627
class Cl(BaseCl):
1728
"""Fixes for cl."""
1829

19-
def fix_file(self, file, output_dir, add_unique_suffix=False):
30+
def fix_file(
31+
self,
32+
file: Path,
33+
output_dir: Path, # noqa: ARG002
34+
add_unique_suffix: bool = False, # noqa: ARG002
35+
) -> Path | Sequence[Cube]:
2036
"""Fix hybrid pressure coordinate.
2137
2238
Adds missing ``formula_terms`` attribute to file.
@@ -43,21 +59,27 @@ def fix_file(self, file, output_dir, add_unique_suffix=False):
4359
Path to the fixed file.
4460
4561
"""
46-
new_path = self._fix_formula_terms(
62+
dataset = ncdata.netcdf4.from_nc4(
4763
file,
48-
output_dir,
49-
add_unique_suffix=add_unique_suffix,
64+
# Use iris-style chunks to avoid mismatching chunks between data
65+
# and derived coordinates, as the latter are automatically rechunked
66+
# by iris.
67+
dim_chunks={
68+
"time": "auto",
69+
"lev": None,
70+
"lat": None,
71+
"lon": None,
72+
"nbnd": None,
73+
},
5074
)
51-
with Dataset(new_path, mode="a") as dataset:
52-
dataset.variables["a_bnds"][:] = dataset.variables["a_bnds"][
53-
:,
54-
::-1,
55-
]
56-
dataset.variables["b_bnds"][:] = dataset.variables["b_bnds"][
57-
:,
58-
::-1,
59-
]
60-
return new_path
75+
self._fix_formula_terms(dataset)
76+
77+
# Correct order of bounds data
78+
a_bnds = dataset.variables["a_bnds"]
79+
a_bnds.data = a_bnds.data[:, ::-1]
80+
b_bnds = dataset.variables["b_bnds"]
81+
b_bnds.data = b_bnds.data[:, ::-1]
82+
return [self.get_cube_from_list(dataset_to_iris(dataset, file))]
6183

6284

6385
Cli = Cl

0 commit comments

Comments
 (0)