roms-tools 0.0.2__py3-none-any.whl → 0.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- ci/environment.yml +28 -0
- roms_tools/__init__.py +3 -0
- roms_tools/_version.py +1 -1
- roms_tools/setup/atmospheric_forcing.py +993 -0
- roms_tools/setup/datasets.py +48 -0
- roms_tools/setup/fill.py +263 -0
- roms_tools/setup/grid.py +483 -324
- roms_tools/setup/plot.py +58 -0
- roms_tools/setup/tides.py +676 -0
- roms_tools/setup/topography.py +242 -0
- roms_tools/tests/test_setup.py +145 -18
- roms_tools-0.1.0.dist-info/METADATA +89 -0
- roms_tools-0.1.0.dist-info/RECORD +17 -0
- {roms_tools-0.0.2.dist-info → roms_tools-0.1.0.dist-info}/WHEEL +1 -1
- {roms_tools-0.0.2.dist-info → roms_tools-0.1.0.dist-info}/top_level.txt +2 -0
- roms_tools/setup/old_grid_script.py +0 -438
- roms_tools-0.0.2.dist-info/METADATA +0 -134
- roms_tools-0.0.2.dist-info/RECORD +0 -11
- {roms_tools-0.0.2.dist-info → roms_tools-0.1.0.dist-info}/LICENSE +0 -0
|
@@ -1,438 +0,0 @@
|
|
|
1
|
-
import netCDF4
|
|
2
|
-
import numpy as np
|
|
3
|
-
|
|
4
|
-
import matplotlib.pyplot as plt
|
|
5
|
-
import copy
|
|
6
|
-
from scipy.interpolate import RegularGridInterpolator
|
|
7
|
-
|
|
8
|
-
import cartopy.crs as ccrs
|
|
9
|
-
import matplotlib.pyplot as plt
|
|
10
|
-
|
|
11
|
-
from datetime import date
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
def generate_grid(grdname, nx, ny, size_x, size_y, tra_lon, tra_lat, rot):
|
|
16
|
-
|
|
17
|
-
r_earth = 6371315.0
|
|
18
|
-
|
|
19
|
-
## Mercator projection around the equator
|
|
20
|
-
|
|
21
|
-
if (size_y>size_x):
|
|
22
|
-
length = size_y * 1e3
|
|
23
|
-
nl = ny
|
|
24
|
-
width = size_x * 1e3
|
|
25
|
-
nw = nx
|
|
26
|
-
else:
|
|
27
|
-
length = size_x * 1e3
|
|
28
|
-
nl = nx
|
|
29
|
-
width = size_y * 1e3
|
|
30
|
-
nw = ny
|
|
31
|
-
|
|
32
|
-
dlon = length/r_earth
|
|
33
|
-
lon1d = dlon*np.arange(-0.5,nl+1.5,1)/nl - dlon/2
|
|
34
|
-
mul = 1.0
|
|
35
|
-
dlat = width/r_earth
|
|
36
|
-
for it in range(1,101):
|
|
37
|
-
y1 = np.log(np.tan(np.pi/4-dlat/4))
|
|
38
|
-
y2 = np.log(np.tan(np.pi/4+dlat/4))
|
|
39
|
-
y = (y2-y1)*np.arange(-0.5,nw+1.5,1)/nw + y1
|
|
40
|
-
lat1d = 2*np.arctan(np.exp(y)) - np.pi/2
|
|
41
|
-
lat1d = np.arctan(np.sinh(y))
|
|
42
|
-
dlat_cen = 0.5*(lat1d[int(np.round(nw/2)+1)]-lat1d[int(np.round(nw/2)-1)])
|
|
43
|
-
dlon_cen = dlon/nl
|
|
44
|
-
mul = dlat_cen/dlon_cen*length/width*nw/nl
|
|
45
|
-
dlat = dlat/mul
|
|
46
|
-
|
|
47
|
-
lon1de = dlon*np.arange(-1,nl+2,1)/nl - dlon/2
|
|
48
|
-
ye = (y2-y1)*np.arange(-1,nw+2)/nw + y1
|
|
49
|
-
lat1de = 2*np.arctan(np.exp(ye)) - np.pi/2
|
|
50
|
-
lat1de = np.arctan(np.sinh(ye))
|
|
51
|
-
lat1de= lat1de/mul
|
|
52
|
-
|
|
53
|
-
(lon1,lat1) = np.meshgrid(lon1d,lat1d)
|
|
54
|
-
(lone,late) = np.meshgrid(lon1de,lat1de)
|
|
55
|
-
lonu = 0.5*(lon1[:,:-1]+lon1[:,1:])
|
|
56
|
-
latu = 0.5*(lat1[:,:-1]+lat1[:,1:])
|
|
57
|
-
lonv = 0.5*(lon1[:-1,:]+lon1[1:,:])
|
|
58
|
-
latv = 0.5*(lat1[:-1,:]+lat1[1:,:])
|
|
59
|
-
|
|
60
|
-
if (size_y>size_x):
|
|
61
|
-
(lon1,lat1) = rot_sphere(lon1,lat1,90)
|
|
62
|
-
(lonu,latu) = rot_sphere(lonu,latu,90)
|
|
63
|
-
(lonv,latv) = rot_sphere(lonv,latv,90)
|
|
64
|
-
(lone,late) = rot_sphere(lone,late,90)
|
|
65
|
-
|
|
66
|
-
lon1 = np.transpose(np.flip(lon1,0))
|
|
67
|
-
lat1 = np.transpose(np.flip(lat1,0))
|
|
68
|
-
lone = np.transpose(np.flip(lone,0))
|
|
69
|
-
late = np.transpose(np.flip(late,1))
|
|
70
|
-
|
|
71
|
-
lonu_tmp= np.transpose(np.flip(lonv,0))
|
|
72
|
-
latu_tmp = np.transpose(np.flip(latv,0))
|
|
73
|
-
lonv = np.transpose(np.flip(lonu,0))
|
|
74
|
-
latv = np.transpose(np.flip(latu,0))
|
|
75
|
-
lonu = lonu_tmp
|
|
76
|
-
latu = latu_tmp
|
|
77
|
-
|
|
78
|
-
(lon2,lat2) = rot_sphere(lon1,lat1,rot)
|
|
79
|
-
(lonu,latu) = rot_sphere(lonu,latu,rot)
|
|
80
|
-
(lonv,latv) = rot_sphere(lonv,latv,rot)
|
|
81
|
-
(lone,late) = rot_sphere(lone,late,rot)
|
|
82
|
-
|
|
83
|
-
(lon3,lat3) = tra_sphere(lon2,lat2,tra_lat)
|
|
84
|
-
(lonu,latu) = tra_sphere(lonu,latu,tra_lat)
|
|
85
|
-
(lonv,latv) = tra_sphere(lonv,latv,tra_lat)
|
|
86
|
-
(lone,late) = tra_sphere(lone,late,tra_lat)
|
|
87
|
-
|
|
88
|
-
lon4 = lon3 + tra_lon*np.pi/180
|
|
89
|
-
lonu = lonu + tra_lon*np.pi/180
|
|
90
|
-
lonv = lonv + tra_lon*np.pi/180
|
|
91
|
-
lone = lone + tra_lon*np.pi/180
|
|
92
|
-
lon4[lon4<-np.pi] = lon4[lon4<-np.pi] + 2*np.pi
|
|
93
|
-
lonu[lonu<-np.pi] = lonu[lonu<-np.pi] + 2*np.pi
|
|
94
|
-
lonv[lonv<-np.pi] = lonv[lonv<-np.pi] + 2*np.pi
|
|
95
|
-
lone[lone<-np.pi] = lone[lone<-np.pi] + 2*np.pi
|
|
96
|
-
lat4 = lat3
|
|
97
|
-
|
|
98
|
-
# Compute pn and pm
|
|
99
|
-
# pm = 1/dx
|
|
100
|
-
pmu = gc_dist(lonu[:,:-1],latu[:,:-1],lonu[:,1:],latu[:,1:])
|
|
101
|
-
pm = 0*lon4
|
|
102
|
-
pm[:,1:-1] = pmu
|
|
103
|
-
pm[:,0] = pm[:,1]
|
|
104
|
-
pm[:,-1] = pm[:,-2]
|
|
105
|
-
pm = 1/pm
|
|
106
|
-
|
|
107
|
-
# pn = 1/dy
|
|
108
|
-
pnv = gc_dist(lonv[:-1,:],latv[:-1,:],lonv[1:,:],latv[1:,:])
|
|
109
|
-
pn = 0*lon4
|
|
110
|
-
pn[1:-1,:] = pnv
|
|
111
|
-
pn[0,:] = pn[1,:]
|
|
112
|
-
pn[-1,:] = pn[-2,:]
|
|
113
|
-
pn = 1/pn
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
## Compute angles of local grid positive x-axis relative to east
|
|
117
|
-
dellat = latu[:,1:]-latu[:,:-1]
|
|
118
|
-
dellon = lonu[:,1:]-lonu[:,:-1]
|
|
119
|
-
dellon[dellon > np.pi] = dellon[dellon > np.pi] - 2*np.pi
|
|
120
|
-
dellon[dellon < -np.pi] = dellon[dellon < -np.pi] + 2*np.pi
|
|
121
|
-
dellon = dellon * np.cos(0.5*(latu[:,1:]+latu[:,:-1]))
|
|
122
|
-
|
|
123
|
-
ang = copy.copy(lon4);
|
|
124
|
-
ang_s = np.arctan(dellat/(dellon+1e-16))
|
|
125
|
-
ang_s[(dellon<0) & (dellat<0)] = ang_s[(dellon<0) & (dellat<0)] - np.pi
|
|
126
|
-
ang_s[(dellon<0) & (dellat>=0)] = ang_s[(dellon<0) & (dellat>=0)] + np.pi
|
|
127
|
-
ang_s[ang_s > np.pi] = ang_s[ang_s > np.pi] - np.pi
|
|
128
|
-
ang_s[ang_s < -np.pi] = ang_s[ang_s < -np.pi] + np.pi
|
|
129
|
-
|
|
130
|
-
ang[:,1:-1] = ang_s
|
|
131
|
-
ang[:,0] = ang[:,1]
|
|
132
|
-
ang[:,-1] = ang[:,-2]
|
|
133
|
-
|
|
134
|
-
lon4[lon4<0] = lon4[lon4<0] + 2*np.pi
|
|
135
|
-
lone[lone<0] = lone[lone<0] + 2*np.pi
|
|
136
|
-
|
|
137
|
-
plot_grid(lon4,lat4)
|
|
138
|
-
save_grid(grdname,nx,ny,lon4,lat4,pm,pn,ang,size_x,size_y,rot,tra_lon,tra_lat,lone,late)
|
|
139
|
-
|
|
140
|
-
#return (lon4,lat4,pm,pn,ang,lone,late)
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
def save_grid(grdname,nx,ny,lon,lat,pm,pn,angle,xsize,ysize,rot,tra_lon,tra_lat,lone,late):
|
|
144
|
-
|
|
145
|
-
# This is part of Easy Grid
|
|
146
|
-
# (c) 2008, Jeroen Molemaker, UCLA
|
|
147
|
-
|
|
148
|
-
ROMS_title = 'ROMS grid by Easy Grid. Settings:' + \
|
|
149
|
-
' nx: ' + str(nx) + ' ny: ' + str(ny) + \
|
|
150
|
-
' xsize: ' + str(xsize/1e3) + ' ysize: ' + str(ysize/1e3) + \
|
|
151
|
-
' rotate: ' + str(rot) + ' Lon: ' + str(tra_lon) + ' Lat: ' + str(tra_lat)
|
|
152
|
-
|
|
153
|
-
nxp= nx+2
|
|
154
|
-
nyp= ny+2
|
|
155
|
-
|
|
156
|
-
# Create the grid file
|
|
157
|
-
create_grid(nxp,nyp,grdname,ROMS_title)
|
|
158
|
-
|
|
159
|
-
f0=4*np.pi*np.sin(lat)/(24*3600)
|
|
160
|
-
|
|
161
|
-
# Make bathymetry
|
|
162
|
-
hraw = make_topo(lon,lat)
|
|
163
|
-
|
|
164
|
-
# Compute the mask
|
|
165
|
-
mask = 0*hraw + 1
|
|
166
|
-
mask[hraw > 0] = 0
|
|
167
|
-
|
|
168
|
-
# Fill the grid file
|
|
169
|
-
f = netCDF4.Dataset(grdname, 'r+', format='NETCDF4')
|
|
170
|
-
f['pm'][:,:] = pm
|
|
171
|
-
f['pn'][:,:] = pn
|
|
172
|
-
f['angle'][:,:] = angle
|
|
173
|
-
f['hraw'][:,:] = hraw
|
|
174
|
-
f['f'][:,:] = f0
|
|
175
|
-
f['mask_rho'][:,:] = mask
|
|
176
|
-
f['lon_rho'][:,:] = lon*180/np.pi
|
|
177
|
-
f['lat_rho'][:,:] = lat*180/np.pi
|
|
178
|
-
f['spherical'][:] = 'T'
|
|
179
|
-
f['tra_lon'][:] = tra_lon
|
|
180
|
-
f['tra_lat'][:] = tra_lat
|
|
181
|
-
f['rotate'][:] = rot
|
|
182
|
-
|
|
183
|
-
f.close()
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
def rot_sphere(lon1, lat1, rot):
|
|
187
|
-
|
|
188
|
-
(n,m) = np.shape(lon1)
|
|
189
|
-
rot = rot*np.pi/180
|
|
190
|
-
|
|
191
|
-
# translate into x,y,z
|
|
192
|
-
# conventions: (lon,lat) = (0,0) corresponds to (x,y,z) = ( 0,-r, 0)
|
|
193
|
-
# (lon,lat) = (0,90) corresponds to (x,y,z) = ( 0, 0, r)
|
|
194
|
-
x1 = np.sin(lon1) * np.cos(lat1)
|
|
195
|
-
y1 = np.cos(lon1) * np.cos(lat1)
|
|
196
|
-
z1 = np.sin(lat1)
|
|
197
|
-
|
|
198
|
-
# We will rotate these points around the small circle defined by
|
|
199
|
-
# the intersection of the sphere and the plane that
|
|
200
|
-
# is orthogonal to the line through (lon,lat) (0,0) and (180,0)
|
|
201
|
-
|
|
202
|
-
# The rotation is in that plane around its intersection with
|
|
203
|
-
# aforementioned line.
|
|
204
|
-
|
|
205
|
-
# Since the plane is orthogonal to the y-axis (in my definition at least),
|
|
206
|
-
# Rotations in the plane of the small circle maintain constant y and are around
|
|
207
|
-
# (x,y,z) = (0,y1,0)
|
|
208
|
-
|
|
209
|
-
rp1 = np.sqrt(x1**2 + z1**2)
|
|
210
|
-
|
|
211
|
-
ap1 = np.pi/2*np.ones((n,m))
|
|
212
|
-
ap1[np.abs(x1)>1e-7] = np.arctan(np.abs(z1[np.abs(x1)>1e-7] / x1[np.abs(x1)>1e-7]))
|
|
213
|
-
ap1[x1<0] = np.pi - ap1[x1<0]
|
|
214
|
-
ap1[z1<0] = -ap1[z1<0]
|
|
215
|
-
|
|
216
|
-
ap2 = ap1 + rot
|
|
217
|
-
x2 = rp1 * np.cos(ap2)
|
|
218
|
-
y2 = y1
|
|
219
|
-
z2 = rp1 * np.sin(ap2)
|
|
220
|
-
|
|
221
|
-
lon2 = np.pi/2*np.ones((n,m))
|
|
222
|
-
lon2[abs(y2)>1e-7] = np.arctan(np.abs(x2[np.abs(y2)>1e-7] / y2[np.abs(y2)>1e-7]))
|
|
223
|
-
lon2[y2<0] = np.pi - lon2[y2<0]
|
|
224
|
-
lon2[x2<0] = -lon2[x2<0]
|
|
225
|
-
|
|
226
|
-
pr2 = np.sqrt(x2**2 + y2**2)
|
|
227
|
-
lat2 = np.pi/2 * np.ones((n,m))
|
|
228
|
-
lat2[np.abs(pr2)>1e-7] = np.arctan(np.abs(z2[np.abs(pr2)>1e-7] / pr2[np.abs(pr2)>1e-7]))
|
|
229
|
-
lat2[z2<0] = -lat2[z2<0]
|
|
230
|
-
|
|
231
|
-
return (lon2,lat2)
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
def tra_sphere(lon1,lat1,tra):
|
|
235
|
-
|
|
236
|
-
# Rotate sphere around its y-axis
|
|
237
|
-
# Part of easy grid
|
|
238
|
-
# (c) 2008, Jeroen Molemaker, UCLA
|
|
239
|
-
|
|
240
|
-
(n,m) = np.shape(lon1)
|
|
241
|
-
tra = tra*np.pi/180 # translation in latitude direction
|
|
242
|
-
|
|
243
|
-
# translate into x,y,z
|
|
244
|
-
# conventions: (lon,lat) = (0,0) corresponds to (x,y,z) = ( 0,-r, 0)
|
|
245
|
-
# (lon,lat) = (0,90) corresponds to (x,y,z) = ( 0, 0, r)
|
|
246
|
-
x1 = np.sin(lon1) * np.cos(lat1)
|
|
247
|
-
y1 = np.cos(lon1) * np.cos(lat1)
|
|
248
|
-
z1 = np.sin(lat1)
|
|
249
|
-
|
|
250
|
-
# We will rotate these points around the small circle defined by
|
|
251
|
-
# the intersection of the sphere and the plane that
|
|
252
|
-
# is orthogonal to the line through (lon,lat) (90,0) and (-90,0)
|
|
253
|
-
|
|
254
|
-
# The rotation is in that plane around its intersection with
|
|
255
|
-
# aforementioned line.
|
|
256
|
-
|
|
257
|
-
# Since the plane is orthogonal to the x-axis (in my definition at least),
|
|
258
|
-
# Rotations in the plane of the small circle maintain constant x and are around
|
|
259
|
-
# (x,y,z) = (x1,0,0)
|
|
260
|
-
|
|
261
|
-
rp1 = np.sqrt(y1**2 + z1**2)
|
|
262
|
-
|
|
263
|
-
ap1 = np.pi/2 * np.ones((n,m))
|
|
264
|
-
ap1[np.abs(y1)>1e-7] = np.arctan(np.abs(z1[np.abs(y1)>1e-7] / y1[np.abs(y1)>1e-7]))
|
|
265
|
-
ap1[y1<0] = np.pi - ap1[y1<0]
|
|
266
|
-
ap1[z1<0] = -ap1[z1<0]
|
|
267
|
-
|
|
268
|
-
ap2 = ap1 + tra
|
|
269
|
-
x2 = x1
|
|
270
|
-
y2 = rp1 * np.cos(ap2)
|
|
271
|
-
z2 = rp1 * np.sin(ap2)
|
|
272
|
-
|
|
273
|
-
## transformation from (x,y,z) to (lat,lon)
|
|
274
|
-
lon2 = np.pi/2* np.ones((n,m))
|
|
275
|
-
lon2[np.abs(y2)>1e-7] = np.arctan(np.abs(x2[np.abs(y2)>1e-7] / y2[np.abs(y2)>1e-7]))
|
|
276
|
-
lon2[y2<0] = np.pi - lon2[y2<0]
|
|
277
|
-
lon2[x2<0] = -lon2[x2<0]
|
|
278
|
-
|
|
279
|
-
pr2 = np.sqrt(x2**2 + y2**2)
|
|
280
|
-
lat2 = np.pi / (2*np.ones((n,m)))
|
|
281
|
-
lat2[np.abs(pr2)>1e-7] = np.arctan(np.abs(z2[np.abs(pr2)>1e-7] / pr2[np.abs(pr2)>1e-7]))
|
|
282
|
-
lat2[z2<0] = -lat2[z2<0]
|
|
283
|
-
|
|
284
|
-
return (lon2,lat2)
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
def gc_dist(lon1,lat1,lon2,lat2):
|
|
288
|
-
|
|
289
|
-
# Distance between 2 points along a great circle
|
|
290
|
-
# lat and lon in radians!!
|
|
291
|
-
# 2008, Jeroen Molaker, UCLA
|
|
292
|
-
|
|
293
|
-
dlat = lat2-lat1
|
|
294
|
-
dlon = lon2-lon1
|
|
295
|
-
|
|
296
|
-
dang = 2*np.arcsin( np.sqrt( np.sin(dlat/2)**2 + np.cos(lat2) * np.cos(lat1) * np.sin(dlon/2)**2 ) ) # haversine function
|
|
297
|
-
|
|
298
|
-
r_earth = 6371315.0
|
|
299
|
-
|
|
300
|
-
dis = r_earth*dang
|
|
301
|
-
|
|
302
|
-
return dis
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
def create_grid(nx, ny, grdname, title):
|
|
306
|
-
|
|
307
|
-
f = netCDF4.Dataset(grdname, 'w', format='NETCDF4')
|
|
308
|
-
|
|
309
|
-
one = f.createDimension('one', 1)
|
|
310
|
-
xi_rho = f.createDimension('xi_rho', nx)
|
|
311
|
-
eta_rho = f.createDimension('eta_rho', ny)
|
|
312
|
-
|
|
313
|
-
spherical = f.createVariable('spherical','c', ('one'));
|
|
314
|
-
setattr(spherical, 'long_name', "Grid type logical switch")
|
|
315
|
-
setattr(spherical, 'option_T', "spherical")
|
|
316
|
-
|
|
317
|
-
angle = f.createVariable('angle','f8', ('eta_rho', 'xi_rho'));
|
|
318
|
-
setattr(angle, 'long_name', "Angle between xi axis and east")
|
|
319
|
-
setattr(angle, 'units', "radians")
|
|
320
|
-
|
|
321
|
-
h = f.createVariable('h','f8', ('eta_rho', 'xi_rho'));
|
|
322
|
-
setattr(h, 'long_name', "Final bathymetry at rho-points")
|
|
323
|
-
setattr(h, 'units', "meter")
|
|
324
|
-
|
|
325
|
-
hraw = f.createVariable('hraw','f8', ('eta_rho', 'xi_rho'));
|
|
326
|
-
setattr(hraw, 'long_name', "Working bathymetry at rho-points")
|
|
327
|
-
setattr(hraw, 'units', "meter")
|
|
328
|
-
|
|
329
|
-
f0 = f.createVariable('f','f8', ('eta_rho', 'xi_rho'));
|
|
330
|
-
setattr(f0, 'long_name', "Coriolis parameter at rho-points")
|
|
331
|
-
setattr(f0, 'units', "second-1")
|
|
332
|
-
|
|
333
|
-
pm = f.createVariable('pm','f8', ('eta_rho', 'xi_rho'));
|
|
334
|
-
setattr(pm, 'long_name', "Curvilinear coordinate metric in xi-direction")
|
|
335
|
-
setattr(pm, 'units', "meter-1")
|
|
336
|
-
|
|
337
|
-
pn = f.createVariable('pn','f8', ('eta_rho', 'xi_rho'));
|
|
338
|
-
setattr(pn, 'long_name', "Curvilinear coordinate metric in eta-direction")
|
|
339
|
-
setattr(pn, 'units', "meter-1")
|
|
340
|
-
|
|
341
|
-
lon_rho = f.createVariable('lon_rho','f8', ('eta_rho', 'xi_rho'));
|
|
342
|
-
setattr(lon_rho, 'long_name', "longitude of rho-points")
|
|
343
|
-
setattr(lon_rho, 'units', "degrees East")
|
|
344
|
-
|
|
345
|
-
lat_rho = f.createVariable('lat_rho','f8', ('eta_rho', 'xi_rho'));
|
|
346
|
-
setattr(lat_rho, 'long_name', "latitude of rho-points")
|
|
347
|
-
setattr(lat_rho, 'units', "degrees North")
|
|
348
|
-
|
|
349
|
-
mask_rho = f.createVariable('mask_rho','f8', ('eta_rho', 'xi_rho'));
|
|
350
|
-
setattr(mask_rho, 'long_name', "Mask at rho-points")
|
|
351
|
-
setattr(mask_rho, 'units', "land/water (0/1)")
|
|
352
|
-
|
|
353
|
-
tra_lon = f.createVariable('tra_lon','f8', ('one'));
|
|
354
|
-
setattr(tra_lon, 'long_name', "Easy grid: Longitudinal translation of base grid")
|
|
355
|
-
setattr(tra_lon, 'units', "degrees East")
|
|
356
|
-
|
|
357
|
-
tra_lat = f.createVariable('tra_lat','f8', ('one'));
|
|
358
|
-
setattr(tra_lat, 'long_name', "Easy grid: Latitudinal translation of base grid")
|
|
359
|
-
setattr(tra_lat, 'units', "degrees North")
|
|
360
|
-
|
|
361
|
-
rotate = f.createVariable('rotate','f8', ('one'));
|
|
362
|
-
setattr(rotate, 'long_name', "Easy grid: Rotation of base grid")
|
|
363
|
-
setattr(rotate, 'units', "degrees")
|
|
364
|
-
|
|
365
|
-
xy_flip = f.createVariable('xy_flip','f8', ('one'));
|
|
366
|
-
setattr(xy_flip, 'long_name', "Easy grid: XY flip of base grid")
|
|
367
|
-
setattr(xy_flip, 'units', "True/False (0/1)")
|
|
368
|
-
|
|
369
|
-
f.Title = title
|
|
370
|
-
today = date.today()
|
|
371
|
-
f.Date = today.strftime("%m/%d/%y")
|
|
372
|
-
f.Type = "ROMS grid produced by Easy Grid"
|
|
373
|
-
|
|
374
|
-
f.close()
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
def make_topo(lon, lat):
|
|
378
|
-
|
|
379
|
-
toponame = 'etopo5.nc'
|
|
380
|
-
g = netCDF4.Dataset(toponame, 'r')
|
|
381
|
-
|
|
382
|
-
topo_lon = g['topo_lon'][:]
|
|
383
|
-
topo_lat = g['topo_lat'][:]
|
|
384
|
-
d = np.transpose(g['topo'][:,:].astype('float64'))
|
|
385
|
-
topo_lon[topo_lon<0] = topo_lon[topo_lon<0] + 360
|
|
386
|
-
topo_lonm = topo_lon-360
|
|
387
|
-
|
|
388
|
-
topo_loncat = np.concatenate((topo_lonm, topo_lon), axis=0)
|
|
389
|
-
d_loncat = np.concatenate((d, d), axis=0)
|
|
390
|
-
|
|
391
|
-
interp = RegularGridInterpolator((topo_loncat, topo_lat), d_loncat)
|
|
392
|
-
|
|
393
|
-
di = interp((lon*180/np.pi,lat*180/np.pi))
|
|
394
|
-
|
|
395
|
-
return di
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
def plot_grid(lon, lat):
|
|
399
|
-
|
|
400
|
-
# Define projections
|
|
401
|
-
geodetic = ccrs.Geodetic()
|
|
402
|
-
trans = ccrs.NearsidePerspective(central_longitude=np.mean(lon*180/np.pi), central_latitude=np.mean(lat*180/np.pi))
|
|
403
|
-
|
|
404
|
-
lon_deg = lon*180/np.pi - 360
|
|
405
|
-
lat_deg = lat*180/np.pi
|
|
406
|
-
|
|
407
|
-
(lo1,la1) = (lon_deg[0,0], lat_deg[0,0])
|
|
408
|
-
(lo2,la2) = (lon_deg[0,-1], lat_deg[0,-1])
|
|
409
|
-
(lo3,la3) = (lon_deg[-1,-1], lat_deg[-1,-1])
|
|
410
|
-
(lo4,la4) = (lon_deg[-1,0], lat_deg[-1,0])
|
|
411
|
-
|
|
412
|
-
(min_lo, max_lo) = (np.min(lon_deg), np.max(lon_deg))
|
|
413
|
-
(min_la, max_la) = (np.min(lat_deg), np.max(lat_deg))
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
lo1t, la1t = trans.transform_point(lo1, la1, geodetic)
|
|
417
|
-
lo2t, la2t = trans.transform_point(lo2, la2, geodetic)
|
|
418
|
-
lo3t, la3t = trans.transform_point(lo3, la3, geodetic)
|
|
419
|
-
lo4t, la4t = trans.transform_point(lo4, la4, geodetic)
|
|
420
|
-
|
|
421
|
-
min_lot, min_lat = trans.transform_point(min_lo, min_la, geodetic)
|
|
422
|
-
max_lot, max_lat = trans.transform_point(max_lo, max_la, geodetic)
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
fig = plt.figure(figsize=(10, 10))
|
|
427
|
-
ax = plt.axes(projection=trans)
|
|
428
|
-
|
|
429
|
-
ax.plot(
|
|
430
|
-
[lo1t, lo2t, lo3t, lo4t, lo1t],
|
|
431
|
-
[la1t, la2t, la3t, la4t, la1t],
|
|
432
|
-
"ro-"
|
|
433
|
-
)
|
|
434
|
-
|
|
435
|
-
ax.coastlines(resolution='50m', linewidth=.5, color='black') # add map
|
|
436
|
-
ax.gridlines()
|
|
437
|
-
|
|
438
|
-
plt.show()
|
|
@@ -1,134 +0,0 @@
|
|
|
1
|
-
Metadata-Version: 2.1
|
|
2
|
-
Name: roms-tools
|
|
3
|
-
Version: 0.0.2
|
|
4
|
-
Summary: Tools for running and analysing UCLA-ROMS simulations
|
|
5
|
-
Author-email: Thomas Nicholas <tom@cworthy.org>
|
|
6
|
-
License: Apache-2
|
|
7
|
-
Project-URL: Home, https://github.com/CWorthy-ocean/roms-tools
|
|
8
|
-
Project-URL: Documentation, https://github.com/CWorthy-ocean/roms-tools#readme
|
|
9
|
-
Classifier: Development Status :: 3 - Alpha
|
|
10
|
-
Classifier: Intended Audience :: Science/Research
|
|
11
|
-
Classifier: Topic :: Scientific/Engineering
|
|
12
|
-
Classifier: License :: OSI Approved :: Apache Software License
|
|
13
|
-
Classifier: Operating System :: OS Independent
|
|
14
|
-
Classifier: Programming Language :: Python
|
|
15
|
-
Classifier: Programming Language :: Python :: 3.9
|
|
16
|
-
Classifier: Programming Language :: Python :: 3.10
|
|
17
|
-
Classifier: Programming Language :: Python :: 3.11
|
|
18
|
-
Classifier: Programming Language :: Python :: 3.12
|
|
19
|
-
Requires-Python: >=3.9
|
|
20
|
-
Description-Content-Type: text/markdown
|
|
21
|
-
License-File: LICENSE
|
|
22
|
-
Requires-Dist: xarray >=2022.6.0
|
|
23
|
-
Requires-Dist: numpy
|
|
24
|
-
Requires-Dist: netcdf4
|
|
25
|
-
Requires-Dist: matplotlib
|
|
26
|
-
Requires-Dist: cartopy
|
|
27
|
-
Requires-Dist: packaging
|
|
28
|
-
|
|
29
|
-
# ROMS-tools
|
|
30
|
-
|
|
31
|
-
## Overview
|
|
32
|
-
|
|
33
|
-
A suite of python tools for setting up a [ROMS](https://github.com/CESR-lab/ucla-roms) simulation.
|
|
34
|
-
|
|
35
|
-
_Note these tools are for the "UCLA" version of ROMS._
|
|
36
|
-
|
|
37
|
-
## Installation instructions
|
|
38
|
-
|
|
39
|
-
For now this package must be installed by clone the source code and installing locally.
|
|
40
|
-
|
|
41
|
-
```bash
|
|
42
|
-
git clone <repo-URL>
|
|
43
|
-
cd roms-tools
|
|
44
|
-
pip install .
|
|
45
|
-
```
|
|
46
|
-
|
|
47
|
-
Check the installation has worked by running the tests (you will need to also install pytest to run these)
|
|
48
|
-
```bash
|
|
49
|
-
pytest
|
|
50
|
-
```
|
|
51
|
-
|
|
52
|
-
Dependencies required are xarray and netcdf4, plus matplotlib and cartopy for visualising grids.
|
|
53
|
-
|
|
54
|
-
ROMS-tools should run on any platform that can install the above dependencies.
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
## Usage instructions
|
|
58
|
-
|
|
59
|
-
To set up all the input files for a new ROMS simulation from scratch, follow these steps in order.
|
|
60
|
-
|
|
61
|
-
### Step 1: Make Grid
|
|
62
|
-
|
|
63
|
-
The first step is choosing the domain size, location, and resolution. Do this by creating an instance of the `Grid` class:
|
|
64
|
-
|
|
65
|
-
```python
|
|
66
|
-
from roms_tools import Grid
|
|
67
|
-
|
|
68
|
-
grid = Grid(
|
|
69
|
-
nx=100, # number of points in the x-direction (not including 2 boundary cells on either end)
|
|
70
|
-
ny=100, # number of points in the y-direction (not including 2 boundary cells on either end)
|
|
71
|
-
size_x=1800, # size of the domain in the x-direction (in km)
|
|
72
|
-
size_y=2400, # size of the domain in the y-direction (in km)
|
|
73
|
-
center_lon=-21, # longitude of the center of the domain
|
|
74
|
-
center_lat=61, # latitude of the center of the domain
|
|
75
|
-
rot=20, # rotation of the grid's x-direction from lines of constant longitude, with positive values being a counter-clockwise rotation
|
|
76
|
-
)
|
|
77
|
-
```
|
|
78
|
-
|
|
79
|
-
To visualize the grid we have just created, use the `.plot` method:
|
|
80
|
-
|
|
81
|
-
```python
|
|
82
|
-
grid.plot()
|
|
83
|
-
```
|
|
84
|
-
|
|
85
|
-
To see the values of the grid variables you can examine the `xarray.Dataset` object returned by the `.ds` property
|
|
86
|
-
|
|
87
|
-
```python
|
|
88
|
-
grid.ds
|
|
89
|
-
```
|
|
90
|
-
```
|
|
91
|
-
<xarray.Dataset>
|
|
92
|
-
Dimensions: (eta_rho: 3, xi_rho: 3, one: 1)
|
|
93
|
-
Dimensions without coordinates: eta_rho, xi_rho, one
|
|
94
|
-
Data variables:
|
|
95
|
-
angle (eta_rho, xi_rho) float64 0.0 0.0 0.0 -1.46e-16 ... 0.0 0.0 0.0
|
|
96
|
-
f0 (eta_rho, xi_rho) float64 4.565e-06 4.565e-06 ... -4.565e-06
|
|
97
|
-
pn (eta_rho, xi_rho) float64 5e-06 5e-06 5e-06 ... 5e-06 5e-06 5e-06
|
|
98
|
-
lon_rho (eta_rho, xi_rho) float64 339.1 340.0 340.9 ... 339.1 340.0 340.9
|
|
99
|
-
lat_rho (eta_rho, xi_rho) float64 1.799 1.799 1.799 ... -1.799 -1.799
|
|
100
|
-
spherical (one) <U1 'T'
|
|
101
|
-
tra_lon (one) int64 -20
|
|
102
|
-
tra_lat (one) int64 0
|
|
103
|
-
rotate (one) int64 0
|
|
104
|
-
Attributes:
|
|
105
|
-
Title: ROMS grid. Settings: nx: 1 ny: 1 xsize: 0.1 ysize: 0.1 rotate:...
|
|
106
|
-
Date: 2023-11-20
|
|
107
|
-
Type: ROMS grid produced by roms-tools
|
|
108
|
-
```
|
|
109
|
-
|
|
110
|
-
Once we are happy with our grid, we can save it as a netCDF file via the `.save` method:
|
|
111
|
-
|
|
112
|
-
```python
|
|
113
|
-
grid.save('grids/my_new_roms_grid.nc')
|
|
114
|
-
```
|
|
115
|
-
|
|
116
|
-
The basic grid domain is now ready for use by ROMS.
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
### Steps 2-7:
|
|
120
|
-
|
|
121
|
-
Coming soon!
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
## Feedback and contributions
|
|
125
|
-
|
|
126
|
-
**If you find a bug, have a feature suggestion, or any other kind of feedback, please start a Discussion.**
|
|
127
|
-
|
|
128
|
-
We also accept contributions in the form of Pull Requests.
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
## See also
|
|
132
|
-
|
|
133
|
-
- [ROMS source code](https://github.com/CESR-lab/ucla-roms)
|
|
134
|
-
- [C-Star](https://github.com/CWorthy-ocean/C-Star)
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
roms_tools/__init__.py,sha256=jIriHk0yQWT8R-Q7NDW5GbG-QrfvtInZz3d8D9IraD8,268
|
|
2
|
-
roms_tools/_version.py,sha256=KnMfto4I4iRxgFOw_PXDZGfLy6ncfXYdIM11IbpNjag,72
|
|
3
|
-
roms_tools/setup/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
4
|
-
roms_tools/setup/grid.py,sha256=i9yZg-7rJZkL8YQn1fni7LfzQPTUbiI_D6aWzqLoUCs,19643
|
|
5
|
-
roms_tools/setup/old_grid_script.py,sha256=5WmR1-LiFPvOEtWnm3D2r1FbQc64Cge9RRJ1QA9qys0,13745
|
|
6
|
-
roms_tools/tests/test_setup.py,sha256=T3KjjFZjTLSXkKuXGQysqXN4SwCem0Q1ZGAwv3J0ykQ,1670
|
|
7
|
-
roms_tools-0.0.2.dist-info/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
|
|
8
|
-
roms_tools-0.0.2.dist-info/METADATA,sha256=xRDdvCpdrBdrqCMudgAFFRZpTghW7m29c2w3Y-KRq7M,4282
|
|
9
|
-
roms_tools-0.0.2.dist-info/WHEEL,sha256=oiQVh_5PnQM0E3gPdiz09WCNmwiHDMaGer_elqB3coM,92
|
|
10
|
-
roms_tools-0.0.2.dist-info/top_level.txt,sha256=-Fb20pZd7AOdU5ADuUzk6cnaiJiuuFJcUAJN-CookbU,11
|
|
11
|
-
roms_tools-0.0.2.dist-info/RECORD,,
|
|
File without changes
|