source: trunk/SRC/Interpolation/extrapolate.pro @ 411

Last change on this file since 411 was 384, checked in by smasson, 16 years ago

add fill(xy)dir keyword to extrapolate

  • Property svn:keywords set to Id
File size: 7.5 KB
RevLine 
[101]1;+
[232]2;
[136]3; @file_comments
[238]4; extrapolate data (zinput) where maskinput equal 0 by filling step by
[295]5; step the coastline points with the mean value of the 8 neighbors
6; (weighted by their mask values).
[101]7;
[226]8; @categories
[157]9; Interpolation
10;
[202]11; @param zinput {in}{required}{type=2d array}
[118]12; data to be extrapolate
13;
[202]14; @param maskinput {in}{required}{type=2d array or -1}
15; a 2D array, the land-sea mask of the output data (1 on ocean, 0 on land)
16; put -1 if input data are not masked
[118]17;
[271]18; @param nb_iteration {in}{optional}{type=integer}{default=large enough to fill everything}
[242]19; Maximum number of iterations done in the extrapolation process. If there
[202]20; is no more masked values we exit extrapolate before reaching nb_iteration
[118]21;
[384]22; @keyword FILLXDIR {type=scalar, 0 or 1}{default=0}
23; put 1 to specify that filling of the data must be done only along x direction
24;
25; @keyword FILLYDIR {type=scalar, 0 or 1}{default=0}
26; put 1 to specify that filling of the data must be done only along y direction
27;
[261]28; @keyword X_PERIODIC {type=scalar, 0 or 1}{default=0}
[202]29; put 1 to specify that the data are periodic along x axis
[118]30;
[202]31; @keyword MINVAL {type=scalar}{default=not used}
32; to specify a minimum value to the extrapolated values
33;
34; @keyword MAXVAL {type=scalar}{default=not used}
35; to specify a maximum value to the extrapolated values
36;
37; @keyword GE0 {type=scalar 0 or 1}{default=0}
38; put 1 to force the extrapolated values to be larger than 0, same as using minval=0.
39;
[271]40; @keyword
41; _EXTRA to be able to call extrapolate with _extra keyword
42;
[238]43; @returns
44; the extrapolated 2d array
[202]45;
46; @examples
[371]47;
48;   IDL> a=extrapolate(dist(jpi,jpj),tmask[*,*,0],/x_periodic)
49;   IDL> tvplus, a
50;   IDL> tvplus, a*(1-tmask[*,*,0])
51;
[202]52; get the coastline:
53;
[371]54;   IDL> a=extrapolate(tmask[*,*,0],tmask[*,*,0],1,/x_periodic)
55;   IDL> tvplus, a-tmask[*,*,0]
56;
[202]57; @history
[292]58;  Originaly written by G. Roullet
[202]59;  Sebastien Masson (smasson\@lodyc.jussieu.fr)
60;
[226]61; @version
62; $Id$
[118]63;
[101]64;-
[384]65FUNCTION extrapolate, zinput, maskinput, nb_iteration, FILLXDIR = fillxdir, FILLYDIR = fillydir $
66                      , X_PERIODIC = x_periodic, MINVAL=minval, MAXVAL=maxval, GE0=ge0, _EXTRA=ex
[59]67;
[125]68  compile_opt idl2, strictarrsubs
[59]69;
70; check the number of iteration used in the extrapolation.
[271]71  szin = size(zinput)
72  IF szin[0] NE 2 THEN return, -1. ELSE szin = szin[1:2]
73  nx = szin[0]
74  ny = szin[1]
75  IF n_elements(nb_iteration) EQ 0 THEN nb_iteration = max(szin)
[59]76  IF nb_iteration EQ 0 THEN return, zinput
77; take care of the boundary conditions...
[125]78;
[59]79; for the x direction, we put 2 additional columns at the left and
[125]80; right side of the array.
[59]81; for the y direction, we put 2 additional lines at the bottom and
[125]82; top side of the array.
[59]83; These changes allow us to use shift function without taking care of
84; the x and y periodicity.
85;
[381]86  msk = bytarr(nx+2, ny+2)
[202]87  IF n_elements(maskinput) EQ 1 AND maskinput[0] EQ -1 THEN maskinput = replicate(1b, nx, ny)
[226]88  IF n_elements(maskinput) NE nx*ny THEN BEGIN
[236]89    ras = report('input grid mask do not have the good size')
[202]90    return, -1
91  ENDIF
[381]92  msk[1:nx, 1:ny] = byte(maskinput)
[59]93;
94  ztmp = replicate(1.e20, nx+2, ny+2)
95  ztmp[1:nx, 1:ny] = zinput
96  if keyword_set(x_periodic) then begin
97    ztmp[0, 1:ny] = zinput[nx-1, *]
98    ztmp[nx+1, 1:ny] = zinput[0, *]
99  ENDIF
100; remove NaN points if there is some...
[381]101  finztmp = finite(ztmp)
102  nan = where(finztmp EQ 0, cnt_nan)
103  IF cnt_nan NE 0 THEN BEGIN
104    ztmp[temporary(nan)] = 1.e20
105    msk = temporary(msk) * temporary(finztmp)
106  ENDIF ELSE finztmp = -1 ; free memory
[59]107  z = temporary(ztmp)
108  nx2 = nx+2
109  ny2 = ny+2
110;---------------------------------------------------------------
111;---------------------------------------------------------------
[125]112; extrapolation
[59]113;---------------------------------------------------------------
114  sqrtinv = 1./sqrt(2)
115;
[69]116  cnt = 1
[226]117; When we look for the coastline, we don't want to select the
[59]118; borderlines of the array. -> we force the value of the mask for
119; those lines.
120  msk[0, *] = 1b
121  msk[nx+1, *] = 1b
122  msk[*, 0] = 1b
123  msk[*, ny+1] = 1b
124; find the land points
125  land = where(msk EQ 0, cnt_land)
[384]126  IF keyword_set(fillxdir) THEN BEGIN
127    tst = total(msk[1:nx, 1:ny], 1)
128    cnt_land = total(tst NE 0 AND tst NE nx)
129  ENDIF
130  IF keyword_set(fillydir) THEN BEGIN
131    tst = total(msk[1:nx, 1:ny], 2)
132    cnt_land = total(tst NE 0 AND tst NE ny)
133  ENDIF
[59]134;---------------------------------------------------------------
135  WHILE cnt LE nb_iteration AND cnt_land NE 0 DO BEGIN
136;---------------------------------------------------------------
[226]137; find the coastline points...
[59]138;---------------------------------------------------------------
[238]139; Once the land points list has been found, we change back the
[59]140; mask values for the boundary conditions.
141    msk[0, *] = 0b
142    msk[nx+1, *] = 0b
143    msk[*, 0] = 0b
144    msk[*, ny+1] = 0b
145    if keyword_set(x_periodic) then begin
146      msk[0, *] = msk[nx, *]
147      msk[nx+1, *] = msk[1, *]
148    endif
149;
[295]150; we compute the weighted number of sea neighbors.
151; those 4 neighbors have a weight of 1:
[125]152;    *
153;   *+*
154;    *
[59]155;
[295]156; those 4 neighbors have a weight of 1/sqrt(2):
[59]157;
158;    * *
[125]159;     +
[59]160;    * *
161;
162; As we make sure that none of the land points are located on the
163; border of the array, we can compute the weight without shift
164; (faster).
[384]165;
166    CASE 1 OF
167      keyword_set(fillxdir):weight = msk[land+1]+msk[land-1]
168      keyword_set(fillydir):weight = msk[land+nx2]+msk[land-nx2]
169      ELSE:weight = msk[land+1]+msk[land-1]+msk[land+nx2]+msk[land-nx2] $
170                    +sqrtinv*(msk[land+nx2+1]+msk[land+nx2-1] $
171                              +msk[land-nx2+1]+msk[land-nx2-1])
172    ENDCASE
[295]173; list all the points that have sea neighbors
[59]174    ok = where(weight GT 0)
175; the coastline points
176    coast = land[ok]
[295]177; their weighted number of sea neighbors.
[59]178    weight = weight[temporary(ok)]
179;---------------------------------------------------------------
[226]180; fill the coastline points
[59]181;---------------------------------------------------------------
182    z = temporary(z)*msk
183;
[384]184    CASE 1 OF
185      keyword_set(fillxdir):zcoast = z[1+coast]+z[-1+coast]
186      keyword_set(fillydir):zcoast = z[nx2+coast]+z[-nx2+coast]
187      ELSE:zcoast = z[1+coast]+z[-1+coast]+z[nx2+coast]+z[-nx2+coast] $
[59]188             +1./sqrt(2)*(z[nx2+1+coast]+z[nx2-1+coast] $
189                          +z[-nx2+1+coast]+z[-nx2-1+coast])
[384]190    ENDCASE
[125]191;
[199]192    IF keyword_set(ge0) THEN zcoast = 0. > temporary(zcoast)
[59]193    IF n_elements(minval) NE 0 THEN zcoast = minval > temporary(zcoast)
194    IF n_elements(maxval) NE 0 THEN zcoast = temporary(zcoast) < maxval
195    z[coast] = temporary(zcoast)/temporary(weight)
[238]196; we update the boundary conditions of z
[59]197    if keyword_set(x_periodic) then begin
198      z[0, *] = z[nx, *]
199      z[nx+1, *] = z[1, *]
200    endif
201;---------------------------------------------------------------
202; we update the mask
203;---------------------------------------------------------------
204    msk[temporary(coast)] = 1
205;
206    cnt = cnt + 1
[125]207; When we look for the coast line, we don't want to select the
[59]208; borderlines of the array. -> we force the value of the mask for
209; those lines.
210    msk[0, *] = 1b
211    msk[nx+1, *] = 1b
212    msk[*, 0] = 1b
213    msk[*, ny+1] = 1b
214; find the land points
215    land = where(msk EQ 0, cnt_land)
[384]216    IF keyword_set(fillxdir) THEN BEGIN
217      tst = total(msk[1:nx, 1:ny], 1)
218      cnt_land = total(tst NE 0 AND tst NE nx)
219    ENDIF
220    IF keyword_set(fillydir) THEN BEGIN
221      tst = total(msk[1:nx, 1:ny], 2)
222      cnt_land = total(tst NE 0 AND tst NE ny)
223    ENDIF
[59]224;
225  ENDWHILE
226;---------------------------------------------------------------
227; we return the original size of the array
228;---------------------------------------------------------------
[125]229;
[59]230  return, z[1:nx, 1:ny]
[125]231END
Note: See TracBrowser for help on using the repository browser.