Skip to content

Commit 3705771

Browse files
committed
Initial insertion of Ugrid into CF loading.
1 parent 656a2b1 commit 3705771

File tree

6 files changed

+130
-16
lines changed

6 files changed

+130
-16
lines changed
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
# Copyright Iris contributors
2+
#
3+
# This file is part of Iris and is released under the LGPL license.
4+
# See COPYING and COPYING.LESSER in the root of the repository for full
5+
# licensing details.
6+
"""
7+
Adds a UGRID extension layer to netCDF file loading.
8+
9+
"""
10+
import os
11+
12+
import netCDF4
13+
14+
from gridded.pyugrid.ugrid import UGrid
15+
from gridded.pyugrid.read_netcdf import (
16+
find_mesh_names,
17+
load_grid_from_nc_dataset,
18+
)
19+
from iris.fileformats.cf import CFReader
20+
21+
22+
_UGRID_ELEMENT_TYPE_NAMES = ("node", "edge", "face", "volume")
23+
24+
_UGRID_LINK_PROPERTIES = [
25+
"{}_coordinates".format(elem) for elem in _UGRID_ELEMENT_TYPE_NAMES
26+
]
27+
_UGRID_LINK_PROPERTIES += [
28+
"{}_{}_connectivity".format(e1, e2)
29+
for e1 in _UGRID_ELEMENT_TYPE_NAMES
30+
for e2 in _UGRID_ELEMENT_TYPE_NAMES
31+
]
32+
33+
# print('')
34+
# print('Ugrid link properties ...')
35+
# print('\n'.join(_UGRID_LINK_PROPERTIES))
36+
37+
38+
class UGridCFReader:
39+
def __init__(self, filename, *args, **kwargs):
40+
self.filename = os.path.expanduser(filename)
41+
dataset = netCDF4.Dataset(self.filename, mode="r")
42+
self.dataset = dataset
43+
meshes = {}
44+
for meshname in find_mesh_names(self.dataset):
45+
mesh = UGrid()
46+
load_grid_from_nc_dataset(dataset, mesh, mesh_name=meshname)
47+
meshes[meshname] = mesh
48+
self.meshes = meshes
49+
# Generate list of excluded variable names.
50+
exclude_vars = list(meshes.keys())
51+
for mesh in meshes.values():
52+
mesh_var = dataset.variables[mesh.mesh_name]
53+
for attr in mesh_var.ncattrs():
54+
if attr in _UGRID_LINK_PROPERTIES:
55+
exclude_vars.extend(mesh_var.getncattr(attr).split())
56+
print("")
57+
print("File {}".format(filename, meshes))
58+
print("File meshes={}".format(meshes))
59+
print("")
60+
print("File exclude vars={}".format(exclude_vars))
61+
print("")
62+
print(
63+
"File remaining vars={}".format(
64+
[x for x in dataset.variables.keys() if x not in exclude_vars]
65+
)
66+
)
67+
kwargs["exclude_var_names"] = exclude_vars
68+
self.cfreader = CFReader(self.dataset, *args, **kwargs)
69+
70+
def complete_ugrid_cube(self, cube):
71+
pass
72+
73+
def __del__(self):
74+
# Explicitly close dataset to prevent file remaining open.
75+
self.dataset.close()

lib/iris/fileformats/cf.py

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,9 @@
1717
from abc import ABCMeta, abstractmethod
1818

1919
from collections.abc import Iterable, MutableMapping
20-
import os
2120
import re
2221
import warnings
2322

24-
import netCDF4
2523
import numpy as np
2624
import numpy.ma as ma
2725

