-
Notifications
You must be signed in to change notification settings - Fork 23
/
make_salt_sfc_restore.py
176 lines (135 loc) · 5.25 KB
/
make_salt_sfc_restore.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
#!/usr/bin/env python
import numpy as np
import sys
import numba
import os
import argparse
import netCDF4 as nc
import shutil
from scipy.ndimage.filters import uniform_filter
from make_remap_weights import create_weights
from esmgrids.mom_grid import MomGrid # noqa
from esmgrids.woa_grid import WoaGrid # noqa
"""
Create MOM salt_sfc_restore.nc file from WOA
"""
def calc_regridding_err(weights, src, dest):
"""
Calculate the regridding error.
"""
EARTH_RADIUS = 6370997.0
with nc.Dataset(weights) as f:
try:
area_a = f.variables['area_a'][:]
except KeyError as e:
area_a = f.variables['src_grid_area'][:]
area_a = area_a.reshape(src.shape[0], src.shape[1])
area_a = area_a*EARTH_RADIUS**2
try:
area_b = f.variables['area_b'][:]
except KeyError as e:
area_b = f.variables['dst_grid_area'][:]
area_b = area_b.reshape(dest.shape[0], dest.shape[1])
area_b = area_b*EARTH_RADIUS**2
try:
frac_a = f.variables['frac_a'][:]
except KeyError as e:
frac_a = f.variables['src_grid_frac'][:]
frac_a = frac_a.reshape(src.shape[0], src.shape[1])
try:
frac_b = f.variables['frac_b'][:]
except KeyError as e:
frac_b = f.variables['dst_grid_frac'][:]
frac_b = frac_b.reshape(dest.shape[0], dest.shape[1])
# Calculation of totals here.
# http://www.earthsystemmodeling.org/esmf_releases/non_public/ESMF_5_3_0/ESMC_crefdoc/node3.html
src_tot = np.sum(src[:, :] * area_a[:, :] * frac_a[:, :])
dest_tot = np.sum(dest[:, :] * area_b[:, :])
rel_err = abs(src_tot - dest_tot) / dest_tot
return rel_err
@numba.jit
def apply_weights(src, dest_shape, n_s, n_b, row, col, s):
"""
Apply ESMF regirdding weights.
"""
dest = np.ndarray(dest_shape).flatten()
dest[:] = 0.0
src = src.flatten()
for i in range(n_s):
dest[row[i]-1] = dest[row[i]-1] + s[i]*src[col[i]-1]
return dest.reshape(dest_shape)
def remap(src_data, weights, dest_shape):
"""
Regrid a 2d field and see how it looks.
"""
dest_data = np.ndarray(dest_shape)
with nc.Dataset(weights) as wf:
try:
n_s = wf.dimensions['n_s'].size
except KeyError as e:
n_s = wf.dimensions['num_links'].size
try:
n_b = wf.dimensions['n_b'].size
except KeyError as e:
n_b = wf.dimensions['dst_grid_size'].size
try:
row = wf.variables['row'][:]
except KeyError as e:
row = wf.variables['dst_address'][:]
try:
col = wf.variables['col'][:]
except KeyError as e:
col = wf.variables['src_address'][:]
s = wf.variables['S'][:]
dest_data[:, :] = apply_weights(src_data[:, :], dest_data.shape,
n_s, n_b, row, col, s)
return dest_data
def smooth2d(src):
tmp_src = np.ndarray((src.shape[0] + 6, src.shape[1]))
# Window size
ws = 3
tmp_src[ws:-ws, :] = src[:, :]
tmp_src[:ws, :] = src[-ws:, :]
tmp_src[-ws:, :] = src[:3, :]
dest = uniform_filter(tmp_src, size=ws, mode='nearest')
return dest[ws:-ws, :]
def main():
parser = argparse.ArgumentParser()
parser.add_argument('woa_input', help='The WOA input file.')
parser.add_argument('ocean_hgrid',
help='The horizontal MOM grid definition to remap to')
parser.add_argument('old_salt_sfc_restore',
help='The old salt sfc restoring file. Needed for metadata.')
parser.add_argument('output', help='salt_sfc_restore.nc file for MOM5')
parser.add_argument('--interpolation_weights', default=None,
help='Interpolation weights, file if not given this will be created.')
parser.add_argument('--method', default='patch', help="""
Interpolation method, passed to ESMF_RegridWeightGen.""")
parser.add_argument('--npes', default=None, help="""
The number of PEs to use. Default is 1/2 of available.""")
args = parser.parse_args()
if args.npes is None:
import multiprocessing as mp
args.npes = mp.cpu_count() // 2
src_grid = WoaGrid(args.woa_input, calc_areas=False)
dest_grid = MomGrid.fromfile(args.ocean_hgrid, calc_areas=False)
dest_res = (dest_grid.num_lat_points, dest_grid.num_lon_points)
if args.interpolation_weights is None:
weights = create_weights(src_grid, dest_grid, args.npes, args.method)
else:
weights = args.interpolation_weights
with nc.Dataset(args.woa_input) as f:
src = f.variables['so'][:]
dest = np.zeros((src.shape[0], dest_res[0], dest_res[1]))
for t in range(src.shape[0]):
smooth_src = smooth2d(src[t, :, :])
dest[t, :, :] = remap(smooth_src, weights, dest_res)
if 'conserve' in args.method:
rel_err = calc_regridding_err(weights, smooth_src, dest[t, :, :])
print('relative error {}'.format(rel_err))
assert rel_err < 1e-14
shutil.copyfile(args.old_salt_sfc_restore, args.output)
with nc.Dataset(args.output, 'r+') as f:
f.variables['salt'][:] = dest
if __name__ == '__main__':
sys.exit(main())