source: trunk/SRC/Computation/curl.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:eol-style set to native
  • Property svn:keywords set to Id
File size: 13.8 KB
Line 
1;+
2;
3; @file_comments
4; Calculate the vertical component of the curl of a vectors field
5; located on Arakawa C-grid.
6;
7; @categories
8; Calculation
9;
10; @param UU
11; Matrix representing the zonal coordinates (at U point) of a field of vectors
12; A 2D (xy), 3D (xyz or yt) or a structure readable by <pro>litchamp</pro> and containing
13; a 2D (xy), 3D (xyz or yt) array (4D case is not coded yet).
14; Note that the dimension of the array must suit the domain dimension.
15;
16; @param VV
17; Matrix representing the meridional coordinates (at V point) of a field of vectors
18; A 2D (xy), 3D (xyz or yt) or a structure readable by <pro>litchamp</pro> and containing
19; a 2D (xy), 3D (xyz or yt) array (4D case is not coded yet).
20; Note that the dimension of the array must suit the domain dimension.
21;
22; @keyword DIREC {type=scalar string}
23; Use if you want to call <pro>moyenne</pro> or
24; <pro>grossemoyenne</pro> after the div computation
25; with a mean done in the DIREC direction
26;
27; @keyword MILLION {default=0}{type=scalar: 0 or 1}
28; Activate to multiply returned array by 1.e6
29;
30; @keyword _EXTRA
31; Used to declare that this routine accepts inherited keywords
32;
33; @returns
34; the vertical component of the curl of the input data (with the same
35; size) located at F point (see restrictions)
36;
37; @uses
38; cm_4cal
39; cm_4data
40; cm_4mesh
41;
42; @restrictions
43;
44; - Works only for Arakawa C-grid.
45; - UU must be on U grid, VV must be on V grid
46; - 4D case is not coded yet
47; - the common variable jpt is used to differ xyz (jpt=1) and xyt (jpt\=1) cases.
48; - U and V arrays are cut in the same geographic domain. Because of the shift between
49;   T, U, V and F grids, it is possible that these two arrays do not have the same
50;   size and refer to different indexes. In this case, arrays are re-cut on
51;   common indexes. To avoid these re-cuts, use the keyword /memeindice in
52; <pro>domdef</pro>
53; - When computing the divergence, we update, vargrid, varname, varunits and the
54;   grid position parameters (firstxf, lastxf, nxf, firstyf, lastyf, nyf).
55; - points that cannot be computed (domain boundaries, coastline) are set to NaN
56;
57; @examples
58; IDL> @tst_initorca2
59; IDL> plt, curl(dist(jpi,jpj), dist(jpi,jpj))
60;
61; @history
62; Guillaume Roullet (grlod\@ipsl.jussieu.fr)
63; Sebastien Masson (smasson\@lodyc.jussieu.fr)
64; adaptation to work with a reduce domain
65; 21/5/1999: missing values at !values.f_nan
66;
67; @version
68; $Id$
69;
70; @todo
71; code the 4D case
72;
73;-
74FUNCTION curl, uu, vv, DIREC = direc, MILLION = million, _EXTRA = ex
75;
76  compile_opt idl2, strictarrsubs
77;
78@cm_4cal                        ; for jpt
79@cm_4data                       ; for varname, vargrid, vardate, varunit, valmask
80@cm_4mesh
81;
82  time1 = systime(1)          ; for key_performance
83;
84  IF finite(glamu[0])*finite(gphiu[0])*finite(glamv[0])*finite(gphiv[0]) EQ 0 THEN $
85     return, report(['This version of curl is based on Arakawa C-grid.' $
86                     , 'U and V grids must therefore be defined'])
87;
88  gr = litchamp(uu, /grid)
89  IF gr NE '' THEN BEGIN
90    IF gr NE 'U' THEN return, report('the first parameter is not located on U grid, but on '+ strtrim(gr, 2) +'grid')
91  ENDIF
92  gr = litchamp(vv, /grid)
93  IF gr NE '' THEN BEGIN
94    IF gr NE 'V' THEN return, report('the second parameter is not located on V grid, but on '+ strtrim(gr, 2) +'grid')
95  ENDIF
96  u = litchamp(uu)
97  v = litchamp(vv)
98
99  szu = size(u)
100  szv = size(v)
101
102  if szu[0] NE szv[0] then return, report('U and V input data must have the same number of dimensions')
103
104;------------------------------------------------------------
105; We find common points between U and V
106;------------------------------------------------------------
107  indicexu = (lindgen(jpi))[firstxu:firstxu+nxu-1]
108  indicexv = (lindgen(jpi))[firstxv:firstxv+nxv-1]
109  indicex = inter(indicexu, indicexv)
110  indiceyu = (lindgen(jpj))[firstyu:firstyu+nyu-1]
111  indiceyv = (lindgen(jpj))[firstyv:firstyv+nyv-1]
112  indicey = inter(indiceyu, indiceyv)
113  nx = n_elements(indicex)
114  ny = n_elements(indicey)
115  indice2d = lindgen(jpi, jpj)
116  indice2d = indice2d[indicex[0]:indicex[0]+nx-1, indicey[0]:indicey[0]+ny-1]
117;----------------------------------------------------------------------------
118  vargrid = 'F'
119  varname = 'vorticity'
120  IF keyword_set(million) THEN varunits = '1.e6*'+varunit+'/m' ELSE varunits = varunit+'/m'
121  IF keyword_set(million) THEN scale = 1.e6 ELSE scale = 1.
122  if n_elements(valmask) EQ 0 THEN valmask = 1e20
123  firstxf = indicex[0] & lastxf = indicex[0]+nx-1 & nxf = nx
124  firstyf = indicey[0] & lastyf = indicey[0]+ny-1 & nyf = ny
125;----------------------------------------------------------------------------
126;----------------------------------------------------------------------------
127  case 1 of
128;----------------------------------------------------------------------------
129;xyz
130;----------------------------------------------------------------------------
131    szu[0] EQ 3 AND jpt EQ 1:BEGIN
132;------------------------------------------------------------
133; extraction of U and V on the appropriated domain
134;------------------------------------------------------------
135      case 1 of
136        szu[1] EQ nxu AND szu[2] EQ nyu AND $
137           szv[1] EQ nxv AND szv[2] EQ nyv:BEGIN
138          case 1 of
139            nxu NE nx:if indicex[0] EQ firstxu then u = u[0:nx-1, *, *] ELSE u = u[1: nx, *, *]
140            nxv NE nx:if indicex[0] EQ firstxv then v = v[0:nx-1, *, *] ELSE v = v[1: nx, *, *]
141            nyu NE ny:if indicey[0] EQ firstyu then u = u[*, 0:ny-1, *] ELSE u = u[*, 1: ny, *]
142            nyv NE ny:if indicey[0] EQ firstyv then v = v[*, 0:ny-1, *] ELSE v = v[*, 1: ny, *]
143            ELSE :
144          endcase
145        END
146        szu[1] EQ jpi AND szu[2] EQ jpj AND $
147           szv[1] EQ jpi AND szv[2] EQ jpj:BEGIN
148          u = u[indicex[0]:indicex[0]+nx-1, indicey[0]:indicey[0]+ny-1, *]
149          v = v[indicex[0]:indicex[0]+nx-1, indicey[0]:indicey[0]+ny-1, *]
150        END
151        ELSE:return,  -1
152      endcase
153;------------------------------------------------------------
154; curl computation
155;------------------------------------------------------------
156      coefu = ((e1u[indice2d])[*]#replicate(1., nzt)) $
157              * (umask())[indicex[0]:indicex[0]+nx-1, indicey[0]:indicey[0]+ny-1, firstzt:lastzt]
158      landu = where(coefu EQ 0)
159      if landu[0] NE -1 then coefu[temporary(landu)] = !values.f_nan
160
161      coefv = ((e2v[indice2d])[*]#replicate(1., nzt)) $
162              *(vmask())[indicex[0]:indicex[0]+nx-1, indicey[0]:indicey[0]+ny-1, firstzt:lastzt]
163      landv = where(coefv EQ 0)
164      if landv[0] NE -1 then coefv[temporary(landv)] = !values.f_nan
165
166      tabf = scale * (fmask())[indicex[0]:indicex[0]+nx-1, indicey[0]:indicey[0]+ny-1, firstzt:lastzt] $
167             / ((e1f[indice2d]*e2f[indice2d])[*]#replicate(1., nzt))
168      landf =  where(tabf EQ 0)
169;
170      zu = temporary(u) * temporary(coefu)
171      zv = temporary(v) * temporary(coefv)
172
173      psi = (shift(zv, -1, 0, 0)-zv) + (zu-shift(zu, 0, -1, 0))
174      psi = temporary(tabf) * temporary(psi)
175;------------------------------------------------------------
176; Edging put at !values.f_nan
177;------------------------------------------------------------
178      if NOT keyword_set(key_periodic)  OR nx NE jpi then begin
179        psi[0, *, *] = !values.f_nan
180        psi[nx-1, *, *] = !values.f_nan
181      endif
182      psi[*, 0, *] = !values.f_nan
183      psi[*, ny-1, *] = !values.f_nan
184;
185      if landf[0] NE -1 then psi[temporary(landf)] = valmask
186      if keyword_set(direc) then psi = moyenne(psi, direc, /nan)
187    END
188;----------------------------------------------------------------------------
189;----------------------------------------------------------------------------
190;xyt
191;----------------------------------------------------------------------------
192;----------------------------------------------------------------------------
193    szu[0] EQ 3 AND jpt GT 1:BEGIN
194;------------------------------------------------------------
195; extraction of U and V on the appropriated domain
196;------------------------------------------------------------
197      case 1 of
198        szu[1] EQ nxu AND szu[2] EQ nyu AND $
199           szv[1] EQ nxv AND szv[2] EQ nyv:BEGIN
200          if nxu NE nx then $
201             if indicex[0] EQ firstxu then u = u[0:nx-1, *, *] ELSE u = u[1: nx, *, *]
202          IF nxv NE nx THEN $
203             if indicex[0] EQ firstxv then v = v[0:nx-1, *, *] ELSE v = v[1: nx, *, *]
204          IF nyu NE ny THEN $
205             if indicey[0] EQ firstyu then u = u[*, 0:ny-1, *] ELSE u = u[*, 1: ny, *]
206          IF nyv NE ny THEN $
207             if indicey[0] EQ firstyv then v = v[*, 0:ny-1, *] ELSE v = v[*, 1: ny, *]
208        END
209        szu[1] EQ jpi AND szu[2] EQ jpj AND $
210           szv[1] EQ jpi AND szv[2] EQ jpj:BEGIN
211          u = u[indicex[0]:indicex[0]+nx-1, indicey[0]:indicey[0]+ny-1, *]
212          v = v[indicex[0]:indicex[0]+nx-1, indicey[0]:indicey[0]+ny-1, *]
213        END
214        ELSE:return $
215           , report(['We cannot find re-cut on common indexes (see restriction un the header.).' $
216                     , 'To avoid this problem, read the full domain' $
217                     , 'or use the keyword /memeindice in domdef when defining the zoom area'])
218      ENDCASE
219;----------------------------------------------------------------------------
220; curl computation
221;----------------------------------------------------------------------------
222      coefu = e1u[indice2d]*(umask())[indice2d+jpi*jpj*firstzt]
223      landu = where(coefu EQ 0)
224      if landu[0] NE -1 then coefu[temporary(landu)] = !values.f_nan
225      coefu = temporary(coefu[*])#replicate(1., jpt)
226;
227      coefv = e2v[indice2d]*(vmask())[indice2d+jpi*jpj*firstzt]
228      landv = where(coefv EQ 0)
229      if landv[0] NE -1 then coefv[temporary(landv)] = !values.f_nan
230      coefv = temporary(coefv[*])#replicate(1., jpt)
231;
232      tabf = scale * (fmask())[indice2d+jpi*jpj*firstzt]/(e1f[indice2d]*e2f[indice2d])
233      tabf = reform(temporary(tabf[*])#replicate(1., jpt), nx, ny, jpt, /overwrite)
234      landf = where(tabf EQ 0)
235;
236      zu = temporary(u) * temporary(coefu)
237      zv = temporary(v) * temporary(coefv)
238;
239      psi = (shift(zv, -1, 0, 0)-zv) + (zu-shift(zu, 0, -1, 0))
240      psi = temporary(tabf) * temporary(psi)
241;------------------------------------------------------------
242; extraction of U and V on the appropriated domain
243;------------------------------------------------------------
244      if NOT keyword_set(key_periodic) OR nx NE jpi then begin
245        psi[0, *, *] = !values.f_nan
246        psi[nx-1, *, *] = !values.f_nan
247      endif
248      psi[*, 0, *] = !values.f_nan
249      psi[*, ny-1, *] = !values.f_nan
250      if landf[0] NE -1 then psi[temporary(landf)] = valmask
251      if keyword_set(direc) then psi = grossemoyenne(psi, direc, /nan)
252    END
253;----------------------------------------------------------------------------
254;----------------------------------------------------------------------------
255;xyzt
256;----------------------------------------------------------------------------
257;----------------------------------------------------------------------------
258    szu[0] EQ 4:BEGIN
259      return, report('Case not coded contact saxo team or make a do loop!')
260    END
261;----------------------------------------------------------------------------
262;----------------------------------------------------------------------------
263;xy
264;----------------------------------------------------------------------------
265;----------------------------------------------------------------------------
266    szu[0] EQ 2:BEGIN
267;------------------------------------------------------------
268;------------------------------------------------------------
269      case 1 of
270        szu[1] EQ nxu AND szu[2] EQ nyu AND $
271           szv[1] EQ nxv AND szv[2] EQ nyv:BEGIN
272          if nxu NE nx then $
273             if indicex[0] EQ firstxu then u = u[0:nx-1, *] ELSE u = u[1: nx, *]
274          IF nxv NE nx THEN $
275             if indicex[0] EQ firstxv then v = v[0:nx-1, *] ELSE v = v[1: nx, *]
276          IF nyu NE ny THEN $
277             if indicey[0] EQ firstyu then u = u[*, 0:ny-1] ELSE u = u[*, 1: ny]
278          IF nyv NE ny THEN $
279             if indicey[0] EQ firstyv then v = v[*, 0:ny-1] ELSE v = v[*, 1: ny]
280        END
281        szu[1] EQ jpi AND szu[2] EQ jpj AND $
282           szv[1] EQ jpi AND szv[2] EQ jpj:BEGIN
283          u = u[indice2d]
284          v = v[indice2d]
285        END
286        ELSE:return,  -1
287      endcase
288;------------------------------------------------------------
289; curl computation
290;------------------------------------------------------------
291      coefu = e1u[indice2d]*(umask())[indice2d+jpi*jpj*firstzt]
292      landu = where(coefu EQ 0)
293      if landu[0] NE -1 then coefu[temporary(landu)] = !values.f_nan
294      coefv = e2v[indice2d]*(vmask())[indice2d+jpi*jpj*firstzt]
295      landv = where(coefv EQ 0)
296      if landv[0] NE -1 then coefv[temporary(landv)] = !values.f_nan
297      tabf = scale * (fmask())[indice2d+jpi*jpj*firstzt]/(e1f[indice2d]*e2f[indice2d])
298      landf =  where(tabf EQ 0)
299;
300      zu = temporary(u) * temporary(coefu)
301      zv = temporary(v) * temporary(coefv)
302
303      psi = (shift(zv, -1, 0)-zv) + (zu-shift(zu, 0, -1))
304      psi = temporary(tabf) * temporary(psi)
305;------------------------------------------------------------
306; Edging put at !values.f_nan
307;------------------------------------------------------------
308      if  NOT keyword_set(key_periodic) OR nx NE jpi then begin
309        psi[0, *] = !values.f_nan
310        psi[nx-1, *] = !values.f_nan
311      endif
312      psi[*, 0] = !values.f_nan
313      psi[*, ny-1] = !values.f_nan
314;
315      if landf[0] NE -1 then psi[temporary(landf)] = valmask
316      if keyword_set(direc) then psi = moyenne(psi, direc, /nan)
317    END
318;----------------------------------------------------------------------------
319;----------------------------------------------------------------------------
320    ELSE:return, report('U and V input arrays must have 2, 3 or 4 dimensions')
321  ENDCASE
322;------------------------------------------------------------
323  if keyword_set(key_performance) THEN print, 'time curl', systime(1)-time1
324
325  return, psi
326end
Note: See TracBrowser for help on using the repository browser.