-
Notifications
You must be signed in to change notification settings - Fork 19
/
regridoperator.py
241 lines (179 loc) · 6.14 KB
/
regridoperator.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
from .. import _found_ESMF
if _found_ESMF:
try:
import ESMF
except Exception:
_found_ESMF = False
if _found_ESMF:
regrid_method_map = {
"linear": ESMF.RegridMethod.BILINEAR, # see comment below...
"bilinear": ESMF.RegridMethod.BILINEAR, # (for back compat)
"conservative": ESMF.RegridMethod.CONSERVE,
"conservative_1st": ESMF.RegridMethod.CONSERVE,
"conservative_2nd": ESMF.RegridMethod.CONSERVE_2ND,
"nearest_dtos": ESMF.RegridMethod.NEAREST_DTOS,
"nearest_stod": ESMF.RegridMethod.NEAREST_STOD,
"patch": ESMF.RegridMethod.PATCH,
}
# ... diverge from ESMF with respect to name for bilinear method
# by using 'linear' because 'bi' implies 2D linear interpolation,
# which could mislead or confuse for Cartesian regridding in 1D or
# 3D.
else:
# Initialize a place holder that may be imported when ESMF is not
# installed
regrid_method_map = {}
regrid_method_map_inverse = {v: k for k, v in regrid_method_map.items()}
conservative_regridding_methods = (
"conservative",
"conservative_1st",
"conservative_2nd",
)
regridding_methods = (
"linear", # prefer over 'bilinear' as of v3.2.0
"bilinear", # only for backward compatibility, use & document 'linear'
"patch",
"nearest_stod",
"nearest_dtos",
) + conservative_regridding_methods
class RegridOperator:
"""A regridding operator between two fields.
Stores an `ESMF.Regrid` regridding operator and associated
parameters that describe the complete coordinate system of the
destination grid.
"""
def __init__(self, regrid, name, **parameters):
"""**Initialization**
:Parameters:
regrid: `ESMF.Regrid`
The `ESMF` regridding operator between two fields.
name: `str`
A name that defines the context of the destination
grid parameters.
parameters: `dict`
Parameters that describe the complete coordinate system
of the destination grid.
Any parameter names and values are allowed, and it is
assumed that the these are well defined during the
creation and subsequent use of a `RegridOperator`
instance.
"""
self._regrid = regrid
self._name = name
self._parameters = parameters
def __del__(self):
"""Calls the `ESMF.Regrid` destroy method."""
self._regrid.destroy()
def __repr__(self):
return (
f"<CF {self.__class__.__name__}: "
f"{self._name}, method={self.method}>"
)
@property
def method(self):
"""The regridding method.
**Examples**
>>> r.method
'conservative'
"""
method = regrid_method_map_inverse[self._regrid.regrid_method]
if method == "bilinear":
method = "linear"
return method
@property
def name(self):
"""The name of the regrid method.
**Examples**
>>> r.name
'regrids'
"""
return self._name
@property
def parameters(self):
"""The parameters that describe the destination grid.
Any parameter names and values are allowed, and it is assumed
that the these are well defined during the creation and
subsequent use of a `RegridOperator` instance.
**Examples**
>>> type(r.parameters)
dict
"""
return self._parameters
@property
def regrid(self):
"""The contained regridding operator.
**Examples**
>>> type(r.regrid)
ESMF.api.regrid.Regrid
"""
return self._regrid
def check_method(self, method):
"""Whether the given method is equivalent to the regridding
method.
:Parameters:
method: `str`
A regridding method, such as ``'conservative'``.
:Returns:
`bool`
Whether or not method is equivalent to the regridding
method.
**Examples**
>>> r.method
'conservative'
>>> r.check_method('conservative')
True
>>> r.check_method('conservative_1st')
True
>>> r.check_method('conservative_2nd')
False
"""
return regrid_method_map.get(method) == self._regrid.regrid_method
def copy(self):
"""Return a copy.
The contained `ESMF.Regrid` instance (see `regrid`) is shallow
copied and the "dst" parameter, which is a `Field` or `dict`
instance, is copied with its `!copy` method.
:Returns:
`RegridOperator`
The copy.
**Examples**
>>> s = r.copy()
"""
parameters = self._parameters
if "dst" in parameters:
parameters = parameters.copy()
parameters["dst"] = parameters["dst"].copy()
return type(self)(
regrid=self._regrid.copy(), name=self._name, **parameters
)
def destroy(self):
"""Free the memory allocated by the `ESMF.Regrid` instance.
**Examples**
>>> r.destroy()
"""
# explicitly release memory for source ESMF objects
self._regrid.srcfield.grid.destroy()
self._regrid.srcfield.destroy()
self._regrid.src_frac_field.destroy()
# explicitly release memory for destination ESMF objects
self._regrid.dstfield.grid.destroy()
self._regrid.dstfield.destroy()
self._regrid.dst_frac_field.destroy()
# explicitly release memory for ESMF Regrid
self._regrid.destroy()
def get_parameter(self, parameter):
"""Return a regrid operation parameter.
**Examples**
>>> r.get_parameter('ignore_degenerate')
True
>>> r.get_parameter('x')
Traceback
...
ValueError: RegridOperator has no 'x' parameter
"""
try:
return self._parameters[parameter]
except KeyError:
raise ValueError(
f"{self.__class__.__name__} has no {parameter!r} parameter"
)