3 Module containing utilities to manipulate netCDF4 files.
5 __author__ =
'gfireman'
11 from os.path
import basename
13 def nccopy_var(srcvar, dstgrp, indices=None, verbose=False):
14 """Copy a netCDF4 variable, optionally subsetting some dimensions.
16 Function to copy a single netCDF4 variable and associated attributes.
17 Optionally subset specified dimensions.
21 srcvar : netCDF4.Variable
22 Open variable to be copied
23 dstgrp : netCDF4.Group
24 Open Group or Dataset destination object to copy stuff to
25 indices : dict, optional
26 Dict of dimname:[indexarr] to subset a dimension
27 verbose : boolean, optional
32 Strings are written as H5T_CSET_ASCII, not H5T_CSET_UTF8
33 Empty attributes are written as scalar "" instead of NULL
37 zlib = srcvar.filters().get(
'zlib',
False)
38 shuffle = srcvar.filters().get(
'shuffle',
False)
39 complevel = srcvar.filters().get(
'complevel', 0)
45 for dimname
in srcvar.dimensions:
46 if dimname
in indices:
47 outputDims[dimname] = len(indices[dimname])
49 if srcvar.chunking() ==
'contiguous':
50 dstvar = dstgrp.createVariable(srcvar.name,
58 srcChunks =
list(srcvar.chunking())
60 for idx, dimname
in enumerate(srcvar.dimensions):
61 if dimname
in outputDims:
62 newChunks.append(min(srcChunks[idx], outputDims[dimname]))
64 newChunks.append(srcChunks[idx])
66 dstvar = dstgrp.createVariable(srcvar.name,
76 dstvar.setncatts(srcvar.__dict__)
79 if not indices
or not any(k
in indices
for k
in srcvar.dimensions):
81 print(
"\tcopying",srcvar.name)
87 print(
"\tsubsetting",srcvar.name)
89 for dimname
in indices:
91 axis = srcvar.dimensions.index(dimname)
94 tmpvar = np.take(tmpvar, indices[dimname], axis=axis)
102 """Recursively copy a netCDF4 group, optionally subsetting some dimensions.
104 Function to recursively copy a netCDF4 group,
105 with associated attributes, dimensions and variables.
106 Optionally subset specified dimensions.
110 srcgrp : netCDF4.Group
111 Open Group or Dataset source object containing stuff to be copied
112 dstgrp : netCDF4.Group
113 Open Group or Dataset destination object to copy stuff to
114 indices : dict, optional
115 Dict of dimname:[indexarr] to subset a dimension
116 verbose : boolean, optional
121 print(
'grp: ', srcgrp.path)
124 dstgrp.setncatts(srcgrp.__dict__)
127 for dimname, dim
in srcgrp.dimensions.items():
128 if dim.isunlimited():
130 elif indices
and dimname
in indices:
131 dimsize = len(indices[dimname])
134 dstgrp.createDimension(dimname, dimsize)
137 for varname, srcvar
in srcgrp.variables.items():
139 print(
'var: ',
'/'.join([srcgrp.path, srcvar.name]))
140 nccopy_var(srcvar, dstgrp, indices=indices, verbose=verbose)
143 for grpname, srcsubgrp
in srcgrp.groups.items():
144 dstsubgrp = dstgrp.createGroup(grpname)
145 nccopy_grp(srcsubgrp, dstsubgrp, indices=indices, verbose=verbose)
148 def nccopy(srcfile, dstfile, verbose=False):
149 """Copy a netCDF4 file.
151 Function to copy a netCDF4 file to a new file.
152 Intended mostly as a demonstration.
157 Path to source file; must be netCDF4 format.
159 Path to destination file; directory must exist.
160 verbose : boolean, optional
164 with netCDF4.Dataset(srcfile,
'r')
as src, \
165 netCDF4.Dataset(dstfile,
'w')
as dst:
167 print(
'\nfile:', src.filepath())
172 """Copy a netCDF4 file, with some dimensions subsetted.
174 Function to copy netCDF4 file to a new file,
176 Function to copy a single netCDF4 variable and associated attributes.
177 Optionally subset specified dimensions.
182 Path to source file; must be netCDF4 format.
184 Path to destination file; directory must exist.
185 subset : dict, optional
186 Dict of dimname:[startindex,endindex] to subset a dimension
187 verbose : boolean, optional
192 Strings are written as H5T_CSET_ASCII, not H5T_CSET_UTF8
193 Empty attributes are written as scalar "" instead of NULL
200 print(
'opening', srcfile)
201 with netCDF4.Dataset(srcfile,
'r')
as src:
204 for dimname
in subset:
205 if dimname
not in src.dimensions:
206 print(
'Warning: dimension "' +
207 dimname +
'" does not exist in input file root group.')
208 if (subset[dimname][0] > subset[dimname][1]):
209 print(
'Invalid indices for dimension "' +
210 dimname +
'"; exiting.')
212 for dimname, dim
in src.dimensions.items():
213 if ((dimname
in subset)
and
214 any((0 > d
or d > len(dim) - 1)
for d
in subset[dimname])):
215 oldsubset = subset.copy()
216 subset[dimname] = np.clip(subset[dimname], a_min=0,
217 a_max=len(dim) - 1).tolist()
218 print(
'Clipping "' + dimname +
219 '" dimension indices to match input file:',
220 oldsubset[dimname],
'->', subset[dimname])
223 indices = {k : np.arange(subset[k][0],
224 subset[k][1] + 1)
for k
in subset}
228 print(
'opening', dstfile)
229 with netCDF4.Dataset(dstfile,
'w')
as dst:
230 nccopy_grp(src, dst, indices=indices, verbose=verbose)
238 """Update 'date_created' and 'history' attributes
240 Function to add or update 'date_created' and 'history'
241 attributes for specified dataset (usually root).
245 dataset : netCDF4.Group
246 Open Group or Dataset destination object to update
247 timestamp : time.struct_time, optional
248 Timestamp to add to history attribute
249 Defaults to current time
250 cmdline : string, optional
251 Description to add to history attribute
255 timestamp = time.gmtime()
256 fmt =
'%Y-%m-%dT%H:%M:%SZ'
257 date_created = time.strftime(fmt, timestamp)
260 cmdline =
' '.join([
basename(sys.argv[0])]+sys.argv[1:])
261 cmdline =
''.join([date_created,
': ', cmdline])
262 if 'history' in dataset.ncattrs():
263 history =
''.join([dataset.history.strip(),
'; ', cmdline])
267 dataset.setncattr(
'date_created', date_created)
268 dataset.setncattr(
'history', history)