@@ -1008,8 +1006,12 @@ class CFReader:
10081006
10091007
"""
10101008

1011-
def __init__(self, filename, warn=False, monotonic=False):
1012-
self._filename = os.path.expanduser(filename)
1009+
def __init__(
1010+
self, dataset, warn=False, monotonic=False, exclude_var_names=None
1011+
):
1012+
self._dataset = dataset
1013+
self._filename = dataset.filepath()
1014+
10131015
# All CF variable types EXCEPT for the "special cases" of
10141016
# CFDataVariable, CFCoordinateVariable and _CFFormulaTermsVariable.
10151017
self._variable_types = (
@@ -1025,8 +1027,6 @@ def __init__(self, filename, warn=False, monotonic=False):
10251027
#: Collection of CF-netCDF variables associated with this netCDF file
10261028
self.cf_group = CFGroup()
10271029

1028-
self._dataset = netCDF4.Dataset(self._filename, mode="r")
1029-
10301030
# Issue load optimisation warning.
10311031
if warn and self._dataset.file_format in [
10321032
"NETCDF3_CLASSIC",
@@ -1260,10 +1260,6 @@ def _reset(self):
12601260
for nc_var_name in self._dataset.variables.keys():
12611261
self.cf_group[nc_var_name].cf_attrs_reset()
12621262

1263-
def __del__(self):
1264-
# Explicitly close dataset to prevent file remaining open.
1265-
self._dataset.close()
1266-
12671263

12681264
def _getncattr(dataset, attr, default=None):
12691265
"""

lib/iris/fileformats/netcdf.py

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@
4444
import iris.exceptions
4545
import iris.fileformats.cf
4646
import iris.fileformats._pyke_rules
47+
from iris.fileformats._ugrid_cf_reader import UGridCFReader
4748
import iris.io
4849
import iris.util
4950
from iris._lazy_data import as_lazy_data
@@ -778,14 +779,17 @@ def load_cubes(filenames, callback=None):
778779

779780
for filename in filenames:
780781
# Ingest the netCDF file.
781-
cf = iris.fileformats.cf.CFReader(filename)
782+
# ncreader = iris.fileformats.cf.CFReader(filename)
783+
ncreader = UGridCFReader(filename)
782784

783785
# Process each CF data variable.
784-
data_variables = list(cf.cf_group.data_variables.values()) + list(
785-
cf.cf_group.promoted.values()
786-
)
786+
data_variables = list(
787+
ncreader.cfreader.cf_group.data_variables.values()
788+
) + list(ncreader.cfreader.cf_group.promoted.values())
787789
for cf_var in data_variables:
788-
cube = _load_cube(engine, cf, cf_var, filename)
790+
cube = _load_cube(engine, ncreader.cfreader, cf_var, filename)
791+
792+
ncreader.complete_ugrid_cube(cube)
789793

790794
# Process any associated formula terms and attach
791795
# the corresponding AuxCoordFactory.
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
# Copyright Iris contributors
2+
#
3+
# This file is part of Iris and is released under the LGPL license.
4+
# See COPYING and COPYING.LESSER in the root of the repository for full
5+
# licensing details.
6+
"""
7+
Integration tests for the
8+
:mod:`iris.fileformats._structured_array_identification` module.
9+
10+
"""
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
# Copyright Iris contributors
2+
#
3+
# This file is part of Iris and is released under the LGPL license.
4+
# See COPYING and COPYING.LESSER in the root of the repository for full
5+
# licensing details.
6+
"""
7+
Integration tests for the
8+
:mod:`iris.fileformats._ugrid_cf_reader.UGridCFReader` class.
9+
10+
"""
11+
12+
# Import iris.tests first so that some things can be initialised before
13+
# importing anything else.
14+
import iris.tests as tests
15+
16+
import iris
17+
18+
19+
class TestUgrid(tests.IrisTest):
20+
def test_basic_load(self):
21+
fp = "/project/avd/ng-vat/data/sam_adams_tiny_test_files/lfric_diag.nc"
22+
cubes = iris.load(fp)
23+
print(cubes)
24+
cube = iris.load_cube(fp, "theta")
25+
print(cube)
26+
27+
28+
if __name__ == "__main__":
29+
tests.main()

lib/iris/tests/unit/fileformats/structured_array_identification/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,6 @@
55
# licensing details.
66
"""
77
Unit tests for the
8-
:mod:`iris.fileformats._structured_array_identification` module.
8+
:mod:`iris.fileformats._ugrid_cf_reader` module.
99
1010
"""

0 commit comments

Comments
 (0)