source: trunk/SRC/ToBeReviewed/LECTURE/read_ncdf.pro @ 163

Last change on this file since 163 was 163, checked in by navarro, 18 years ago

header improvements : type of parameters and keywords, default values, spell checking + idldoc assistant (IDL online_help)

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 20.2 KB
Line 
1;+
2; @file_comments
3; Reading function for the file net_cdf.
4; This program is less universal than ncdf_lec (it appeal to declared
5; variables in common.pro) but it is very easier to be used. It considerate
6; the declaration of the different zooms which have been defined
7; (ixminmesh...premierx...), the declaration of the variable key_shift...
8; To put it in a nutshell, the result of read_ncdf can be directly used in plt...
9; This is also this program which is used by default in our reading widgets. 
10;
11; @categories
12; Reading
13;
14; @param NAME {in}{required}{type=string}
15; It define the field to be read.
16;
17; @param BEGINNING {in}{required}
18; Relative with the time axis.
19; These can be
20;  - 2 date of the  type yyyymmdd and in this case, we select dates
21;  which are included between these two dates.
22;  - 2 indexes which define between which and which time step we have
23;  to extract the temporal dimension.
24;
25; @param ENDING  {in}{required}
26; Relative with the time axis.
27; See BEGINNING.
28;
29; @param COMPATIBILITY {in}{required}
30; Useless
31
32; @keyword BOXZOOM
33; Contain the boxzoom on which we have to do the reading
34;
35; @keyword FILENAME {type=string}
36; It contains he file's name.
37;
38; @keyword INIT
39; To call automatically initncdf, filename and thus
40; redefine all the grid parameters
41;
42; @keyword GRID
43; ='[UTVWF]' to specify the type of grid. Default is (1)
44; based on the name of the file if the file ends by
45; GRID[._][TUVFW].NC (not case sensible) or (2) T if case (1)
46; is not found.
47;
48; @keyword TIMESTEP
49; We activate to specify that BEGINNING and ENDING refer to indexes
50; of the time axis and not to dates
51;
52; @keyword TOUT
53; We activate it if we want to read the file on the whole domain without
54; considerate the sub-domain defined by the boxzoom or
55; lon1,lon2,lat1,lat2,vert1,vert2.
56;
57; @keyword NOSTRUCT
58; We activate it if we do not want that read_ncdf send back a structure
59; but only the array referring to the field.
60;
61; @keyword TIMEVAR {type=string}
62; It define the name of the variable that
63; contains the time axis. This keyword can be useful if there
64; is no unlimited dimension or if the time axis selected by default
65; (the first 1D array with unlimited dimension) is not the good one.
66;
67; @keyword _EXTRA
68; Used to pass your keywords
69;
70; @returns
71; Structure readable by litchamp.pro or an array if NOSTRUCT is activated.
72;
73; @uses
74; common.pro
75;
76; @restrictions
77; The field must have a temporal dimension.
78;
79; @history
80; Sebastien Masson (smasson\@lodyc.jussieu.fr)
81;                      15/10/1999
82;
83; @version
84; $Id$
85;-
86;---------------------------------------------------------
87;---------------------------------------------------------
88;---------------------------------------------------------
89
90FUNCTION read_ncdf, name, beginning, ending, compatibility, BOXZOOM = boxzoom, FILENAME = filename $
91                    , PARENTIN = parentin, TIMESTEP = timestep, TIMEVAR = timevar $
92                    , TOUT = tout, NOSTRUCT = nostruct, CONT_NOFILL = CONT_NOFILL, INIT = init $
93                    , GRID = grid, FBASE2TBASE = fbase2tbase, _EXTRA = ex
94;---------------------------------------------------------
95;
96  compile_opt idl2, strictarrsubs
97;
98@cm_4mesh
99@cm_4data
100@cm_4cal
101  IF NOT keyword_set(key_forgetold) THEN BEGIN
102@updatenew
103@updatekwd
104  ENDIF
105;------------------------------------------------------------
106; we find the filename.
107;------------------------------------------------------------
108;  print,filename
109; is parent a valid widget ?
110  if keyword_set(parentin) then BEGIN
111    parent = long(parentin)
112    parent = parent*widget_info(parent, /managed)
113  ENDIF
114  filename = isafile(filename = filename, IODIRECTORY = iodir, _EXTRA = ex)
115;------------------------------------------------------------
116; Opening of the name file
117;------------------------------------------------------------
118  if size(filename, /type) NE 7 then $
119    return, report('read_ncdf cancelled')
120  IF !version.OS_FAMILY EQ 'unix' THEN spawn, '\file '+filename+' > /dev/null'
121  cdfid = ncdf_open(filename)
122  contient = ncdf_inquire(cdfid)
123;------------------------------------------------------------
124; we check if the variable name exists in the file.
125;------------------------------------------------------------
126  if ncdf_varid(cdfid, name) EQ -1 then BEGIN
127    ncdf_close, cdfid
128    return, report('variable '+name+' !C not found in the file '+filename)
129  ENDIF
130  varcontient = ncdf_varinq(cdfid, name)
131;------------------------------------------------------------
132; shall we redefine the grid parameters
133;------------------------------------------------------------
134  if keyword_set(init) THEN initncdf, filename, _extra = ex
135;------------------------------------------------------------
136; check the time axis and the debut and ending dates
137;------------------------------------------------------------
138  if n_elements(beginning) EQ 0 then begin
139    beginning = 0
140    timestep = 1
141  endif
142  if keyword_set(timestep) then begin
143    firsttps = beginning[0]
144    if n_elements(ending) NE 0 then lasttps = ending[0] ELSE lasttps = firsttps
145    jpt = lasttps-firsttps+1
146    time = julday(1, 1, 1) + lindgen(jpt)
147  ENDIF ELSE BEGIN
148    if keyword_set(parent) then BEGIN
149      widget_control, parent, get_uvalue = top_uvalue
150      filelist = extractatt(top_uvalue, 'filelist')
151      IF filelist[0] EQ 'many !' THEN filelist = filename
152      currentfile = (where(filelist EQ filename))[0]
153      time = (*(extractatt(top_uvalue, 'fileparameters'))[currentfile]).time_counter
154      date1 = date2jul(beginning[0])
155      if n_elements(ending) NE 0 then date2 = date2jul(ending[0]) ELSE date2 = date1
156      firsttps = where(time EQ date1) & firsttps = firsttps[0]
157      lasttps = where(time EQ date2) & lasttps = lasttps[0]
158    ENDIF ELSE BEGIN
159      IF keyword_set(timevar) THEN BEGIN
160        timeid = ncdf_varid(cdfid, timevar)
161        IF timeid EQ -1 THEN BEGIN
162          ncdf_close, cdfid
163          return, report('the file '+filename+' as no variable ' + timevar $
164                         + '. !C Use the TIMESTEP keyword')
165        endif
166        timecontient = ncdf_varinq(cdfid, timeid)
167        contient.recdim = timecontient.dim[0]
168      ENDIF ELSE BEGIN
169; we find the infinite dimension
170        timedim = contient.recdim
171        if timedim EQ -1 then BEGIN
172          ncdf_close, cdfid
173          return, report('the file '+filename+' as no infinite dimension. !C Use TIMESTEP or TIMEVAR keyword')
174        endif
175; we find the FIRST time axis     
176        timeid = 0
177        repeat BEGIN       ; As long as we have not find a variable having only one dimension: the infinite one
178          timecontient = ncdf_varinq(cdfid, timeid) ; that the variable contain.
179          timeid = timeid+1
180        endrep until (n_elements(timecontient.dim) EQ 1 $
181                      AND timecontient.dim[0] EQ contient.recdim) $
182          OR timeid EQ contient.nvars+1
183;
184        if timeid EQ contient.nvars+1 then BEGIN
185          ncdf_close, cdfid
186          return, report('the file '+filename+' as no time axis variable. !C Use the TIMESTEP keyword')
187        endif
188        timeid = timeid-1
189      ENDELSE
190; we must found the time origin of the julian calendar used in the
191; time axis.
192; does the attribut units an dcalendar exist for the variable time axis?
193      if timecontient.natts EQ 0 then BEGIN
194        ncdf_close, cdfid
195        return, report('the variable '+timecontient.name+' has no attribut.!C Use the TIMESTEP keyword or add the attribut ''units'' to the variable')
196      endif
197      attnames = strarr(timecontient.natts)
198      for attiq = 0, timecontient.natts-1 do attnames[attiq] = ncdf_attname(cdfid, timeid, attiq)
199      if (where(attnames EQ 'units'))[0] EQ -1 then BEGIN
200        ncdf_close, cdfid
201        return, report('Attribut ''units'' not found for the variable '+timecontient.name+' !C Use the TIMESTEP keyword')
202      ENDIF
203;
204; now we try to find the attribut called calendar...
205; the attribute "calendar" exists?
206; If no, we suppose that the calendar is gregorian calendar
207;
208      if (where(attnames EQ 'calendar'))[0] NE -1 then BEGIN
209        ncdf_attget, cdfid, timeid, 'calendar', value
210        value = string(value)
211        CASE value OF
212          'noleap':key_caltype = 'noleap'
213          '360d':key_caltype = '360d'
214          'greg':IF n_elements(key_caltype) EQ 0 THEN key_caltype = 'greg'
215          ELSE:BEGIN
216;            notused = report('Unknown calendar: '+value+', we use greg calendar.')
217            key_caltype = 'greg'
218          END
219        ENDCASE
220      ENDIF ELSE BEGIN
221;        notused = report('Unknown calendar, we use '+key_caltype+' calendar.')
222        IF n_elements(key_caltype) EQ 0 THEN key_caltype = 'greg'
223      ENDELSE
224;
225; now we take acre of units attribut
226      ncdf_attget, cdfid, timeid, 'units', value
227;
228; time_counter:units = "seconds since 0001-01-01 00:00:00" ;
229; time_counter:units = "hours since 0001-01-01 00:00:00" ;
230; time_counter:units = "days since 1979-01-01 00:00:00" ;
231; time_counter:units = "months since 1979-01-01 00:00:00" ;
232; time_counter:units = "years since 1979-01-01 00:00:00" ;
233;
234; we decript the "units" attribut to find the time origin
235      value = strtrim(strcompress(string(value)), 2)
236      mots = str_sep(value, ' ')
237      unite = mots[0]
238      depart = str_sep(mots[2], '-')
239      ncdf_varget, cdfid, timeid, time
240      time = double(time)
241      unite = strlowcase(unite)
242      IF strpos(unite, 's', strlen(unite)-1) NE -1 THEN unite = strmid(unite, 0, strlen(unite)-1)
243      IF strpos(unite, 'julian_') NE -1 THEN unite = strmid(unite, 7)
244      case unite of
245        'second':time = julday(depart[1], depart[2], depart[0])+time/86400.d
246        'hour':time = julday(depart[1], depart[2], depart[0])+time/24.d
247        'day':time = julday(depart[1], depart[2], depart[0])+time
248        'month':BEGIN
249          if total(fix(time) NE time) NE 0 then $ ; we switch to days with 30d/m
250            time = julday(depart[1], depart[2], depart[0])+round(time*30) $
251            ELSE for t = 0, n_elements(time)-1 DO $
252            time[t] = julday(depart[1]+time[t], depart[2], depart[0])
253        END
254        'year':BEGIN
255          if total(fix(time) NE time) NE 0 then $ ; we switch to days with 365d/y
256            time = julday(depart[1], depart[2], depart[0])+round(time*365) $
257            ELSE for t = 0, n_elements(time)-1 do $
258            time[t] = julday(depart[1], depart[2], depart[0]+time[t])
259        END
260        ELSE:BEGIN
261          ncdf_close, cdfid
262          return, report('The "units" attribu of the time axis must be something like: !C "seconds since 0001-01-01 ..." !C "days since 1979-01-01 ..." !C "months since 1979-01-01 ..." !C "years since 1979-01-01 ..."')
263        end
264      ENDCASE
265      date1 = date2jul(beginning[0])
266      if n_elements(ending) NE 0 then date2 = date2jul(ending[0]) ELSE date2 = date1
267      time = double(time)
268      firsttps = where(time GE date1) & firsttps = firsttps[0]
269      if firsttps EQ -1 THEN BEGIN
270        ncdf_close, cdfid
271        return, report('date 1: '+strtrim(jul2date(date1), 1)+' is not found in the time axis.')
272      ENDIF
273      lasttps = where(time LE date2)
274      if lasttps[0] EQ -1 THEN BEGIN
275        ncdf_close, cdfid
276        return, report('the time axis as no date before date 2: '+strtrim(jul2date(date2), 1))
277      endif
278      lasttps = lasttps[n_elements(lasttps)-1]
279      if lasttps LT firsttps then BEGIN
280        ncdf_close, cdfid
281        return, report('the time axis as no dates between date1 and  date 2: '+strtrim(jul2date(date1), 1)+' '+strtrim(jul2date(date2), 1))
282      endif
283    ENDELSE
284    time = time[firsttps:lasttps]
285    jpt = lasttps-firsttps+1
286  ENDELSE
287;------------------------------------------------------------
288; Name of the grid on which the field refer to.
289;------------------------------------------------------------
290  IF keyword_set(grid) THEN vargrid = strupcase(grid) ELSE BEGIN
291    vargrid = 'T'               ; default definition
292    IF finite(glamu[0]) EQ 1 THEN BEGIN
293      pattern = ['GRID.', 'GRID_', 'GRID', 'UPID_', '30ID_']
294      gdtype = ['T', 'U', 'V', 'W', 'F']
295      fnametest = strupcase(filename)
296      FOR i = 0, n_elements(pattern)-1 DO BEGIN
297        FOR j = 0, n_elements(gdtype)-1 DO BEGIN
298          substr = pattern[i]+gdtype[j]
299          pos = strpos(fnametest, substr)
300          IF pos NE -1 THEN $
301             vargrid = strmid(fnametest, pos+strlen(substr)-1, 1)
302        ENDFOR
303      ENDFOR
304    ENDIF
305  ENDELSE
306;---------------------------------------------------------------
307; call the init function ?
308;---------------------------------------------------------------
309
310;---------------------------------------------------------------
311; redefinition of the  domain
312;---------------------------------------------------------------
313  if keyword_set(tout) then begin
314    nx = jpi
315    ny = jpj
316    nz = jpk
317    firstx = 0
318    firsty = 0
319    firstz = 0
320    lastx = jpi-1
321    lasty = jpj-1
322    lastz = jpk-1
323    case strupcase(vargrid) of
324      'T':mask = tmask
325      'U':mask = umask()
326      'V':mask = vmask()
327      'W':mask = tmask
328      'F':mask = fmask()
329    endcase
330  ENDIF ELSE BEGIN
331    if keyword_set(boxzoom) then BEGIN
332      Case 1 Of
333        N_Elements(Boxzoom) Eq 1:bte = [lon1, lon2, lat1, lat2, 0., boxzoom[0]]
334        N_Elements(Boxzoom) Eq 2:bte = [lon1, lon2, lat1, lat2, boxzoom[0], boxzoom[1]]
335        N_Elements(Boxzoom) Eq 4:bte = [Boxzoom, vert1, vert2]
336        N_Elements(Boxzoom) Eq 5:bte = [Boxzoom[0:3], 0, Boxzoom[4]]
337        N_Elements(Boxzoom) Eq 6:bte = Boxzoom
338        Else: BEGIN
339          ncdf_close, cdfid
340          return, report('Wrong Definition of Boxzoom')
341        end
342      ENDCASE
343      savedbox = 1b
344      saveboxparam, 'boxparam4rdncdf.dat'
345      domdef, bte, GRIDTYPE = ['T', vargrid], _extra = ex
346    ENDIF
347    grille, mask, glam, gphi, gdep, nx, ny, nz, firstx, firsty, firstz, lastx, lasty, lastz
348    undefine, glam & undefine, gphi & ; We liberate some memoty!
349  ENDELSE
350;---------------------------------------------------------------------
351; We initializate ixmindta, iymindta if needed
352;---------------------------------------------------------------------
353  if n_elements(jpidta) EQ 0 THEN jpidta = jpiglo
354  if n_elements(jpjdta) EQ 0 THEN jpjdta = jpjglo
355  if n_elements(jpkdta) EQ 0 THEN jpkdta = jpkglo
356  if n_elements(ixmindta) EQ 0 THEN ixmindta = 0
357  if n_elements(ixmaxdta) EQ 0 then ixmaxdta = jpidta-1
358  if ixmindta EQ -1 THEN ixmindta = 0
359  IF ixmaxdta EQ -1 then ixmaxdta = jpidta-1
360  if n_elements(iymindta) EQ 0 THEN iymindta = 0
361  IF n_elements(iymaxdta) EQ 0 then iymaxdta = jpjdta-1
362  if iymindta EQ -1 THEN iymindta = 0
363  IF iymaxdta EQ -1 then iymaxdta = jpjdta-1
364  if n_elements(izmindta) EQ 0 THEN izmindta = 0
365  IF n_elements(izmaxdta) EQ 0 then izmaxdta = jpkdta-1
366  if izmindta EQ -1 THEN izmindta = 0
367  IF izmaxdta EQ -1 then izmaxdta = jpkdta-1
368;----------------------------------------------------------------
369; We will read the file
370;---------------------------------------------------------------
371  if n_elements(key_stride) LE 2 then key_stride = [1, 1, 1]
372  key_stride = 1l > long(key_stride)
373  key_shift = long(testvar(var = key_shift))
374;
375  IF n_elements(key_yreverse) EQ 0 THEN key_yreverse = 0
376  IF keyword_set(key_yreverse) THEN BEGIN
377    tmp = jpj-1-firsty
378    firsty = jpj-1-lasty
379    lasty = tmp
380  ENDIF
381;
382  IF keyword_set(fbase2tbase) THEN BEGIN
383    case strupcase(vargrid) of
384      'U':BEGIN
385        IF NOT keyword_set(key_periodic) THEN BEGIN
386          firstx = firstx+1
387          lastx = lastx+1
388        ENDIF
389      END
390      'V':BEGIN
391        firsty = firsty+1
392        lasty = lasty+1
393      END
394      'F':BEGIN
395        firsty = firsty+1
396        lasty = lasty+1
397        IF NOT keyword_set(key_periodic) THEN BEGIN
398          firstx = firstx+1
399          lastx = lastx+1
400        ENDIF
401      END
402      ELSE:
403    endcase
404  ENDIF
405;
406  IF keyword_set(fbase2tbase) AND keyword_set(key_periodic) $
407    AND (strupcase(vargrid) EQ 'U' OR strupcase(vargrid) EQ 'F') THEN key_shift =  key_shift-1
408;
409;---------------------------------------------------------------------
410;---------------------------------------------------------------------
411@read_ncdf_varget
412;---------------------------------------------------------------------
413;---------------------------------------------------------------------
414;
415  IF keyword_set(fbase2tbase) AND keyword_set(key_periodic) $
416    AND (strupcase(vargrid) EQ 'U' OR strupcase(vargrid) EQ 'F') THEN key_shift =  key_shift+1
417;---------------------------------------------------------------------
418; We define global variable joined with the variable.
419;---------------------------------------------------------------------
420; varname
421  varname = name
422; varunit
423  if varcontient.natts NE 0 then begin
424    attnames = strarr(varcontient.natts)
425    for attiq = 0, varcontient.natts-1 do attnames[attiq] = ncdf_attname(cdfid, name, attiq)
426    lowattnames = strlowcase(attnames)
427;
428    found = (where(lowattnames EQ 'units'))[0]
429    IF found NE -1 then ncdf_attget, cdfid, name, attnames[found], value ELSE value = ''
430    varunit = strtrim(string(value), 2)
431;
432    found = (where(lowattnames EQ 'add_offset'))[0]
433    if found NE -1 then ncdf_attget, cdfid, name, attnames[found], add_offset ELSE add_offset = 0.
434;
435    found = (where(lowattnames EQ 'scale_factor'))[0]
436    if found NE -1 then ncdf_attget, cdfid, name, attnames[found], scale_factor ELSE scale_factor = 1.
437;
438    missing_value = 'no'
439    found = (where(lowattnames EQ '_fillvalue'))[0]
440    if found NE -1 then ncdf_attget, cdfid, name, attnames[found], missing_value
441    found = (where(lowattnames EQ 'missing_value'))[0]
442    if found NE -1 then ncdf_attget, cdfid, name, attnames[found], missing_value
443;
444  ENDIF ELSE BEGIN
445    varunit = ''
446    add_offset = 0.
447    scale_factor = 1.
448    missing_value = 'no'
449  ENDELSE
450; vardate
451; We make a legible date in function of the specified language.
452  year = long(beginning[0])/10000
453  month = (long(beginning[0])/100) MOD 100
454  day = (long(beginning[0]) MOD 100)
455  vardate = string(format = '(C(CMoA))', 31*(month-1))+' '+strtrim(day, 1)+', '+strtrim(year, 1)
456  varexp = file_basename(filename)
457
458; we apply reverse
459  if keyword_set(key_yreverse) then res = reverse(temporary(res),  2)
460  if keyword_set(key_zreverse) AND (size(res))[0] EQ 3 AND jpt EQ 1 then res = reverse(temporary(res), 3)
461  if keyword_set(key_zreverse) AND (size(res))[0] EQ 4 THEN res = reverse(temporary(res), 3)
462
463; We apply the value valmask on land points.
464  if NOT keyword_set(cont_nofill) then begin
465    valmask = 1e20
466    case 1 of
467      varcontient.ndims eq 2:BEGIN ;xy array
468        mask = mask[*, *, 0]
469        earth = where(mask EQ 0)
470      END
471      varcontient.ndims eq 3 AND (where(varcontient.dim EQ contient.recdim))[0] EQ -1:BEGIN ;xyz array
472        earth = where(mask EQ 0)
473      END
474      varcontient.ndims eq 3 AND (where(varcontient.dim EQ contient.recdim))[0] NE -1:BEGIN ;xyt array
475        mask = mask[*, *, 0]
476        earth = where(mask EQ 0)
477        if earth[0] NE -1 then BEGIN
478          earth = earth#replicate(1, jpt)+replicate(nx*ny, n_elements(earth))#lindgen(jpt)
479        END
480      END
481      varcontient.ndims eq 4:BEGIN ;xyzt array
482        earth = where(mask EQ 0)
483        if earth[0] NE -1 then BEGIN
484          earth = earth#replicate(1, jpt)+replicate(nx*ny*nz, n_elements(earth))#lindgen(jpt)
485        END
486      END
487    endcase
488  ENDIF ELSE earth = -1
489; we look for  missing_value
490  IF size(missing_value, /type) NE 7 then BEGIN
491    IF size(missing_value, /type) EQ 1 THEN BEGIN
492      IF isnumber(string(missing_value), tmp) EQ 1 THEN missing_value = tmp
493    ENDIF
494;    if missing_value NE valmask then begin
495    if abs(missing_value) LT 1e6 then missing = where(res EQ missing_value) $
496    ELSE missing = where(abs(res) gt abs(missing_value)/10.)
497;    ENDIF ELSE missing = -1
498  ENDIF ELSE missing = -1
499; we apply add_offset, scale_factor and missing_value
500  if scale_factor NE 1 then res = temporary(res)*scale_factor
501  if add_offset NE 0 then res = temporary(res)+add_offset
502  if missing[0] NE -1 then res[temporary(missing)] = !values.f_nan
503  if earth[0] NE -1 then res[temporary(earth)] = 1e20
504;---------------------------------------------------------------------
505  ncdf_close, cdfid
506;---------------------------------------------------------------------
507  if keyword_set(savedbox) THEN restoreboxparam, 'boxparam4rdncdf.dat'
508  if keyword_set(nostruct) then return, res $
509  ELSE BEGIN
510    IF keyword_set(key_forgetold) THEN BEGIN
511      return, {arr:res, grid:vargrid, unit:varunit, experiment:varexp, name:varname}
512    ENDIF ELSE BEGIN
513      return, {tab:res, grille:vargrid, unite:varunit, experience:varexp, nom:varname}
514    ENDELSE
515  ENDELSE
516END
517
518
519
520
521
522
Note: See TracBrowser for help on using the repository browser.