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

Last change on this file since 314 was 314, checked in by smasson, 17 years ago

bugfix + cleaning of Computation routines

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 13.8 KB
RevLine 
[2]1;+
2;
[142]3; @file_comments
[314]4; Calculate the vertical component of the curl of a vectors field
5; located on Arakawa C-grid.
[2]6;
[142]7; @categories
[157]8; Calculation
[226]9;
[142]10; @param UU
[314]11; Matrix representing the zonal coordinates (at U point) of a field of vectors
[268]12; A 2D (xy), 3D (xyz or yt) or a structure readable by <pro>litchamp</pro> and containing
[242]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.
[2]15;
[226]16; @param VV
[314]17; Matrix representing the meridional coordinates (at V point) of a field of vectors
[268]18; A 2D (xy), 3D (xyz or yt) or a structure readable by <pro>litchamp</pro> and containing
[242]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.
[2]21;
[167]22; @keyword DIREC {type=scalar string}
[238]23; Use if you want to call <pro>moyenne</pro> or
24; <pro>grossemoyenne</pro> after the div computation
[167]25; with a mean done in the DIREC direction
26;
[314]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;
[238]33; @returns
[314]34; the vertical component of the curl of the input data (with the same
35; size) located at F point (see restrictions)
[2]36;
[142]37; @uses
[238]38; cm_4cal
39; cm_4data
[314]40; cm_4mesh
[2]41;
[142]42; @restrictions
[2]43;
[226]44; - Works only for Arakawa C-grid.
[167]45; - UU must be on U grid, VV must be on V grid
[242]46; - 4D case is not coded yet
[167]47; - the common variable jpt is used to differ xyz (jpt=1) and xyt (jpt\=1) cases.
[226]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
[231]51;   common indexes. To avoid these re-cuts, use the keyword /memeindice in
52; <pro>domdef</pro>
[167]53; - When computing the divergence, we update, vargrid, varname, varunits and the
54;   grid position parameters (firstxf, lastxf, nxf, firstyf, lastyf, nyf).
[226]55; - points that cannot be computed (domain boundaries, coastline) are set to NaN
[2]56;
[167]57; @examples
[314]58; IDL> @tst_initorca2
[167]59; IDL> plt, curl(dist(jpi,jpj), dist(jpi,jpj))
[2]60;
[226]61; @history
[157]62; Guillaume Roullet (grlod\@ipsl.jussieu.fr)
[163]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
[226]66;
[142]67; @version
68; $Id$
69;
[226]70; @todo
[242]71; code the 4D case
[238]72;
[2]73;-
[231]74;
[314]75FUNCTION curl, uu, vv, DIREC = direc, MILLION = million, _EXTRA = ex
[114]76;
77  compile_opt idl2, strictarrsubs
78;
[167]79@cm_4cal                        ; for jpt
80@cm_4data                       ; for varname, vargrid, vardate, varunit, valmask
[226]81@cm_4mesh
[2]82;
[314]83  time1 = systime(1)          ; for key_performance
[167]84;
85  IF finite(glamu[0])*finite(gphiu[0])*finite(glamv[0])*finite(gphiv[0]) EQ 0 THEN $
[25]86     return, report(['This version of curl is based on Arakawa C-grid.' $
87                     , 'U and V grids must therefore be defined'])
88;
[314]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
[167]97  u = litchamp(uu)
98  v = litchamp(vv)
[2]99
[167]100  szu = size(u)
101  szv = size(v)
[226]102
[167]103  if szu[0] NE szv[0] then return, report('U and V input data must have the same number of dimensions')
[2]104
105;------------------------------------------------------------
[142]106; We find common points between U and V
[2]107;------------------------------------------------------------
[167]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)
[226]114  nx = n_elements(indicex)
[167]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]
[2]118;----------------------------------------------------------------------------
[167]119  vargrid = 'F'
120  varname = 'vorticity'
[314]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.
[167]123  if n_elements(valmask) EQ 0 THEN valmask = 1e20
[314]124  firstxf = indicex[0] & lastxf = indicex[0]+nx-1 & nxf = nx
125  firstyf = indicey[0] & lastyf = indicey[0]+ny-1 & nyf = ny
[2]126;----------------------------------------------------------------------------
[167]127;----------------------------------------------------------------------------
128  case 1 of
129;----------------------------------------------------------------------------
[2]130;xyz
131;----------------------------------------------------------------------------
[226]132    szu[0] EQ 3 AND jpt EQ 1:BEGIN
[2]133;------------------------------------------------------------
[142]134; extraction of U and V on the appropriated domain
[2]135;------------------------------------------------------------
[167]136      case 1 of
137        szu[1] EQ nxu AND szu[2] EQ nyu AND $
[226]138           szv[1] EQ nxv AND szv[2] EQ nyv:BEGIN
[167]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 $
[226]148           szv[1] EQ jpi AND szv[2] EQ jpj:BEGIN
[167]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
[2]154;------------------------------------------------------------
[167]155; curl computation
[2]156;------------------------------------------------------------
[167]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
[226]161
[167]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
[2]166
[314]167      tabf = scale * (fmask())[indicex[0]:indicex[0]+nx-1, indicey[0]:indicey[0]+ny-1, firstzt:lastzt] $
[167]168             / ((e1f[indice2d]*e2f[indice2d])[*]#replicate(1., nzt))
169      landf =  where(tabf EQ 0)
[2]170;
[167]171      zu = temporary(u) * temporary(coefu)
172      zv = temporary(v) * temporary(coefv)
[2]173
[167]174      psi = (shift(zv, -1, 0, 0)-zv) + (zu-shift(zu, 0, -1, 0))
175      psi = temporary(tabf) * temporary(psi)
[2]176;------------------------------------------------------------
[142]177; Edging put at !values.f_nan
[2]178;------------------------------------------------------------
[167]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
[2]185;
[167]186      if landf[0] NE -1 then psi[temporary(landf)] = valmask
187      if keyword_set(direc) then psi = moyenne(psi, direc, /nan)
188    END
[2]189;----------------------------------------------------------------------------
190;----------------------------------------------------------------------------
191;xyt
192;----------------------------------------------------------------------------
193;----------------------------------------------------------------------------
[226]194    szu[0] EQ 3 AND jpt GT 1:BEGIN
[2]195;------------------------------------------------------------
[142]196; extraction of U and V on the appropriated domain
[2]197;------------------------------------------------------------
[167]198      case 1 of
199        szu[1] EQ nxu AND szu[2] EQ nyu AND $
[226]200           szv[1] EQ nxv AND szv[2] EQ nyv:BEGIN
[167]201          if nxu NE nx then $
[226]202             if indicex[0] EQ firstxu then u = u[0:nx-1, *, *] ELSE u = u[1: nx, *, *]
[167]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 $
[226]206             if indicey[0] EQ firstyu then u = u[*, 0:ny-1, *] ELSE u = u[*, 1: ny, *]
[167]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 $
[226]211           szv[1] EQ jpi AND szv[2] EQ jpj:BEGIN
[167]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
[314]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
[2]220;----------------------------------------------------------------------------
[167]221; curl computation
[2]222;----------------------------------------------------------------------------
[167]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)
[2]227;
[167]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)
[2]232;
[314]233      tabf = scale * (fmask())[indice2d+jpi*jpj*firstzt]/(e1f[indice2d]*e2f[indice2d])
[248]234      tabf = reform(temporary(tabf[*])#replicate(1., jpt), nx, ny, jpt, /overwrite)
[167]235      landf = where(tabf EQ 0)
[2]236;
[167]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)
[2]242;------------------------------------------------------------
[142]243; extraction of U and V on the appropriated domain
[2]244;------------------------------------------------------------
[167]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
[2]254;----------------------------------------------------------------------------
255;----------------------------------------------------------------------------
256;xyzt
257;----------------------------------------------------------------------------
258;----------------------------------------------------------------------------
[226]259    szu[0] EQ 4:BEGIN
[167]260      return, report('Case not coded contact saxo team or make a do loop!')
261    END
[2]262;----------------------------------------------------------------------------
263;----------------------------------------------------------------------------
264;xy
265;----------------------------------------------------------------------------
266;----------------------------------------------------------------------------
[226]267    szu[0] EQ 2:BEGIN
[2]268;------------------------------------------------------------
269;------------------------------------------------------------
[167]270      case 1 of
271        szu[1] EQ nxu AND szu[2] EQ nyu AND $
[226]272           szv[1] EQ nxv AND szv[2] EQ nyv:BEGIN
[167]273          if nxu NE nx then $
[226]274             if indicex[0] EQ firstxu then u = u[0:nx-1, *] ELSE u = u[1: nx, *]
[167]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 $
[226]278             if indicey[0] EQ firstyu then u = u[*, 0:ny-1] ELSE u = u[*, 1: ny]
[167]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 $
[226]283           szv[1] EQ jpi AND szv[2] EQ jpj:BEGIN
[167]284          u = u[indice2d]
285          v = v[indice2d]
286        END
287        ELSE:return,  -1
288      endcase
[2]289;------------------------------------------------------------
[167]290; curl computation
[2]291;------------------------------------------------------------
[167]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
[314]298      tabf = scale * (fmask())[indice2d+jpi*jpj*firstzt]/(e1f[indice2d]*e2f[indice2d])
[167]299      landf =  where(tabf EQ 0)
[2]300;
[167]301      zu = temporary(u) * temporary(coefu)
302      zv = temporary(v) * temporary(coefv)
[2]303
[167]304      psi = (shift(zv, -1, 0)-zv) + (zu-shift(zu, 0, -1))
305      psi = temporary(tabf) * temporary(psi)
[2]306;------------------------------------------------------------
[142]307; Edging put at !values.f_nan
[2]308;------------------------------------------------------------
[167]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
[2]315;
[167]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
[2]323;------------------------------------------------------------
[314]324  if keyword_set(key_performance) THEN print, 'time curl', systime(1)-time1
[2]325
[167]326  return, psi
[2]327end
Note: See TracBrowser for help on using the repository browser.