This recipe illustrates how to extract a low resolution grid from a high resolution grid using the Numeric package. It presents an inefficient but straightforward solution and then a more efficient solution that employs the functionality in Numeric.
| 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 | #!/usr/bin/env python
"""Replace a grid with one that is more coarse"""
import Numeric
def grid_coarse(in_grid, in_ny, in_nx, out_ny, out_nx, factor):
    """Replace a grid with one that is more coarse
        Inputs:
            in_ny -- number of input grid rows
            in_nx -- number of input grid columns
            out_ny -- number of output grid rows
            out_nx -- number of output grid columns
            factor -- input grid box length divided by output grid box length
            
    """
    out_grid = Numeric.zeros((out_ny, out_nx), in_grid.typecode())
    for j in xrange(0, out_ny):
        xjfine = float(j) * factor 
        jfine = int (float(j) * factor)
        dj = xjfine - float(jfine)
        jp1 = min(in_ny-1, jfine+1)
        jm1 = max(0, jfine-1)
        for i in xrange(0, out_nx):
            xifine = float(i) * factor
            ifine = int (float(i) * factor)
            di = xifine - float(ifine)
            ip1 = min(in_nx-1, ifine+1)
            xval = (1.-di) * (1.-dj) * in_grid[jfine, ifine] + (1.-di) * dj * in_grid[jp1, ifine] + di * (1.-dj) * in_grid[jfine, ip1] + di * dj * in_grid[jp1, ip1]
 
            out_grid[j, i] = xval
    return out_grid
    
class GridCoarse(object):
    """Replace a grid with one that is more coarse"""
    def __init__(self, in_ny, in_nx, out_ny, out_nx, factor):
        """Constructor
        
        Inputs:
            in_ny -- number of input grid rows
            in_nx -- number of input grid columns
            out_ny -- number of output grid rows
            out_nx -- number of output grid columns
            factor -- input grid box length divided by output grid box length
        """
        self.in_ny = in_ny
        self.in_nx = in_nx
        self.out_ny = out_ny
        self.out_nx = out_nx
        self.factor = factor
        self.jfine = Numeric.zeros(out_ny)
        self.dj = Numeric.zeros(out_ny, Numeric.Float64)
        self.jp1 = Numeric.zeros(out_ny)
        self.ifine = Numeric.zeros(out_nx)
        self.di = Numeric.zeros(out_nx, Numeric.Float64)
        self.ip1 = Numeric.zeros(out_nx)
        for j in xrange(0, out_ny):
            xjfine = float(j) * self.factor 
            self.jfine[j] = int(float(j) * self.factor)
            self.dj[j] = xjfine - float(self.jfine[j])
            self.jp1[j] = min(self.in_ny-1, self.jfine[j]+1)
        for i in xrange(0, out_nx):
            xifine = float(i) * self.factor
            self.ifine[i] = int(float(i) * self.factor)
            self.di[i] = xifine - float(self.ifine[i])
            self.ip1[i] = min (self.in_nx-1, self.ifine[i]+1)
        self.d1 = Numeric.outerproduct(1.0 - self.dj, 1.0 - self.di)
        self.d2 = Numeric.outerproduct(self.dj, 1.0 - self.di)
        self.d3 = Numeric.outerproduct(1.0 - self.dj, self.di)
        self.d4 = Numeric.outerproduct(self.dj, self.di)
    def convert(self, in_grid):
        g1 = Numeric.take(Numeric.take(in_grid, self.jfine), self.ifine, 1)
        g2 = Numeric.take(Numeric.take(in_grid, self.jp1), self.ifine, 1)
        g3 = Numeric.take(Numeric.take(in_grid, self.jfine), self.ip1, 1)
        g4 = Numeric.take(Numeric.take(in_grid, self.jp1), self.ip1, 1)
        out_grid = self.d1 * g1 + self.d2 * g2 + self.d3 * g3 + self.d4 * g4
        return out_grid.astype(in_grid.typecode())
def test1():
    in_ny = 500
    in_nx = 500
    out_ny = 250
    out_nx = 250
    factor = 2.0
    a = Numeric.arange(500*500)
    in_grid = a.resize((500, 500))
    gc = grid_coarse(in_grid, in_ny, in_nx, out_ny, out_nx, factor)
def test2():
    in_ny = 500
    in_nx = 500
    out_ny = 250
    out_nx = 250
    factor = 2.0
    a = Numeric.arange(500*500)
    in_grid = a.resize((500, 500))
    gc = GridCoarse(in_ny, in_nx, out_ny, out_nx, factor)
    out_grid = gc.convert(in_grid)
if __name__ == "__main__":
    import timeit
            
    t = timeit.Timer("test1()", "from __main__ import test1")
    print "test1(): ",
    print t.timeit(number=10)
    t = timeit.Timer("test2()", "from __main__ import test2")
    print "test2(): ",
    print t.timeit(number=10)
    
    
    
 | 
This recipe illustrates how functionality in the Numeric package can be applied in cases where one would normally iterate through a rectangular subgrid. The initial solution is presented in grid_coarse(). This solution is quite efficient in Fortran or C but is not an effective solution when used with the Numeric package. The convert method in GridCoarse avoids the inner loop and is useful for converting a number of 2-d grids all having the same grid dimensions. This is just what is called for when converting the horizontal planes in a 3d volume.
The original Fortran version for grid_coarse() was provided by the Forecast System Laboratory at NOAA.

 Download
Download Copy to clipboard
Copy to clipboard
