Skip to content

Commit ddd41cc

Browse files
committed
Compute uv with stencil method on regular dataset
1 parent 7b7b649 commit ddd41cc

File tree

1 file changed

+59
-34
lines changed

1 file changed

+59
-34
lines changed

src/py_eddy_tracker/dataset/grid.py

Lines changed: 59 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -202,6 +202,7 @@ class GridDataset(object):
202202

203203
GRAVITY = 9.807
204204
EARTH_RADIUS = 6370997.
205+
# EARTH_RADIUS = 6378136.3
205206
N = 1
206207

207208
def __init__(self, filename, x_name, y_name, centered=None):
@@ -374,7 +375,6 @@ def copy(self, grid_in, grid_out):
374375
)
375376
self.vars[grid_out] = self.grid(grid_in).copy()
376377

377-
378378
def grid(self, varname):
379379
"""give grid required
380380
"""
@@ -1068,6 +1068,7 @@ def spectrum_lonlat(self, grid_name, area=None, ref=None, **kwargs):
10681068
def add_uv(self, grid_height):
10691069
"""Compute a u and v grid
10701070
"""
1071+
data = self.grid(grid_height)
10711072
h_dict = self.variables_description[grid_height]
10721073
for variable in ('u', 'v'):
10731074
self.variables_description[variable] = dict(
@@ -1076,44 +1077,67 @@ def add_uv(self, grid_height):
10761077
args=tuple((variable, *h_dict['args'][1:])),
10771078
kwargs=h_dict['kwargs'].copy(),
10781079
)
1080+
10791081
self.variables_description[variable]['attrs']['units'] += '/s'
1080-
data = self.grid(grid_height)
1081-
gof = sin(deg2rad(self.y_c)) * ones((self.x_c.shape[0], 1)) * 4. * pi / 86400.
1082-
# gof = sin(deg2rad(self.y_c))* ones((self.x_c.shape[0], 1)) * 4. * pi / (23 * 3600 + 56 *60 +4.1 )
1082+
# Divide by sideral day
1083+
gof = sin(deg2rad(self.y_c)) * ones((self.x_c.shape[0], 1)) * 4. * pi / (23 * 3600 + 56 * 60 + 4.1)
10831084
with errstate(divide='ignore'):
10841085
gof = self.GRAVITY / (gof * ones((self.x_c.shape[0], 1)))
10851086

1086-
m_y = array((1, 0, -1))
1087-
m_x = array((1, 0, -1))
1088-
d_hy = convolve(
1089-
data,
1090-
weights=m_y.reshape((-1, 1)).T
1091-
)
1092-
mask = convolve(
1093-
int8(data.mask),
1094-
weights=ones(m_y.shape).reshape((1, -1))
1095-
)
1096-
d_hy = ma.array(d_hy, mask=mask != 0)
1087+
w = [
1088+
array((3, -32, 168, -672, 0, 672, -168, 32, -3)) / 840.,
1089+
array((-1, 9, -45, 0, 45, -9, 1)) / 60.,
1090+
array((1, -8, 0, 8, -1)) / 12.,
1091+
array((-1, 0, 1)) /2.,
1092+
array((-1, 1)), # array((0, -1, 1))
1093+
(1, array((-1, 1))), # array((-1, 1, 0))
1094+
]
1095+
1096+
# Compute v
1097+
self.vars['v'] = None
1098+
mode = 'wrap' if self.is_circular() else 'reflect'
1099+
for m_x in w:
1100+
if isinstance(m_x, tuple):
1101+
shift, m_x = m_x
1102+
data_ = data.copy()
1103+
data_[shift:] = data[:-shift]
1104+
data_[:shift] = data[-shift:]
1105+
else:
1106+
data_ = data
1107+
d_hx = convolve(data_, weights=m_x.reshape((-1, 1)), mode=mode)
1108+
mask = convolve(int8(data_.mask), weights=ones(m_x.shape).reshape((-1, 1)), mode=mode)
1109+
d_hx = ma.array(d_hx, mask=mask != 0)
1110+
1111+
d_x_degrees = convolve(self.x_c, m_x, mode=mode).reshape((-1, 1))
1112+
d_x_degrees = (d_x_degrees + 180) % 360 - 180
1113+
d_x = self.EARTH_RADIUS * 2 * pi / 360 * d_x_degrees * cos(deg2rad(self.y_c))
1114+
v = d_hx / d_x * gof
1115+
if self.vars['v'] is None:
1116+
self.vars['v'] = v
1117+
else:
1118+
self.vars['v'][self.vars['v'].mask] = v[self.vars['v'].mask]
1119+
1120+
# Compute u
1121+
self.vars['u'] = None
1122+
for m_y in w:
1123+
if isinstance(m_y, tuple):
1124+
shift, m_y = m_y
1125+
data_ = data.copy()
1126+
data_[:, shift:] = data[:, :-1]
1127+
else:
1128+
data_ = data
10971129

1098-
d_y = self.EARTH_RADIUS * 2 * pi / 360 * convolve(self.y_c, m_y)
1130+
d_hy = convolve(data_, weights=m_y.reshape((-1, 1)).T)
1131+
mask = convolve(int8(data_.mask), weights=ones(m_y.shape).reshape((1, -1)))
1132+
d_hy = ma.array(d_hy, mask=mask != 0)
10991133

1100-
self.vars['u'] = - d_hy / d_y * gof
1101-
mode = 'wrap' if self.is_circular() else 'reflect'
1102-
d_hx = convolve(
1103-
data,
1104-
weights=m_x.reshape((-1, 1)),
1105-
mode=mode,
1106-
)
1107-
mask = convolve(
1108-
int8(data.mask),
1109-
weights=ones(m_x.shape).reshape((-1, 1)),
1110-
mode=mode,
1111-
)
1112-
d_hx = ma.array(d_hx, mask=mask != 0)
1113-
d_x_degrees = convolve(self.x_c, m_x, mode=mode).reshape((-1, 1))
1114-
d_x_degrees = (d_x_degrees + 180) % 360 - 180
1115-
d_x = self.EARTH_RADIUS * 2 * pi / 360 * d_x_degrees * cos(deg2rad(self.y_c))
1116-
self.vars['v'] = d_hx / d_x * gof
1134+
d_y = self.EARTH_RADIUS * 2 * pi / 360 * convolve(self.y_c, m_y)
1135+
1136+
u = - d_hy / d_y * gof
1137+
if self.vars['u'] is None:
1138+
self.vars['u'] = u
1139+
else:
1140+
self.vars['u'][self.vars['u'].mask] = u[self.vars['u'].mask]
11171141

11181142
def speed_coef_mean(self, contour):
11191143
"""some nan can be compute over contour if we are near border,
@@ -1226,8 +1250,9 @@ def bbox_indice_regular(vertices, x0, y0, xstep, ystep, N, circular, x_size):
12261250
lat_min, lat_max = lat.min(), lat.max()
12271251
i_x0, i_y0 = int32(((lon_min - x0) % 360) // xstep), int32((lat_min - y0) // ystep)
12281252
i_x1, i_y1 = int32(((lon_max - x0) % 360) // xstep), int32((lat_max - y0) // ystep)
1229-
12301253
if circular:
12311254
slice_x = (i_x0 - N) % x_size, (i_x1 + N + 1) % x_size
1255+
else:
1256+
slice_x = min(i_x0 - N, 0), i_x1 + N + 1
12321257
slice_y = i_y0 - N, i_y1 + N + 1
12331258
return slice_x, slice_y

0 commit comments

Comments
 (0)