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

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

english and nicer header (3a)

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