source: trunk/SRC/Interpolation/compute_fromirr_bilinear_weigaddr.pro @ 325

Last change on this file since 325 was 325, checked in by pinsard, 17 years ago

modification of some headers (+some corrections) to prepare usage of the new idldoc

  • Property svn:keywords set to Id
File size: 13.4 KB
RevLine 
[110]1;+
[232]2;
[136]3; @file_comments
[125]4; compute the weight and address needed to interpolate data from
5; an "irregular 2D grid" (defined as a grid made of quadrilateral cells)
6; to any grid using the bilinear method
7;
[226]8; @categories
[157]9; Interpolation
[110]10;
[202]11; @param olonin {in}{required}{type=2d array}
[136]12; longitude of the input data
[110]13;
[202]14; @param olat {in}{required}{type=2d array}
[136]15; latitude of the input data
16;
[202]17; @param omsk {in}{required}{type=2d array or -1}
[136]18; land/sea mask of the input data
[202]19; put -1 if input data are not masked
[136]20;
[202]21; @param alonin {in}{required}{type=2d array}
[136]22; longitude of the output data
23;
[202]24; @param alat {in}{required}{type=2d array}
[136]25; latitude of the output data
26;
[202]27; @param amsk {in}{required}{type=2d array or -1}
[136]28; land/sea mask of the output data
[202]29; put -1 if output data are not masked
[136]30;
[202]31; @param weig {out}{type=2d array}
32; (see ADDR)
33;
34; @param addr {out}{type=2d array}
[118]35; 2D arrays, weig and addr are the weight and addresses used to
36; perform the interpolation:
37;  dataout = total(weig*datain[addr], 1)
38;  dataout = reform(dataout, jpia, jpja, /over)
[110]39;
40; @restrictions
[125]41;  -  the input grid must be an "irregular 2D grid", defined as a grid made
[271]42;  of quadrilateral cells
[110]43;  -  We supposed the data are located on a sphere, with a periodicity along
[125]44;  the longitude
[110]45;  -  to perform the bilinear interpolation within quadrilateral cells, we
[125]46;  first morph the cell into a square cell and then compute the bilinear
47;  interpolation.
[295]48;  -  if some corners of the cell are land points, their weights are set to 0
[125]49;  and the weight is redistributed on the remaining "water" corners
[110]50;  -  points located out of the southern and northern boundaries or in cells
[295]51;  containing only land points are set the same value as their closest neighbors
[125]52;
[110]53; @history
[125]54;  June 2006: Sebastien Masson (smasson\@lodyc.jussieu.fr)
[118]55;
[226]56; @version
57; $Id$
[118]58;
[110]59;-
[325]60PRO compute_fromirr_bilinear_weigaddr, olonin, olat, omsk, alonin, alat, amsk $
61                                     , weig, addr
[110]62;
[125]63  compile_opt idl2, strictarrsubs
[110]64;
65  jpia = (size(alonin, /dimensions))[0]
66  jpja = (size(alonin, /dimensions))[1]
67;
68  jpio = (size(olonin, /dimensions))[0]
[226]69  jpjo = (size(olonin, /dimensions))[1]
[202]70; mask check
[257]71  IF n_elements(omsk) EQ 1 AND omsk[0] EQ -1 THEN BEGIN
72    omsk = replicate(1b, jpio, jpjo)
[271]73; if this is ORCA2 grid...
74    IF (jpio EQ 180 OR jpio EQ 182) AND (jpjo EQ 149  OR jpjo EQ 148  OR jpjo EQ 147 ) THEN BEGIN
75; we look for ill defined cells.
76      IF jpio EQ 182 THEN lontmp = olonin[1:180, *] ELSE lontmp = olonin
77; longitudinal size of the cells...
78      a = (lontmp-shift(lontmp, 1, 0))
79      d1 = 0.5 * max( [[[a]], [[360+a]]] MOD 360, dimension = 3)
80      a = (lontmp-shift(lontmp, 1, 1))
81      d2 = 0.5 * max( [[[a]], [[360+a]]] MOD 360, dimension = 3)
82      a = (shift(lontmp, 0, 1)-shift(lontmp, 1, 0))
83      d3 = 0.5 * max( [[[a]], [[360+a]]] MOD 360, dimension = 3)
84      a = (shift(lontmp, 0, 1)-shift(lontmp, 1, 1))
85      d4 = 0.5 * max( [[[a]], [[360+a]]] MOD 360, dimension = 3)
86      md = [[[d1]], [[d2]], [[d3]], [[d4]]]
87      bad = max(md, dimension = 3) GE 1.5
88      bad = (bad + shift(bad, -1, -1) + shift(bad, 0, -1) + shift(bad, -1, 0)) < 1
89      IF jpio EQ 182 THEN BEGIN
90        omsk[1:180, 80:120] = 1b - bad[*, 80:120]
91        omsk[0, *] = omsk[180, *]
92        omsk[181, *] = omsk[1, *]
93      ENDIF ELSE omsk[*, 80:120] = 1b - bad[*, 80:120]
94    ENDIF
95  ENDIF ELSE BEGIN
96    IF n_elements(omsk) NE jpio*jpjo THEN BEGIN
97      ras = report('input grid mask do not have the good size')
98      stop
99    ENDIF
100  ENDELSE
101  IF n_elements(amsk) EQ 1 AND amsk[0] EQ -1 THEN amsk = replicate(1b, jpia, jpja) ELSE BEGIN
102    IF n_elements(amsk) NE jpia*jpja THEN BEGIN
103      ras = report('output grid mask do not have the good size')
104      stop
105    ENDIF
106  ENDELSE
[110]107;
108; longitude, between 0 and 360
109  alon = alonin MOD 360
[125]110  out = where(alon LT 0)
[110]111  IF out[0] NE -1 THEN alon[out] = alon[out]+360
112  olon = olonin MOD 360
[125]113  out = where(olon LT 0)
[110]114  IF out[0] NE -1 THEN olon[out] = olon[out]+360
115;
[297]116; we work only on the output grid water points
[110]117  awater = where(amsk EQ 1)
[125]118  nawater = n_elements(awater)
[110]119;
120; define all cells that have corners located at olon, olat
121; we define the cell with the address of all corners
122;
123;            3        2
124;             +------+
125;             |      |
126;             |      |
127;             |      |
128;             +------+
129;            0        1
130;
131  alladdr = lindgen(jpio, jpjo-1)
[303]132  alladdrm1 = shift(alladdr, -1)
133  IF ((jpio EQ 92  ) AND (jpjo EQ 76   OR jpjo EQ 75   OR jpjo EQ 74  )) OR $
134     ((jpio EQ 182 ) AND (jpjo EQ 149  OR jpjo EQ 148  OR jpjo EQ 147 )) OR $
135     ((jpio EQ 722 ) AND (jpjo EQ 522  OR jpjo EQ 521  OR jpjo EQ 520 )) OR $
136     ((jpio EQ 1442) AND (jpjo EQ 1021 OR jpjo EQ 1020 OR jpjo EQ 1019)) THEN alladdrm1[jpio-1, *] = alladdr[2, *]
137 
[110]138  celladdr = lonarr(4, jpio*(jpjo-1))
139  celladdr[0, *] = alladdr
[303]140  celladdr[1, *] = alladdrm1
141  celladdr[2, *] = temporary(alladdrm1) + jpio
142  celladdr[3, *] = temporary(alladdr) + jpio
[110]143;
144; list the cells that have at least 1 ocean point as corner
145  good = where(total(omsk[celladdr], 1) GT 0)
[125]146; keep only those cells
[110]147  celladdr = celladdr[*, temporary(good)]
148;
149  xcell = olon[celladdr]
150  minxcell = min(xcell, dimension = 1, max = maxxcell)
151  ycell = olat[celladdr]
152  minycell = min(ycell, dimension = 1, max = maxycell)
153; foraddr: address of the ocean water cell associated to each atmosphere water point
154  foraddr = lonarr(nawater)
155; forweight: x/y position of the atmosphere water point in the ocean water cell
156  forweight = dblarr(nawater, 2)
157;
158; Loop on all the water point of the atmosphere
159; We look for which ocean water cell contains the atmosphere water point
160;
[303]161  delta = max([(360./jpio), (180./jpjo)])* 3.
[110]162  FOR n = 0L, nawater-1 DO BEGIN
163; control print
164    IF (n MOD 5000) EQ 0 THEN print, n
[121]165; longitude and latitude of the atmosphere water point
[110]166    xx = alon[awater[n]]
167    yy = alat[awater[n]]
168; 1) we reduce the number of ocean cells for which we will try to know if
[125]169; xx,yy is inside.
[110]170    CASE 1 OF
[295]171; if we are near the north pole
[110]172      yy GE (90-delta):BEGIN
173        lat1 = 90-2*delta
174        good = where(maxycell GE lat1)
175        onsphere = 1
176      END
177; if we are near the longitude periodicity area
[125]178      xx LE delta OR xx GE (360-delta):BEGIN
[110]179        lat1 = yy-delta
180        lat2 = yy+delta
181        good = where((minxcell LE 2*delta OR maxxcell GE (360-2*delta)) AND maxycell GE lat1 AND minycell LE lat2)
182        onsphere = 1
183      END
184; other cases
185      ELSE:BEGIN
186        lon1 = xx-delta
187        lon2 = xx+delta
188        lat1 = yy-delta
189        lat2 = yy+delta
190        good = where(maxxcell GE lon1 AND minxcell LE lon2 AND maxycell GE lat1 AND minycell le lat2)
191; ORCA cases : orca grid is irregular only northward of 40N
192        CASE 1 OF
[303]193          (jpio EQ 90   OR jpio EQ 92  ) AND (jpjo EQ 76   OR jpjo EQ 75   OR jpjo EQ 74  ):onsphere = yy GT 40
194          (jpio EQ 180  OR jpio EQ 182 ) AND (jpjo EQ 149  OR jpjo EQ 148  OR jpjo EQ 147 ):onsphere = yy GT 40
195          (jpio EQ 720  OR jpio EQ 722 ) AND (jpjo EQ 522  OR jpjo EQ 521  OR jpjo EQ 520 ):onsphere = yy GT 40
[271]196          (jpio EQ 1440 OR jpio EQ 1442) AND (jpjo EQ 1021 OR jpjo EQ 1020 OR jpjo EQ 1019):onsphere = yy GT 40
[110]197          ELSE:onsphere = 1
198        ENDCASE
199      END
200    ENDCASE
201; we found a short list of possible ocean water cells containing the atmosphere water point
202    IF good[0] NE -1 THEN BEGIN
203; in which cell is located the atmosphere water point?
204; Warning! inquad use clockwise quadrilateral definition
205      ind = inquad(xx, yy $
206                   , xcell[0, good], ycell[0, good] $
207                   , xcell[3, good], ycell[3, good] $
208                   , xcell[2, good], ycell[2, good] $
209                   , xcell[1, good], ycell[1, good] $
[303]210                   , onsphere = onsphere, newcoord = newcoord, /noprint, delta = delta, /double)
[110]211; keep only the first cell (if the atmospheric point was located in several ocean cells)
212      ind = ind[0]
213; we found one ocean water cell containing the atmosphere water point
214      IF ind NE -1 THEN BEGIN
215        ind = good[ind]
216; now, we morph the quadrilateral ocean cell into the reference square (0 -> 1)
[226]217; in addition we get the coordinates of the atmospheric point in this new morphed square
[110]218        IF onsphere THEN BEGIN
219; Warning! quadrilateral2square use anticlockwise quadrilateral definition
220          xy = quadrilateral2square(newcoord[0, 0], newcoord[1, 0] $
221                                    , newcoord[0, 3], newcoord[1, 3] $
222                                    , newcoord[0, 2], newcoord[1, 2] $
223                                    , newcoord[0, 1], newcoord[1, 1] $
[282]224                                    , newcoord[0, 4], newcoord[1, 4], /double)
[110]225        ENDIF ELSE BEGIN
226          xy = quadrilateral2square(xcell[0, ind], ycell[0, ind] $
227                                    , xcell[1, ind], ycell[1, ind] $
228                                    , xcell[2, ind], ycell[2, ind] $
[282]229                                    , xcell[3, ind], ycell[3, ind], xx, yy, /double)
[125]230        ENDELSE
[110]231; take care of rounding errors...
[282]232        zero = where(abs(xy) LT 1e-6)
233        IF zero[0] NE -1 THEN xy[zero] = 0.d
234        one = where(abs(1.d - xy) LT 1e-6)
235        IF one[0] NE -1 THEN xy[one] = 1.d
[202]236; some checks...
237        tmpmsk = omsk[celladdr[*, ind]]
238        CASE 1 OF
239          xy[0] LT 0 OR xy[0] GT 1 : stop
240          xy[1] LT 0 OR xy[1] GT 1 : stop
241          xy[0] EQ 0 AND xy[1] EQ 0 AND tmpmsk[0] EQ 0 : foraddr[n] = -1
242          xy[0] EQ 1 AND xy[1] EQ 0 AND tmpmsk[1] EQ 0 : foraddr[n] = -1
243          xy[0] EQ 1 AND xy[1] EQ 1 AND tmpmsk[2] EQ 0 : foraddr[n] = -1
244          xy[0] EQ 0 AND xy[1] EQ 1 AND tmpmsk[3] EQ 0 : foraddr[n] = -1
245          xy[0] EQ 0 AND (tmpmsk[0]+tmpmsk[3]) EQ 0    : foraddr[n] = -1
246          xy[0] EQ 1 AND (tmpmsk[1]+tmpmsk[2]) EQ 0    : foraddr[n] = -1
247          xy[1] EQ 0 AND (tmpmsk[0]+tmpmsk[1]) EQ 0    : foraddr[n] = -1
248          xy[1] EQ 1 AND (tmpmsk[2]+tmpmsk[3]) EQ 0    : foraddr[n] = -1
[226]249          ELSE: BEGIN
[202]250; we keep its address
[271]251            foraddr[n] = ind
[110]252; keep the new coordinates
[202]253            forweight[n, 0] = xy[0]
254            forweight[n, 1] = xy[1]
255          END
256        ENDCASE
[110]257      ENDIF ELSE foraddr[n] = -1
258    ENDIF ELSE foraddr[n] = -1
259  ENDFOR
260; do we have some water atmospheric points that are not located in an water oceanic cell?
261  bad = where(foraddr EQ -1)
262  IF bad[0] NE -1 THEN BEGIN
263; yes?
264; we look for neighbor water atmospheric point located in water oceanic cell
265    badaddr = awater[bad]
266    good = where(foraddr NE -1)
267; list the atmospheric points located in water oceanic cell
268    goodaddr = awater[good]
269; there longitude and latitude
270    goodlon = alon[goodaddr]
271    goodlat = alat[goodaddr]
272; for all the bad points, look for a neighbor
273    neig = lonarr(n_elements(bad))
[303]274    onsphere = 1
275    FOR i = 0L, n_elements(bad)-1L DO BEGIN
276      IF (i MOD 500) EQ 0 THEN print, i
277      xtmp = alon[badaddr[i]]
278      ytmp = alat[badaddr[i]]
279      CASE 1 OF
280; if we are near the north pole
281        ytmp GE (90-delta):keep = where(goodlat GE 90-3*delta, cnt)
282; if we are near the longitude periodicity area
283        xtmp LE delta OR xtmp GE (360-delta):keep = where((goodlon LE 3*delta OR goodlon GE (360-3*delta)) $
284                                                          AND goodlat GE (ytmp-3*delta) AND goodlat LE (ytmp+3*delta), cnt)
285; other cases
286        ELSE:BEGIN
287          keep = where(goodlon GE (xtmp-3*delta) AND goodlon LE (xtmp+3*delta) $
288                       AND goodlat GE (ytmp-3*delta) AND goodlat le (ytmp+3*delta), cnt)
289; ORCA cases : orca grid is irregular only northward of 40N
290          CASE 1 OF
291            (jpio EQ 90   OR jpio EQ 92  ) AND (jpjo EQ 76   OR jpjo EQ 75   OR jpjo EQ 74  ):onsphere = yy GT 40
292            (jpio EQ 180  OR jpio EQ 182 ) AND (jpjo EQ 149  OR jpjo EQ 148  OR jpjo EQ 147 ):onsphere = yy GT 40
293            (jpio EQ 720  OR jpio EQ 722 ) AND (jpjo EQ 522  OR jpjo EQ 521  OR jpjo EQ 520 ):onsphere = yy GT 40
294            (jpio EQ 1440 OR jpio EQ 1442) AND (jpjo EQ 1021 OR jpjo EQ 1020 OR jpjo EQ 1019):onsphere = yy GT 40
295            ELSE:
296          ENDCASE
297        END
298      ENDCASE
299      IF cnt NE 0 THEN BEGIN
300        neig[i] = keep[(neighbor(xtmp, ytmp, goodlon[keep], goodlat[keep], sphere = onsphere))[0]]
301      ENDIF ELSE neig[i] = (neighbor(alon[badaddr[i]], alat[badaddr[i]], goodlon, goodlat, sphere = onsphere))[0]
[110]302    ENDFOR
303; get the address regarding foraddr
304    neig = good[neig]
305; associate each bad point with its neighbor (get its address and weight)
306    foraddr[bad] = foraddr[neig]
307    forweight[bad, *] = forweight[neig, *]
[303]308  ENDIF
[110]309; transform the address of the ocean cell into the address of its 4 corners
310  newaaddr = celladdr[*, temporary(foraddr)]
311; now we compute the weight to give at each corner
312  newaweig = dblarr(4, nawater)
313  a = reform(forweight[*, 0], 1, nawater)
314  b = reform(forweight[*, 1], 1, nawater)
[271]315  forweight =  -1               ; free memory
[309]316  newaweig = [(1.d - a)*(1.d - b), (1.d - b)*a, a*b, (1.d - a)*b]
[271]317  a = -1 &  b = -1              ; free memory
[110]318; mask the weight to suppress the corner located on land
[307]319  newaweig = newaweig*(omsk[newaaddr])
[110]320; for cell with some land corner,
[282]321; we have to redistribute the weight on the remaining water corners
[110]322; weights normalization
[282]323  totalweig = total(newaweig, 1, /double)
[309]324;;   IF min(totalweig, max = ma) LE 0.d then stop
325;;   IF ma- 1.d GT 1.e-6 then stop
[282]326  newaweig = newaweig/(replicate(1.d, 4)#totalweig)
[110]327; weights
328  weig = dblarr(4, jpia*jpja)
329  weig[*, awater] = temporary(newaweig)
330; address
[307]331  addr = lonarr(4, jpia*jpja)
[110]332  addr[*, awater] = temporary(newaaddr)
333;
334  RETURN
335END
Note: See TracBrowser for help on using the repository browser.