source: trunk/SRC/Computation/div.pro

Last change on this file was 495, checked in by pinsard, 10 years ago

fix thanks to coding rules; typo; dupe empty lines; trailing blanks

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 13.5 KB
Line 
1;+
2;
3; @file_comments
4; compute the horizontal divergence of a vectors field located on Arakawa C-grid.
5;
6; @categories
7; Calculation
8;
9; @param UU
10; Matrix representing the zonal coordinates (at U point) of a field of vectors
11; A 2D (xy), 3D (xyz or yt) or a structure readable by <pro>litchamp</pro> and containing
12; a 2D (xy), 3D (xyz or yt) array (4D case is not coded yet).
13; note that the dimension of the array must suit the domain dimension.
14;
15; @param VV
16; Matrix representing the meridional coordinates (at V point) of a field of vectors
17; A 2D (xy), 3D (xyz or yt) or a structure readable by <pro>litchamp</pro> and containing
18; a 2D (xy), 3D (xyz or yt) array (4D case is not coded yet).
19; note that the dimension of the array must suit the domain dimension.
20;
21; @keyword DIREC {type=scalar string}
22; Use if you want to call <pro>moyenne</pro> or
23; <pro>grossemoyenne</pro> after the div computation
24; (stupid ?) with a mean done in the DIREC direction
25;
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;
32; @returns
33; the divergence of the input data (with the same size) located at T
34;point (see restrictions).
35;
36; @uses
37; <pro>cm_4cal</pro>
38; <pro>cm_4data</pro>
39; <pro>cm_4mesh</pro>
40;
41; @restrictions
42;
43; - Works only for Arakawa C-grid.
44; - UU must be on U grid, VV must be on V grid
45; - 4D case is not coded yet
46; - the common variable jpt is used to differ xyz (jpt=1) and xyt (jpt\=1) cases.
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
50;   common indexes. To avoid these re-cuts, use the keyword /memeindice in
51; <pro>domdef</pro>
52; - When computing the divergence, we update, vargrid, varname, varunits and the
53;   grid position parameters (firstxt, lastxt, nxt, firstyt, lastyt, nyt).
54; - points that cannot be computed (domain boundaries, coastline) are set to NaN
55;
56; @examples
57;
58;   IDL> \@tst_initorca2
59;   IDL> plt, div(dist(jpi,jpj), dist(jpi,jpj))
60;
61; @history
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
65;
66; @version
67; $Id$
68;
69; @todo
70; code the 4D case
71;
72;-
73FUNCTION div, uu, vv, DIREC=direc, MILLION=million, _EXTRA=ex
74;
75  compile_opt idl2, strictarrsubs
76;
77@cm_4cal                        ; for jpt
78@cm_4data                       ; for varname, vargrid, vardate, varunit, valmask
79@cm_4mesh
80;
81  time1 = systime(1)          ; for key_performance
82;
83  IF finite(glamu[0])*finite(gphiu[0])*finite(glamv[0])*finite(gphiv[0]) EQ 0 THEN $
84     return, report(['This version of div is based on Arakawa C-grid.' $
85                     , 'U and V grids must therefore be defined'])
86;
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
95  u = litchamp(uu)
96  v = litchamp(vv)
97;
98  szu = size(u)
99  szv = size(v)
100
101  if szu[0] NE szv[0] then return, report('U and V input data must have the same number of dimensions')
102
103;------------------------------------------------------------
104; We find common points between U and V
105;------------------------------------------------------------
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)
112  nx = n_elements(indicex)
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]
116;----------------------------------------------------------------------------
117  vargrid = 'T'
118  varname = 'div'
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.
121  if n_elements(valmask) EQ 0 THEN valmask = 1.e20
122  firstxt = indicex[0] & lastxt = indicex[0]+nx-1 & nxt = nx
123  firstyt = indicey[0] & lastyt = indicey[0]+ny-1 & nyt = ny
124;----------------------------------------------------------------------------
125;----------------------------------------------------------------------------
126  case 1 of
127;----------------------------------------------------------------------------
128;xyz
129;----------------------------------------------------------------------------
130    szu[0] EQ 3 AND jpt EQ 1:BEGIN
131;------------------------------------------------------------
132; extraction of U and V on the appropriated domain
133;------------------------------------------------------------
134      case 1 of
135        szu[1] EQ nxu AND szu[2] EQ nyu AND $
136           szv[1] EQ nxv AND szv[2] EQ nyv:BEGIN
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 $
146           szv[1] EQ jpi AND szv[2] EQ jpj:BEGIN
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
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
155;------------------------------------------------------------
156; divergence computation
157;------------------------------------------------------------
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)
162;
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)
167;
168      zdiv = (scale / (e1t[indice2d]*e2t[indice2d]))[*]#replicate(1., nzt)
169      zdiv = ( zu - shift(zu, 1, 0, 0) + zv - shift(zv, 0, 1, 0) ) * temporary(zdiv)
170;------------------------------------------------------------
171; Edging put at !values.f_nan
172;------------------------------------------------------------
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
179;
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
184;----------------------------------------------------------------------------
185;----------------------------------------------------------------------------
186;xyt
187;----------------------------------------------------------------------------
188;----------------------------------------------------------------------------
189    szu[0] EQ 3 AND jpt GT 1:BEGIN
190;------------------------------------------------------------
191; extraction of U and V on the appropriated domain
192;------------------------------------------------------------
193      case 1 of
194        szu[1] EQ nxu AND szu[2] EQ nyu AND $
195           szv[1] EQ nxv AND szv[2] EQ nyv:BEGIN
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 $
205           szv[1] EQ jpi AND szv[2] EQ jpj:BEGIN
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
211;------------------------------------------------------------
212; divergence computation
213;------------------------------------------------------------
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)
219;
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)
225;
226      zdiv = (scale / (e1t[indice2d]*e2t[indice2d]))[*]#replicate(1., jpt)
227      zdiv = ( zu - shift(zu, 1, 0, 0) + zv - shift(zv, 0, 1, 0) ) * temporary(zdiv)
228;------------------------------------------------------------
229; Edging put at !values.f_nan
230;------------------------------------------------------------
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
237;
238      land = where(tmask[indice2d+jpi*jpj*firstzt] EQ 0, cnt)
239      if land[0] NE -1 then BEGIN
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
245;----------------------------------------------------------------------------
246;----------------------------------------------------------------------------
247;xyzt
248;----------------------------------------------------------------------------
249;----------------------------------------------------------------------------
250    szu[0] EQ 4:BEGIN
251      return, report('Case not coded contact saxo team or make a do loop!')
252    END
253;----------------------------------------------------------------------------
254;----------------------------------------------------------------------------
255;xy
256;----------------------------------------------------------------------------
257;----------------------------------------------------------------------------
258    szu[0] EQ 2:BEGIN
259;------------------------------------------------------------
260; extraction of U and V on the appropriated domain
261;------------------------------------------------------------
262      case 1 of
263        szu[1] EQ nxu AND szu[2] EQ nyu AND $
264           szv[1] EQ nxv AND szv[2] EQ nyv:BEGIN
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 $
274           szv[1] EQ jpi AND szv[2] EQ jpj:BEGIN
275          u = u[indice2d]
276          v = v[indice2d]
277        END
278        ELSE:return, -1
279      endcase
280;------------------------------------------------------------
281; divergence computation
282;------------------------------------------------------------
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
293      zdiv = scale / (e1t[indice2d]*e2t[indice2d])
294      zdiv = ( zu - shift(zu, 1, 0) + zv - shift(zv, 0, 1) ) * temporary(zdiv)
295;------------------------------------------------------------
296; Edging put at !values.f_nan
297;------------------------------------------------------------
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
304;
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')
312  ENDCASE
313;------------------------------------------------------------
314  if keyword_set(key_performance) THEN print, 'time div', systime(1)-time1
315
316  return, zdiv
317end
Note: See TracBrowser for help on using the repository browser.