source: trunk/SRC/Computation/curl.pro @ 378

Last change on this file since 378 was 371, checked in by pinsard, 16 years ago

improvements of headers (alignments of IDL prompt in examples)

  • 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; <pro>cm_4cal</pro>
39; <pro>cm_4data</pro>
40; <pro>cm_4mesh</pro>
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;
59;   IDL> @tst_initorca2
60;   IDL> plt, curl(dist(jpi,jpj), dist(jpi,jpj))
61;
62; @history
63; Guillaume Roullet (grlod\@ipsl.jussieu.fr)
64; Sebastien Masson (smasson\@lodyc.jussieu.fr)
65; adaptation to work with a reduce domain
66; 21/5/1999: missing values at !values.f_nan
67;
68; @version
69; $Id$
70;
71; @todo
72; code the 4D case
73;
74;-
75FUNCTION curl, uu, vv, DIREC=direc, MILLION=million, _EXTRA=ex
76;
77  compile_opt idl2, strictarrsubs
78;
79@cm_4cal                        ; for jpt
80@cm_4data                       ; for varname, vargrid, vardate, varunit, valmask
81@cm_4mesh
82;
83  time1 = systime(1)          ; for key_performance
84;
85  IF finite(glamu[0])*finite(gphiu[0])*finite(glamv[0])*finite(gphiv[0]) EQ 0 THEN $
86     return, report(['This version of curl is based on Arakawa C-grid.' $
87                     , 'U and V grids must therefore be defined'])
88;
89  gr = litchamp(uu, /grid)
90  IF gr NE '' THEN BEGIN
91    IF gr NE 'U' THEN return, report('the first parameter is not located on U grid, but on '+ strtrim(gr, 2) +'grid')
92  ENDIF
93  gr = litchamp(vv, /grid)
94  IF gr NE '' THEN BEGIN
95    IF gr NE 'V' THEN return, report('the second parameter is not located on V grid, but on '+ strtrim(gr, 2) +'grid')
96  ENDIF
97  u = litchamp(uu)
98  v = litchamp(vv)
99
100  szu = size(u)
101  szv = size(v)
102
103  if szu[0] NE szv[0] then return, report('U and V input data must have the same number of dimensions')
104
105;------------------------------------------------------------
106; We find common points between U and V
107;------------------------------------------------------------
108  indicexu = (lindgen(jpi))[firstxu:firstxu+nxu-1]
109  indicexv = (lindgen(jpi))[firstxv:firstxv+nxv-1]
110  indicex = inter(indicexu, indicexv)
111  indiceyu = (lindgen(jpj))[firstyu:firstyu+nyu-1]
112  indiceyv = (lindgen(jpj))[firstyv:firstyv+nyv-1]
113  indicey = inter(indiceyu, indiceyv)
114  nx = n_elements(indicex)
115  ny = n_elements(indicey)
116  indice2d = lindgen(jpi, jpj)
117  indice2d = indice2d[indicex[0]:indicex[0]+nx-1, indicey[0]:indicey[0]+ny-1]
118;----------------------------------------------------------------------------
119  vargrid = 'F'
120  varname = 'vorticity'
121  IF keyword_set(million) THEN varunits = '1.e6*'+varunit+'/m' ELSE varunits = varunit+'/m'
122  IF keyword_set(million) THEN scale = 1.e6 ELSE scale = 1.
123  if n_elements(valmask) EQ 0 THEN valmask = 1e20
124  firstxf = indicex[0] & lastxf = indicex[0]+nx-1 & nxf = nx
125  firstyf = indicey[0] & lastyf = indicey[0]+ny-1 & nyf = ny
126;----------------------------------------------------------------------------
127;----------------------------------------------------------------------------
128  case 1 of
129;----------------------------------------------------------------------------
130;xyz
131;----------------------------------------------------------------------------
132    szu[0] EQ 3 AND jpt EQ 1:BEGIN
133;------------------------------------------------------------
134; extraction of U and V on the appropriated domain
135;------------------------------------------------------------
136      case 1 of
137        szu[1] EQ nxu AND szu[2] EQ nyu AND $
138           szv[1] EQ nxv AND szv[2] EQ nyv:BEGIN
139          case 1 of
140            nxu NE nx:if indicex[0] EQ firstxu then u = u[0:nx-1, *, *] ELSE u = u[1: nx, *, *]
141            nxv NE nx:if indicex[0] EQ firstxv then v = v[0:nx-1, *, *] ELSE v = v[1: nx, *, *]
142            nyu NE ny:if indicey[0] EQ firstyu then u = u[*, 0:ny-1, *] ELSE u = u[*, 1: ny, *]
143            nyv NE ny:if indicey[0] EQ firstyv then v = v[*, 0:ny-1, *] ELSE v = v[*, 1: ny, *]
144            ELSE :
145          endcase
146        END
147        szu[1] EQ jpi AND szu[2] EQ jpj AND $
148           szv[1] EQ jpi AND szv[2] EQ jpj:BEGIN
149          u = u[indicex[0]:indicex[0]+nx-1, indicey[0]:indicey[0]+ny-1, *]
150          v = v[indicex[0]:indicex[0]+nx-1, indicey[0]:indicey[0]+ny-1, *]
151        END
152        ELSE:return,  -1
153      endcase
154;------------------------------------------------------------
155; curl computation
156;------------------------------------------------------------
157      coefu = ((e1u[indice2d])[*]#replicate(1., nzt)) $
158              * (umask())[indicex[0]:indicex[0]+nx-1, indicey[0]:indicey[0]+ny-1, firstzt:lastzt]
159      landu = where(coefu EQ 0)
160      if landu[0] NE -1 then coefu[temporary(landu)] = !values.f_nan
161
162      coefv = ((e2v[indice2d])[*]#replicate(1., nzt)) $
163              *(vmask())[indicex[0]:indicex[0]+nx-1, indicey[0]:indicey[0]+ny-1, firstzt:lastzt]
164      landv = where(coefv EQ 0)
165      if landv[0] NE -1 then coefv[temporary(landv)] = !values.f_nan
166
167      tabf = scale * (fmask())[indicex[0]:indicex[0]+nx-1, indicey[0]:indicey[0]+ny-1, firstzt:lastzt] $
168             / ((e1f[indice2d]*e2f[indice2d])[*]#replicate(1., nzt))
169      landf =  where(tabf EQ 0)
170;
171      zu = temporary(u) * temporary(coefu)
172      zv = temporary(v) * temporary(coefv)
173
174      psi = (shift(zv, -1, 0, 0)-zv) + (zu-shift(zu, 0, -1, 0))
175      psi = temporary(tabf) * temporary(psi)
176;------------------------------------------------------------
177; Edging put at !values.f_nan
178;------------------------------------------------------------
179      if NOT keyword_set(key_periodic)  OR nx NE jpi then begin
180        psi[0, *, *] = !values.f_nan
181        psi[nx-1, *, *] = !values.f_nan
182      endif
183      psi[*, 0, *] = !values.f_nan
184      psi[*, ny-1, *] = !values.f_nan
185;
186      if landf[0] NE -1 then psi[temporary(landf)] = valmask
187      if keyword_set(direc) then psi = moyenne(psi, direc, /nan)
188    END
189;----------------------------------------------------------------------------
190;----------------------------------------------------------------------------
191;xyt
192;----------------------------------------------------------------------------
193;----------------------------------------------------------------------------
194    szu[0] EQ 3 AND jpt GT 1:BEGIN
195;------------------------------------------------------------
196; extraction of U and V on the appropriated domain
197;------------------------------------------------------------
198      case 1 of
199        szu[1] EQ nxu AND szu[2] EQ nyu AND $
200           szv[1] EQ nxv AND szv[2] EQ nyv:BEGIN
201          if nxu NE nx then $
202             if indicex[0] EQ firstxu then u = u[0:nx-1, *, *] ELSE u = u[1: nx, *, *]
203          IF nxv NE nx THEN $
204             if indicex[0] EQ firstxv then v = v[0:nx-1, *, *] ELSE v = v[1: nx, *, *]
205          IF nyu NE ny THEN $
206             if indicey[0] EQ firstyu then u = u[*, 0:ny-1, *] ELSE u = u[*, 1: ny, *]
207          IF nyv NE ny THEN $
208             if indicey[0] EQ firstyv then v = v[*, 0:ny-1, *] ELSE v = v[*, 1: ny, *]
209        END
210        szu[1] EQ jpi AND szu[2] EQ jpj AND $
211           szv[1] EQ jpi AND szv[2] EQ jpj:BEGIN
212          u = u[indicex[0]:indicex[0]+nx-1, indicey[0]:indicey[0]+ny-1, *]
213          v = v[indicex[0]:indicex[0]+nx-1, indicey[0]:indicey[0]+ny-1, *]
214        END
215        ELSE:return $
216           , report(['We cannot find re-cut on common indexes (see restriction un the header.).' $
217                     , 'To avoid this problem, read the full domain' $
218                     , 'or use the keyword /memeindice in domdef when defining the zoom area'])
219      ENDCASE
220;----------------------------------------------------------------------------
221; curl computation
222;----------------------------------------------------------------------------
223      coefu = e1u[indice2d]*(umask())[indice2d+jpi*jpj*firstzt]
224      landu = where(coefu EQ 0)
225      if landu[0] NE -1 then coefu[temporary(landu)] = !values.f_nan
226      coefu = temporary(coefu[*])#replicate(1., jpt)
227;
228      coefv = e2v[indice2d]*(vmask())[indice2d+jpi*jpj*firstzt]
229      landv = where(coefv EQ 0)
230      if landv[0] NE -1 then coefv[temporary(landv)] = !values.f_nan
231      coefv = temporary(coefv[*])#replicate(1., jpt)
232;
233      tabf = scale * (fmask())[indice2d+jpi*jpj*firstzt]/(e1f[indice2d]*e2f[indice2d])
234      tabf = reform(temporary(tabf[*])#replicate(1., jpt), nx, ny, jpt, /overwrite)
235      landf = where(tabf EQ 0)
236;
237      zu = temporary(u) * temporary(coefu)
238      zv = temporary(v) * temporary(coefv)
239;
240      psi = (shift(zv, -1, 0, 0)-zv) + (zu-shift(zu, 0, -1, 0))
241      psi = temporary(tabf) * temporary(psi)
242;------------------------------------------------------------
243; extraction of U and V on the appropriated domain
244;------------------------------------------------------------
245      if NOT keyword_set(key_periodic) OR nx NE jpi then begin
246        psi[0, *, *] = !values.f_nan
247        psi[nx-1, *, *] = !values.f_nan
248      endif
249      psi[*, 0, *] = !values.f_nan
250      psi[*, ny-1, *] = !values.f_nan
251      if landf[0] NE -1 then psi[temporary(landf)] = valmask
252      if keyword_set(direc) then psi = grossemoyenne(psi, direc, /nan)
253    END
254;----------------------------------------------------------------------------
255;----------------------------------------------------------------------------
256;xyzt
257;----------------------------------------------------------------------------
258;----------------------------------------------------------------------------
259    szu[0] EQ 4:BEGIN
260      return, report('Case not coded contact saxo team or make a do loop!')
261    END
262;----------------------------------------------------------------------------
263;----------------------------------------------------------------------------
264;xy
265;----------------------------------------------------------------------------
266;----------------------------------------------------------------------------
267    szu[0] EQ 2:BEGIN
268;------------------------------------------------------------
269;------------------------------------------------------------
270      case 1 of
271        szu[1] EQ nxu AND szu[2] EQ nyu AND $
272           szv[1] EQ nxv AND szv[2] EQ nyv:BEGIN
273          if nxu NE nx then $
274             if indicex[0] EQ firstxu then u = u[0:nx-1, *] ELSE u = u[1: nx, *]
275          IF nxv NE nx THEN $
276             if indicex[0] EQ firstxv then v = v[0:nx-1, *] ELSE v = v[1: nx, *]
277          IF nyu NE ny THEN $
278             if indicey[0] EQ firstyu then u = u[*, 0:ny-1] ELSE u = u[*, 1: ny]
279          IF nyv NE ny THEN $
280             if indicey[0] EQ firstyv then v = v[*, 0:ny-1] ELSE v = v[*, 1: ny]
281        END
282        szu[1] EQ jpi AND szu[2] EQ jpj AND $
283           szv[1] EQ jpi AND szv[2] EQ jpj:BEGIN
284          u = u[indice2d]
285          v = v[indice2d]
286        END
287        ELSE:return,  -1
288      endcase
289;------------------------------------------------------------
290; curl computation
291;------------------------------------------------------------
292      coefu = e1u[indice2d]*(umask())[indice2d+jpi*jpj*firstzt]
293      landu = where(coefu EQ 0)
294      if landu[0] NE -1 then coefu[temporary(landu)] = !values.f_nan
295      coefv = e2v[indice2d]*(vmask())[indice2d+jpi*jpj*firstzt]
296      landv = where(coefv EQ 0)
297      if landv[0] NE -1 then coefv[temporary(landv)] = !values.f_nan
298      tabf = scale * (fmask())[indice2d+jpi*jpj*firstzt]/(e1f[indice2d]*e2f[indice2d])
299      landf =  where(tabf EQ 0)
300;
301      zu = temporary(u) * temporary(coefu)
302      zv = temporary(v) * temporary(coefv)
303
304      psi = (shift(zv, -1, 0)-zv) + (zu-shift(zu, 0, -1))
305      psi = temporary(tabf) * temporary(psi)
306;------------------------------------------------------------
307; Edging put at !values.f_nan
308;------------------------------------------------------------
309      if  NOT keyword_set(key_periodic) OR nx NE jpi then begin
310        psi[0, *] = !values.f_nan
311        psi[nx-1, *] = !values.f_nan
312      endif
313      psi[*, 0] = !values.f_nan
314      psi[*, ny-1] = !values.f_nan
315;
316      if landf[0] NE -1 then psi[temporary(landf)] = valmask
317      if keyword_set(direc) then psi = moyenne(psi, direc, /nan)
318    END
319;----------------------------------------------------------------------------
320;----------------------------------------------------------------------------
321    ELSE:return, report('U and V input arrays must have 2, 3 or 4 dimensions')
322  ENDCASE
323;------------------------------------------------------------
324  if keyword_set(key_performance) THEN print, 'time curl', systime(1)-time1
325
326  return, psi
327end
Note: See TracBrowser for help on using the repository browser.