source: trunk/SRC/Computation/div.pro @ 371

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