Skip to content

Commit

Permalink
Merge pull request #22 from tsutterley/nodal
Browse files Browse the repository at this point in the history
update nodal corrections for FES models
  • Loading branch information
tsutterley authored Sep 1, 2020
2 parents 41f8caf + 0c10cf5 commit cb1edbb
Show file tree
Hide file tree
Showing 15 changed files with 485 additions and 114 deletions.
2 changes: 2 additions & 0 deletions doc/source/user_guide/bilinear_interp.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,9 @@ data = bilinear_interp(ilon,ilat,idata,lon,lat)
5. `lat`: output latitude

#### Options
- `fill_value`: invalid value
- `dtype`: output data type
- `extrapolate`: extrapolate points

#### Outputs
- `data`: interpolated data
11 changes: 6 additions & 5 deletions notebooks/Plot Antarctic Tidal Currents.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -261,9 +261,10 @@
"nx = np.int((xlimits[1]-xlimits[0])/spacing[0])+1\n",
"ny = np.int((ylimits[0]-ylimits[1])/spacing[1])+1\n",
"#-- convert image coordinates from polar stereographic to latitude/longitude\n",
"proj1 = pyproj.Proj(\"+init=EPSG:{0:d}\".format(4326))\n",
"proj2 = pyproj.Proj(\"+init=EPSG:{0:d}\".format(3031))\n",
"lon,lat = pyproj.transform(proj2, proj1, xgrid.flatten(), ygrid.flatten())"
"crs1 = pyproj.CRS.from_string(\"epsg:{0:d}\".format(3031))\n",
"crs2 = pyproj.CRS.from_string(\"epsg:{0:d}\".format(4326))\n",
"transformer = pyproj.Transformer.from_crs(crs1, crs2, always_xy=True)\n",
"lon,lat = transformer.transform(xgrid.flatten(), ygrid.flatten())"
]
},
{
Expand Down Expand Up @@ -363,8 +364,8 @@
" ax.set_xlim(xlimits)\n",
" ax.set_ylim(ylimits)\n",
" # stronger linewidth on frame\n",
" ax.outline_patch.set_linewidth(2.0)\n",
" ax.outline_patch.set_capstyle('projecting')\n",
" ax.spines['geo'].set_linewidth(2.0)\n",
" ax.spines['geo'].set_capstyle('projecting')\n",
"\n",
"#-- Add colorbar with a colorbar axis\n",
"#-- Add an axes at position rect [left, bottom, width, height]\n",
Expand Down
11 changes: 6 additions & 5 deletions notebooks/Plot Antarctic Tide Range.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -251,9 +251,10 @@
"nx = np.int((xlimits[1]-xlimits[0])/spacing[0])+1\n",
"ny = np.int((ylimits[0]-ylimits[1])/spacing[1])+1\n",
"#-- convert image coordinates from polar stereographic to latitude/longitude\n",
"proj1 = pyproj.Proj(\"+init=EPSG:{0:d}\".format(4326))\n",
"proj2 = pyproj.Proj(\"+init=EPSG:{0:d}\".format(3031))\n",
"lon,lat = pyproj.transform(proj2, proj1, xgrid.flatten(), ygrid.flatten())"
"crs1 = pyproj.CRS.from_string(\"epsg:{0:d}\".format(3031))\n",
"crs2 = pyproj.CRS.from_string(\"epsg:{0:d}\".format(4326))\n",
"transformer = pyproj.Transformer.from_crs(crs1, crs2, always_xy=True)\n",
"lon,lat = transformer.transform(xgrid.flatten(), ygrid.flatten())"
]
},
{
Expand Down Expand Up @@ -409,8 +410,8 @@
"ax.set_ylim(ylimits)\n",
"\n",
"#-- stronger linewidth on frame\n",
"ax.outline_patch.set_linewidth(2.0)\n",
"ax.outline_patch.set_capstyle('projecting')\n",
"ax.spines['geo'].set_linewidth(2.0)\n",
"ax.spines['geo'].set_capstyle('projecting')\n",
"#-- adjust subplot within figure\n",
"fig.subplots_adjust(left=0.02,right=0.98,bottom=0.05,top=0.98)\n",
"#-- show the plot\n",
Expand Down
11 changes: 6 additions & 5 deletions notebooks/Plot Ross Ice Shelf Map.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -268,9 +268,10 @@
"nx = np.int((xlimits[1]-xlimits[0])/spacing[0])+1\n",
"ny = np.int((ylimits[0]-ylimits[1])/spacing[1])+1\n",
"#-- convert image coordinates from polar stereographic to latitude/longitude\n",
"proj1 = pyproj.Proj(\"+init=EPSG:{0:d}\".format(4326))\n",
"proj2 = pyproj.Proj(\"+init=EPSG:{0:d}\".format(3031))\n",
"lon,lat = pyproj.transform(proj2, proj1, xgrid.flatten(), ygrid.flatten())"
"crs1 = pyproj.CRS.from_string(\"epsg:{0:d}\".format(3031))\n",
"crs2 = pyproj.CRS.from_string(\"epsg:{0:d}\".format(4326))\n",
"transformer = pyproj.Transformer.from_crs(crs1, crs2, always_xy=True)\n",
"lon,lat = transformer.transform(xgrid.flatten(), ygrid.flatten())"
]
},
{
Expand Down Expand Up @@ -382,8 +383,8 @@
"ax.set_ylim(ylimits)\n",
"\n",
"# stronger linewidth on frame\n",
"ax.outline_patch.set_linewidth(2.0)\n",
"ax.outline_patch.set_capstyle('projecting')\n",
"ax.spines['geo'].set_linewidth(2.0)\n",
"ax.spines['geo'].set_capstyle('projecting')\n",
"# adjust subplot within figure\n",
"fig.subplots_adjust(left=0.02,right=0.98,bottom=0.05,top=0.98)\n",
" \n",
Expand Down
77 changes: 40 additions & 37 deletions pyTMD/bilinear_interp.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,9 @@
lon: output longitude
OPTIONS:
fill_value: invalid value
dtype: output data type
extrapolate: extrapolate points
OUTPUT:
data: interpolated data
Expand All @@ -26,14 +28,16 @@
UPDATE HISTORY:
Updated 08/2020: check that output coordinates are within bounds
allow small extrapolations if individual grid cells are invalid
Updated 07/2020: split into separate function
Updated 06/2020: use argmin and argmax in bilinear interpolation
Updated 09/2017: Rewritten in Python
"""
import numpy as np

#-- PURPOSE: bilinear interpolation of input data to output data
def bilinear_interp(ilon,ilat,idata,lon,lat,dtype=np.float):
def bilinear_interp(ilon,ilat,idata,lon,lat,fill_value=np.nan,
dtype=np.float,extrapolate=False):
"""
Bilinear interpolation of input data to output coordinates
Expand All @@ -47,61 +51,60 @@ def bilinear_interp(ilon,ilat,idata,lon,lat,dtype=np.float):
Keyword arguments
-----------------
fill_value: invalid value
dtype: output data type
extrapolate: extrapolate points
Returns
-------
data: interpolated data
"""
#-- degrees to radians
dtr = np.pi/180.0
#-- grid step size of tide model
dlon = np.abs(ilon[1] - ilon[0])
dlat = np.abs(ilat[1] - ilat[0])
#-- find valid points (within bounds)
valid, = np.nonzero((lon >= ilon.min()) & (lon <= ilon.max()) &
(lat > ilat.min()) & (lat < ilat.max()))
#-- Convert input coordinates to radians
phi = ilon*dtr
th = (90.0 - ilat)*dtr
#-- Convert output data coordinates to radians
xphi = lon*dtr
xth = (90.0 - lat)*dtr
#-- interpolate gridded data values to data
npts = len(lon)
data = np.ma.zeros((npts),dtype=dtype)
#-- allocate to output interpolated data array
data = np.ma.zeros((npts),dtype=dtype,fill_value=fill_value)
data.mask = np.ones((npts),dtype=np.bool)
data.mask[valid] = False
#-- initially set all data to fill value
data.data[:] = data.fill_value
#-- for each valid point
for i in valid:
#-- calculating the indices for the original grid
dx = (ilon - np.floor(lon[i]/dlon)*dlon)**2
dy = (ilat - np.floor(lat[i]/dlat)*dlat)**2
iph = np.argmin(dx)
ith = np.argmin(dy)
ix, = np.nonzero((ilon[0:-1] <= lon[i]) & (ilon[1:] > lon[i]))
iy, = np.nonzero((ilat[0:-1] <= lat[i]) & (ilat[1:] > lat[i]))
#-- corner data values for adjacent grid cells
IM = np.ma.zeros((4),fill_value=fill_value,dtype=dtype)
IM.mask = np.ones((4),dtype=np.bool)
#-- corner weight values for adjacent grid cells
WM = np.zeros((4))
#-- build data and weight arrays
for j,XI,YI in zip([0,1,2,3],[ix,ix+1,ix,ix+1],[iy,iy,iy+1,iy+1]):
IM.data[j], = idata.data[YI,XI]
IM.mask[j], = idata.mask[YI,XI]
WM[j], = np.abs(lon[i]-ilon[XI])*np.abs(lat[i]-ilat[YI])
#-- if on corner value: use exact
if ((lat[i] == ilat[ith]) & (lon[i] == ilon[iph])):
data.data[i] = idata[ith,iph]
elif ((lat[i] == ilat[ith+1]) & (lon[i] == ilon[iph])):
data.data[i] = idata[ith+1,iph]
elif ((lat[i] == ilat[ith]) & (lon[i] == ilon[iph+1])):
data.data[i] = idata[ith,iph+1]
elif ((lat[i] == ilat[ith+1]) & (lon[i] == ilon[iph+1])):
data.data[i] = idata[ith+1,iph+1]
else:
#-- corner weight values for i,j
Wa = (xphi[i]-phi[iph])*(xth[i]-th[ith])
Wb = (phi[iph+1]-xphi[i])*(xth[i]-th[ith])
Wc = (xphi[i]-phi[iph])*(th[ith+1]-xth[i])
Wd = (phi[iph+1]-xphi[i])*(th[ith+1]-xth[i])
#-- divisor weight value
W = (phi[iph+1]-phi[iph])*(th[ith+1]-th[ith])
#-- corner data values for i,j
Ia = idata[ith,iph]#-- (0,0)
Ib = idata[ith,iph+1]#-- (1,0)
Ic = idata[ith+1,iph]#-- (0,1)
Id = idata[ith+1,iph+1]#-- (1,1)
if ((lat[i] == ilat[iy]) & (lon[i] == ilon[ix])):
data.data[i] = idata.data[iy,ix]
data.mask[i] = idata.mask[iy,ix]
elif ((lat[i] == ilat[iy+1]) & (lon[i] == ilon[ix])):
data.data[i] = idata.data[iy+1,ix]
data.mask[i] = idata.mask[iy+1,ix]
elif ((lat[i] == ilat[iy]) & (lon[i] == ilon[ix+1])):
data.data[i] = idata.data[iy,ix+1]
data.mask[i] = idata.mask[iy,ix+1]
elif ((lat[i] == ilat[iy+1]) & (lon[i] == ilon[ix+1])):
data.data[i] = idata.data[iy+1,ix+1]
data.mask[i] = idata.mask[iy+1,ix+1]
elif np.all(np.isfinite(IM) & (~IM.mask)) or extrapolate:
#-- find valid indices for data summation and weight matrix
ii, = np.nonzero(np.isfinite(IM) & (~IM.mask))
#-- calculate interpolated value for i
data.data[i] = (Ia*Wa + Ib*Wb + Ic*Wc + Id*Wd)/W
data.data[i] = np.sum(WM[ii]*IM[ii])/np.sum(WM[ii])
data.mask[i] = np.all(IM.mask[ii])
#-- return interpolated values
return data
2 changes: 1 addition & 1 deletion pyTMD/calc_astrol_longitudes.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ def polynomial_sum(coefficients, t):
Arguments
---------
coefficients: leading coefficient of polynomials of increasing order
t: delta time in units for a given astrological longitudes calculation
t: delta time in units for a given astronomical longitudes calculation
"""
#-- convert time to array if importing a single value
t = np.array([t]) if (np.ndim(t) == 0) else np.copy(t)
Expand Down
Loading

0 comments on commit cb1edbb

Please sign in to comment.