source: trunk/SRC/Interpolation/extrapolate.pro

Last change on this file was 502, checked in by smasson, 8 years ago

bugfix in extrapolate for 1d array andwhen using smwin

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