1 | ;+ |
---|
2 | ; |
---|
3 | ; @file_comments |
---|
4 | ; compute the weight and address needed to interpolate data from a |
---|
5 | ; "regular grid" to any grid using the bilinear method |
---|
6 | ; |
---|
7 | ; @categories |
---|
8 | ; Interpolation |
---|
9 | ; |
---|
10 | ; @param alonin{in}{required}{type=2d array} |
---|
11 | ; longitude of the input data |
---|
12 | ; |
---|
13 | ; @param alatin {in}{required}{type=2d array} |
---|
14 | ; latitude of the input data |
---|
15 | ; |
---|
16 | ; @param olonin {in}{required}{type=2d array} |
---|
17 | ; longitude of the output data |
---|
18 | ; |
---|
19 | ; @param olat {in}{required}{type=2d array} |
---|
20 | ; latitude of the output data |
---|
21 | ; |
---|
22 | ; @keyword NONORTHERNLINE {type=scalar 0 or 1}{default=0} |
---|
23 | ; put 1 if you don't want to take into |
---|
24 | ; account the northern line of the input data when performing the interpolation. |
---|
25 | ; |
---|
26 | ; @keyword NOSOUTHERNLINE {type=scalar 0 or 1}{default=0} |
---|
27 | ; put 1 if you don't want to take into |
---|
28 | ; account the southern line of the input data when performing the interpolation. |
---|
29 | ; |
---|
30 | ; @param weig {out}{type=2d array} |
---|
31 | ; (see ADDR) |
---|
32 | ; |
---|
33 | ; @param addr {out}{type=2d array} |
---|
34 | ; 2D arrays, weig and addr are the weight and addresses used to |
---|
35 | ; perform the interpolation: |
---|
36 | ; dataout = total(weig*datain[addr], 1) |
---|
37 | ; dataout = reform(dataout, jpio, jpjo, /over) |
---|
38 | ; |
---|
39 | ; @restrictions |
---|
40 | ; - the input grid must be a "regular grid", defined as a grid for which each |
---|
41 | ; longitude lines have the same latitude and each latitude columns have the |
---|
42 | ; same longitude. |
---|
43 | ; - We supposed the data are located on a sphere, with a periodicity along |
---|
44 | ; the longitude. |
---|
45 | ; - points located out of the southern and northern boundaries are interpolated |
---|
46 | ; using a linear interpolation only along the longitudinal direction. |
---|
47 | ; |
---|
48 | ; @history |
---|
49 | ; November 2005: Sebastien Masson (smasson\@lodyc.jussieu.fr) |
---|
50 | ; |
---|
51 | ; @version |
---|
52 | ; $Id$ |
---|
53 | ; |
---|
54 | ;- |
---|
55 | PRO compute_fromreg_bilinear_weigaddr, alonin, alatin, olonin, olat $ |
---|
56 | , weig , addr $ |
---|
57 | , NONORTHERNLINE = nonorthernline $ |
---|
58 | , NOSOUTHERNLINE = nosouthernline |
---|
59 | ; |
---|
60 | compile_opt idl2, strictarrsubs |
---|
61 | ; |
---|
62 | alon = alonin |
---|
63 | alat = alatin |
---|
64 | olon = olonin |
---|
65 | ; |
---|
66 | jpia = n_elements(alon) |
---|
67 | jpja = n_elements(alat) |
---|
68 | ; |
---|
69 | jpio = (size(olon, /dimensions))[0] |
---|
70 | jpjo = (size(olon, /dimensions))[1] |
---|
71 | ; |
---|
72 | ; alon |
---|
73 | minalon = min(alon, max = maxalon) |
---|
74 | IF maxalon-minalon GE 360. THEN stop |
---|
75 | ; alon must be monotonically increasing |
---|
76 | IF array_equal(sort(alon), lindgen(jpia)) NE 1 THEN BEGIN |
---|
77 | shiftx = -(where(alon EQ min(alon)))[0] |
---|
78 | alon = shift(alon, shiftx) |
---|
79 | IF array_equal(sort(alon), lindgen(jpia)) NE 1 THEN stop |
---|
80 | ENDIF ELSE shiftx = 0 |
---|
81 | ; for longitude periodic boundary condition we add the fist |
---|
82 | ; column on the right side of the array and |
---|
83 | alon = [alon, alon[0]+360.] |
---|
84 | jpia = jpia+1L |
---|
85 | ; alat |
---|
86 | revy = alat[0] GT alat[1] |
---|
87 | IF revy THEN alat = reverse(alat) |
---|
88 | ; alat must be monotonically increasing |
---|
89 | IF array_equal(sort(alat), lindgen(jpja)) NE 1 THEN stop |
---|
90 | ; |
---|
91 | if keyword_set(nonorthernline) then BEGIN |
---|
92 | jpja = jpja - 1L |
---|
93 | alat = alat[0: jpja-1L] |
---|
94 | ENDIF |
---|
95 | if keyword_set(nosouthernline) then BEGIN |
---|
96 | alat = alat[1: jpja-1L] |
---|
97 | jpja = jpja - 1L |
---|
98 | ENDIF |
---|
99 | ; olon between minalon and minalon+360 |
---|
100 | out = where(olon LT minalon) |
---|
101 | WHILE out[0] NE -1 DO BEGIN |
---|
102 | olon[out] = olon[out]+360. |
---|
103 | out = where(olon LT minalon) |
---|
104 | ENDWHILE |
---|
105 | out = where(olon GE minalon+360.) |
---|
106 | WHILE out[0] NE -1 DO BEGIN |
---|
107 | olon[out] = olon[out]- 360. |
---|
108 | out = where(olon GE minalon+360.) |
---|
109 | ENDWHILE |
---|
110 | ; make sure that all values of olon are located within values of alon |
---|
111 | IF min(olon, max = ma) LT minalon THEN stop |
---|
112 | IF ma GE minalon+360. THEN stop |
---|
113 | ; |
---|
114 | ; we want to do bilinear interpolation => for each ocean point, we must |
---|
115 | ; find in which atm cell it is located. |
---|
116 | ; if the ocean point is out of the atm grid, we use closest neighbor |
---|
117 | ; interpolation |
---|
118 | ; |
---|
119 | ; for each T point of oce grid, we find in which atmospheric cell it is |
---|
120 | ; located. |
---|
121 | ; As the atmospheric grid is regular, we can use inrecgrid instead |
---|
122 | ; of inquad. |
---|
123 | pos = inrecgrid(olon, olat, alon[0:jpia-2L], alat[0:jpja-2L] $ |
---|
124 | , checkout = [alon[jpia-1L], alat[jpja-1L]], /output2d) |
---|
125 | ; checks... |
---|
126 | ; for longitude, each ocean point must be located in atm cell. |
---|
127 | IF (where(pos[0, *] EQ -1))[0] NE -1 THEN stop |
---|
128 | ; no ocean point should be located westward of the left boundary of the |
---|
129 | ; atm cell in which it is supposed to be located |
---|
130 | IF total(olon LT alon[pos[0, *]]) NE 0 THEN stop |
---|
131 | ; no ocean point should be located eastward of the right boundary of the |
---|
132 | ; atm cell in which it is supposed to be located |
---|
133 | IF total(olon GT alon[pos[0, *]+1]) NE 0 THEN stop |
---|
134 | ; |
---|
135 | ; we use bilinear interpolation |
---|
136 | ; |
---|
137 | ; we change the coordinates of each ocean point to fit into a |
---|
138 | ; rectangle defined by: |
---|
139 | ; |
---|
140 | ; y2 *------------* |
---|
141 | ; | | |
---|
142 | ; | | |
---|
143 | ; | | |
---|
144 | ; y1 *------------* |
---|
145 | ; x1 x2 |
---|
146 | ; |
---|
147 | ; X = (x-x1)/(x2-x1) |
---|
148 | ; Y = (y-y1)/(y2-y1) |
---|
149 | ; |
---|
150 | indx = pos[0, *] |
---|
151 | indy = (temporary(pos))[1, *] |
---|
152 | ; points located out of the atmospheric grid...(too much northward or southward) |
---|
153 | bad = where(indy EQ -1) |
---|
154 | indy = 0 > indy |
---|
155 | ; |
---|
156 | IF max(indx) GT jpia-2 THEN stop ; checks... |
---|
157 | IF max(indy) GT jpja-2 THEN stop ; checks... |
---|
158 | ; x coordinates of the atm cell |
---|
159 | x1 = alon[indx] |
---|
160 | x2 = alon[indx+1] |
---|
161 | ; new x coordinates of the ocean points in each cell |
---|
162 | divi = temporary(x2)-x1 |
---|
163 | glamnew = (olon-x1)/temporary(divi) |
---|
164 | x1 = -1 ; free memory |
---|
165 | olon = -1 ; free memory |
---|
166 | ; y coordinates of the atm cell |
---|
167 | y1 = alat[indy] |
---|
168 | y2 = alat[indy+1] ; |
---|
169 | ; new y coordinates of the ocean points in each cell |
---|
170 | divi = temporary(y2)-y1 |
---|
171 | zero = where(divi EQ 0) |
---|
172 | IF zero[0] NE -1 THEN divi[zero] = 1. |
---|
173 | gphinew = (olat-y1)/temporary(divi) |
---|
174 | y1 = -1 ; free memory |
---|
175 | ; checks... |
---|
176 | IF min(glamnew) LT 0 THEN stop |
---|
177 | IF max(glamnew) GT 1 THEN stop |
---|
178 | ; |
---|
179 | ; weight and address array used for bilinear interpolation. |
---|
180 | xaddr = lonarr(4, jpio*jpjo) |
---|
181 | xaddr[0, *] = indx |
---|
182 | xaddr[1, *] = indx + 1L |
---|
183 | xaddr[2, *] = indx + 1L |
---|
184 | xaddr[3, *] = indx |
---|
185 | ; |
---|
186 | yaddr = lonarr(4, jpio*jpjo) |
---|
187 | yaddr[0, *] = indy |
---|
188 | yaddr[1, *] = indy |
---|
189 | yaddr[2, *] = indy + 1L |
---|
190 | yaddr[3, *] = indy + 1L |
---|
191 | ; compute the weight for the bilinear interpolation. |
---|
192 | weig = fltarr(4, jpio*jpjo) |
---|
193 | weig[0, *] = (1.-glamnew) * (1.-gphinew) |
---|
194 | weig[1, *] = glamnew * (1.-gphinew) |
---|
195 | weig[2, *] = glamnew * gphinew |
---|
196 | weig[3, *] = (1.-glamnew) * gphinew |
---|
197 | ; free memory |
---|
198 | gphinew = -1 |
---|
199 | IF bad[0] EQ -1 THEN glamnew = -1 ELSE glamnew = (temporary(glamnew))[bad] |
---|
200 | ; we work now on the "bad" points |
---|
201 | ; linear interpolation only along the longitudinal direction |
---|
202 | IF bad[0] NE -1 THEN BEGIN |
---|
203 | ybad = olat[bad] |
---|
204 | ; the ocean points that are not located into an atm cell should be |
---|
205 | ; located northward of the northern boundary of the atm grid |
---|
206 | ; or southward of the southern boundary of the atm grid |
---|
207 | IF total(ybad GE min(alat) AND ybad LE max(alat)) GE 1 THEN stop |
---|
208 | ; |
---|
209 | weig[0, bad] = (1.-glamnew) |
---|
210 | weig[1, bad] = temporary(glamnew) |
---|
211 | weig[2, bad] = 0. |
---|
212 | weig[3, bad] = 0. |
---|
213 | south = where(ybad LT alat[0]) |
---|
214 | IF south[0] NE -1 THEN yaddr[*, bad[temporary(south)]] = 0L |
---|
215 | north = where(ybad GT alat[jpja-1]) |
---|
216 | IF north[0] NE -1 THEN yaddr[*, bad[temporary(north)]] = jpja-1 |
---|
217 | ybad = -1 & bad = -1 ; free memory |
---|
218 | ENDIF |
---|
219 | ; check totalweight = 1 |
---|
220 | totalweig = abs(1.d - total(weig, 1, /double)) |
---|
221 | IF (where(temporary(totalweig) GE 1.e-5))[0] NE -1 THEN stop |
---|
222 | ; |
---|
223 | ; come back to the original atm grid without longitudinal overlap. |
---|
224 | ; |
---|
225 | jpia = jpia-1L |
---|
226 | xaddr = temporary(xaddr) MOD jpia |
---|
227 | ; take into account shiftx if needed |
---|
228 | IF shiftx NE 0 THEN xaddr = (temporary(xaddr) - shiftx) MOD jpia |
---|
229 | ; take into account nosouthernline and nonorthernline |
---|
230 | if keyword_set(nosouthernline) then BEGIN |
---|
231 | yaddr = temporary(yaddr) + 1L |
---|
232 | jpja = jpja + 1L |
---|
233 | ENDIF |
---|
234 | if keyword_set(nonorthernline) then jpja = jpja + 1L |
---|
235 | ; take into account revy if needed |
---|
236 | IF revy EQ 1 THEN yaddr = jpja - 1L - temporary(yaddr) |
---|
237 | ; ; |
---|
238 | addr = temporary(yaddr)*jpia + temporary(xaddr) |
---|
239 | ; |
---|
240 | return |
---|
241 | end |
---|