/
domainaxis.py
321 lines (222 loc) · 8.26 KB
/
domainaxis.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
import logging
from . import core, mixin
from .decorators import _manage_log_level_via_verbosity
logger = logging.getLogger(__name__)
class DomainAxis(
mixin.NetCDFDimension,
mixin.NetCDFUnlimitedDimension,
mixin.Container,
core.DomainAxis,
):
"""A domain axis construct of the CF data model.
A domain axis construct specifies the number of points along an
independent axis of the domain. It comprises a positive integer
representing the size of the axis. In CF-netCDF it is usually
defined either by a netCDF dimension or by a scalar coordinate
variable, which implies a domain axis of size one. The field
construct's data array spans the domain axis constructs of the
domain, with the optional exception of size one axes, because
their presence makes no difference to the order of the elements.
**NetCDF interface**
The netCDF dimension name of the construct may be accessed with
the `nc_set_dimension`, `nc_get_dimension`, `nc_del_dimension`,
and `nc_has_dimension` methods.
Whether or not the netCDF is unlimited may be accessed with the
`nc_is_unlimited` and `nc_set_unlimited` methods.
The netCDF dimension group structure may be accessed with the
`nc_set_dimension`, `nc_get_dimension`, `nc_dimension_groups`,
`nc_clear_dimension_groups`, and `nc_set_dimension_groups` methods.
.. versionadded:: (cfdm) 1.7.0
"""
def __init__(self, size=None, source=None, copy=True):
"""**Initialisation**
:Parameters:
size: `int`, optional
The size of the domain axis.
The size may also be set after initialisation with the
`set_size` method.
*Parameter example:*
``size=192``
{{init source: optional}}
{{init copy: `bool`, optional}}
"""
super().__init__(size=size, source=source, copy=copy)
self._initialise_netcdf(source)
def __str__(self):
"""Called by the `str` built-in function.
x.__str__() <==> str(x)
.. versionadded:: (cfdm) 1.7.0
"""
return f"size({self.get_size('')})"
def _identities_iter(self):
"""Return all possible identities.
See `identities` for details and examples.
:Returns:
generator
The identities.
"""
n = self.nc_get_dimension(None)
if n is not None:
yield f"ncdim%{n}"
def creation_commands(
self, namespace=None, indent=0, string=True, name="c", header=True
):
"""Returns the commands to create the domain axis construct.
.. versionadded:: (cfdm) 1.8.7.0
.. seealso:: `{{package}}.Field.creation_commands`
:Parameters:
{{namespace: `str`, optional}}
{{indent: `int`, optional}}
{{string: `bool`, optional}}
{{name: `str`, optional}}
{{header: `bool`, optional}}
:Returns:
{{returns creation_commands}}
**Examples**
>>> x = {{package}}.DomainAxis(size=12)
>>> x.nc_set_dimension('time')
>>> print(x.creation_commands(header=False))
c = {{package}}.DomainAxis()
c.set_size(12)
c.nc_set_dimension('time')
"""
if namespace is None:
namespace = self._package() + "."
elif namespace and not namespace.endswith("."):
namespace += "."
out = []
if header:
out.append("#")
out.append(f"# {self.construct_type}:")
identity = self.identity()
if identity:
out[-1] += f" {identity}"
out.append(f"{name} = {namespace}{self.__class__.__name__}()")
size = self.get_size(None)
if size is not None:
out.append(f"{name}.set_size({size})")
nc = self.nc_get_dimension(None)
if nc is not None:
out.append(f"{name}.nc_set_dimension({nc!r})")
if self.nc_is_unlimited():
out.append("fc.nc_set_unlimited({True})")
if string:
indent = " " * indent
out[0] = indent + out[0]
out = (f"\n{indent}").join(out)
return out
@_manage_log_level_via_verbosity
def equals(self, other, verbose=None, ignore_type=False):
"""Whether two domain axis constructs are the same.
Equality is strict by default. This means that:
* the axis sizes must be the same.
Any type of object may be tested but, in general, equality is
only possible with another domain axis construct, or a
subclass of one. See the *ignore_type* parameter.
NetCDF elements, such as netCDF variable and dimension names,
do not constitute part of the CF data model and so are not
checked.
.. versionadded:: (cfdm) 1.7.0
:Parameters:
other:
The object to compare for equality.
{{verbose: `int` or `str` or `None`, optional}}
{{ignore_type: `bool`, optional}}
:Returns:
`bool`
Whether the two domain axis constructs are equal.
**Examples**
>>> d.equals(d)
True
>>> d.equals(d.copy())
True
>>> d.equals('not a domain axis')
False
>>> d = {{package}}.DomainAxis(1)
>>> e = {{package}}.DomainAxis(99)
>>> d.equals(e, verbose=3)
DomainAxis: Different axis sizes: 1 != 99
False
"""
pp = super()._equals_preprocess(
other, verbose=verbose, ignore_type=ignore_type
)
if pp is True or pp is False:
return pp
other = pp
# Check that each axis has the same size
self_size = self.get_size(None)
other_size = other.get_size(None)
if not self_size == other_size:
logger.info(
f"{self.__class__.__name__}: Different axis sizes: "
f"{self_size} != {other_size}"
)
return False
return True
def identity(self, default=""):
"""Return the canonical identity.
The identity is the first found of the following:
1. The netCDF dimension name, preceded by 'ncdim%'.
2. The value of the default parameter.
.. versionadded:: (cfdm) 1.7.0
.. seealso:: `identities`
:Parameters:
default: optional
If no identity can be found then return the value of
the default parameter.
:Returns:
The identity.
**Examples**
>>> d = {{package}}.DomainAxis(size=9)
>>> d.nc_set_dimension('time')
>>> d.identity()
'ncdim%time'
>>> d.identity(default='no identity')
'ncdim%time'
>>> d.nc_del_dimension()
'time'
>>> d.identity()
''
>>> d.identity(default='no identity')
'no identity'
"""
n = self.nc_get_dimension(None)
if n is not None:
return f"ncdim%{n}"
return default
def identities(self, generator=False, **kwargs):
"""Return all possible identities.
The identities comprise:
* The netCDF dimension name, preceded by 'ncdim%'.
.. versionadded:: (cfdm) 1.7.0
.. seealso:: `identity`
:Parameters:
generator: `bool`, optional
If True then return a generator for the identities,
rather than a list.
.. versionadded:: (cfdm) 1.8.9.0
kwargs: optional
Additional configuration parameters. Currently
none. Unrecognised parameters are ignored.
.. versionadded:: (cfdm) 1.8.9.0
:Returns:
`list` or generator
The identities.
**Examples**
>>> d = {{package}}.DomainAxis(size=9)
>>> d.nc_set_dimension('time')
>>> d.identities()
['ncdim%time']
>>> d.nc_del_dimension()
'time'
>>> d.identities()
[]
>>> for i in d.identities(generator=True):
... print(i)
...
"""
g = self._iter(body=self._identities_iter(), **kwargs)
if generator:
return g
return list(g)