问题
Is there a readily available method for extrapolating the grid corner positions (blue dots) from grid center positions (red dots)?
The grid I am working with is not rectangular, so regular bi-linear interpolation doesn't seem like it would be the best way; though, this is just so that I my plot my data use pyplot.pcolormesh()
, so perhaps that doesn't matter so much.
Example grid data:
import numpy as np
lons = np.array([[ 109.93299681, 109.08091365, 108.18301276, 107.23602539],
[ 108.47911382, 107.60397996, 106.68325946, 105.71386119],
[ 107.06790187, 106.17259769, 105.23214707, 104.2436463 ],
[ 105.69908292, 104.78633156, 103.82905363, 102.82453812]])
lats = np.array([[ 83.6484245 , 83.81088466, 83.97177823, 84.13098916],
[ 83.55459198, 83.71460466, 83.87294803, 84.02950188],
[ 83.4569054 , 83.61444708, 83.77022192, 83.92410637],
[ 83.35554612, 83.51060313, 83.6638013 , 83.81501464]])
回答1:
I am not aware of any robust matplotlib technique for doing what you are asking, but I may have a different solution. I often have to fill/extrapolate to areas of a grid where I am missing information. To do this I use a Fortran program that I compile using F2PY (that ships with numpy), which creates it into a python module. Assuming you have the Intel Fortran compiler you compile it with the following command: f2py --verbose --fcompiler=intelem -c -m extrapolate fill.f90
. You can call the program from python with (see here for full example):
import extrapolate as ex
undef=2.0e+35
tx=0.9*undef
critx=0.01
cor=1.6
mxs=100
field = Zg
field=np.where(abs(field) > 50 ,undef,field)
field=ex.extrapolate.fill(int(1),int(grdROMS.xi_rho),
int(1),int(grdROMS.eta_rho),
float(tx), float(critx), float(cor), float(mxs),
np.asarray(field, order='Fortran'),
int(grdROMS.xi_rho),
int(grdROMS.eta_rho))
The program solves Laplace's equation with Neumann boundary conditions (dA/dn = 0) in RECTANGULAR coordinates by an iterative method to fill in reasonable values at gridpoints containing values like "undef". This works great for me and perhaps you may find it useful. The program is available on my github account here.
回答2:
This is the not-so-elegant approach that I took using pyproj
to first calculate the distance and azimuth between the points (with pyproj.Geod.inv
, then interpolating/extrapolating that angle by the necessary distance (with pyproj.Geod.fwd
) to the psi position.
code:
def calc_psi_coords(lons, lats):
''' Calcuate psi points from centered grid points'''
import numpy as np
import pyproj
# Create Geod object with WGS84 ellipsoid
g = pyproj.Geod(ellps='WGS84')
# Get grid field dimensions
ydim, xdim = lons.shape
# Create empty coord arrays
lons_psi = np.zeros((ydim+1, xdim+1))
lats_psi = np.zeros((ydim+1, xdim+1))
# Calculate internal points
#--------------------------
for j in range(ydim-1):
for i in range(xdim-1):
lon1 = lons[j,i] # top left point
lat1 = lats[j,i]
lon2 = lons[j+1,i+1] # bottom right point
lat2 = lats[j+1,i+1]
# Calc distance between points, find position at half of dist
fwd_az, bck_az, dist = g.inv(lon1,lat1,lon2,lat2)
lon_psi, lat_psi, bck_az = g.fwd(lon1,lat1,fwd_az,dist*0.5)
# Assign to psi interior positions
lons_psi[j+1,i+1] = lon_psi
lats_psi[j+1,i+1] = lat_psi
# Caclulate external points (not corners)
#----------------------------------------
for j in range(ydim):
# Left external points
#~~~~~~~~~~~~~~~~~~~~~
lon1 = lons_psi[j+1,2] # left inside point
lat1 = lats_psi[j+1,2]
lon2 = lons_psi[j+1,1] # left outside point
lat2 = lats_psi[j+1,1]
# Calc dist between points, find position at dist*2 from pos1
fwd_az, bck_az, dist = g.inv(lon1,lat1,lon2,lat2)
lon_psi, lat_psi, bck_az = g.fwd(lon1,lat1,fwd_az,dist*2.)
lons_psi[j+1,0] = lon_psi
lats_psi[j+1,0] = lat_psi
# Right External points
#~~~~~~~~~~~~~~~~~~~~~~
lon1 = lons_psi[j+1,-3] # right inside point
lat1 = lats_psi[j+1,-3]
lon2 = lons_psi[j+1,-2] # right outside point
lat2 = lats_psi[j+1,-2]
# Calc dist between points, find position at dist*2 from pos1
fwd_az, bck_az, dist = g.inv(lon1,lat1,lon2,lat2)
lon_psi, lat_psi, bck_az = g.fwd(lon1,lat1,fwd_az,dist*2.)
lons_psi[j+1,-1] = lon_psi
lats_psi[j+1,-1] = lat_psi
for i in range(xdim):
# Top external points
#~~~~~~~~~~~~~~~~~~~~
lon1 = lons_psi[2,i+1] # top inside point
lat1 = lats_psi[2,i+1]
lon2 = lons_psi[1,i+1] # top outside point
lat2 = lats_psi[1,i+1]
# Calc dist between points, find position at dist*2 from pos1
fwd_az, bck_az, dist = g.inv(lon1,lat1,lon2,lat2)
lon_psi, lat_psi, bck_az = g.fwd(lon1,lat1,fwd_az,dist*2.)
lons_psi[0,i+1] = lon_psi
lats_psi[0,i+1] = lat_psi
# Bottom external points
#~~~~~~~~~~~~~~~~~~~~~~~
lon1 = lons_psi[-3,i+1] # bottom inside point
lat1 = lats_psi[-3,i+1]
lon2 = lons_psi[-2,i+1] # bottom outside point
lat2 = lats_psi[-2,i+1]
# Calc dist between points, find position at dist*2 from pos1
fwd_az, bck_az, dist = g.inv(lon1,lat1,lon2,lat2)
lon_psi, lat_psi, bck_az = g.fwd(lon1,lat1,fwd_az,dist*2.)
lons_psi[-1,i+1] = lon_psi
lats_psi[-1,i+1] = lat_psi
# Calculate corners:
#-------------------
# top left corner
#~~~~~~~~~~~~~~~~
lon1 = lons_psi[2,2] # bottom right point
lat1 = lats_psi[2,2]
lon2 = lons_psi[1,1] # top left point
lat2 = lats_psi[1,1]
# Calc dist between points, find position at dist*2 from pos1
fwd_az, bck_az, dist = g.inv(lon1,lat1,lon2,lat2)
lon_psi, lat_psi, bck_az = g.fwd(lon1,lat1,fwd_az,dist*2.)
lons_psi[0,0] = lon_psi
lats_psi[0,0] = lat_psi
# top right corner
#~~~~~~~~~~~~~~~~~
lon1 = lons_psi[2,-3] # bottom left point
lat1 = lats_psi[2,-3]
lon2 = lons_psi[1,-2] # top right point
lat2 = lats_psi[1,-2]
# Calc dist between points, find position at dist*2 from pos1
fwd_az, bck_az, dist = g.inv(lon1,lat1,lon2,lat2)
lon_psi, lat_psi, bck_az = g.fwd(lon1,lat1,fwd_az,dist*2.)
lons_psi[0,-1] = lon_psi
lats_psi[0,-1] = lat_psi
# bottom left corner
#~~~~~~~~~~~~~~~~~~~
lon1 = lons_psi[-3,2] # top right point
lat1 = lats_psi[-3,2]
lon2 = lons_psi[-2,1] # bottom left point
lat2 = lats_psi[-2,1]
# Calc dist between points, find position at dist*2 from pos1
fwd_az, bck_az, dist = g.inv(lon1,lat1,lon2,lat2)
lon_psi, lat_psi, bck_az = g.fwd(lon1,lat1,fwd_az,dist*2.)
lons_psi[-1,0] = lon_psi
lats_psi[-1,0] = lat_psi
# bottom right corner
#~~~~~~~~~~~~~~~~~~~~
lon1 = lons_psi[-3,-3] # top left point
lat1 = lats_psi[-3,-3]
lon2 = lons_psi[-2,-2] # bottom right point
lat2 = lats_psi[-2,-2]
# Calc dist between points, find position at dist*2 from pos1
fwd_az, bck_az, dist = g.inv(lon1,lat1,lon2,lat2)
lon_psi, lat_psi, bck_az = g.fwd(lon1,lat1,fwd_az,dist*2.)
lons_psi[-1,-1] = lon_psi
lats_psi[-1,-1] = lat_psi
return lons_psi, lats_psi
Example image (around Denmark/southern Sweden):
来源:https://stackoverflow.com/questions/22666937/resample-grid-from-center-coordinates-to-external-i-e-corner-coordinates