Resample grid from center coordinates to external (i.e. corner) coordinates

末鹿安然 提交于 2019-12-07 11:55:27

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!