source: trunk/SRC/ReadWrite/ncdf_gettime.pro @ 495

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

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

  • Property svn:keywords set to Id
File size: 10.2 KB
RevLine 
[272]1;+
2;
3; @file_comments
4; get the time axis from a netcdf_file and transforms it in
5; Julian days of IDL.
6;
7; @categories
8; Read NetCDF file
9;
10; @param filename {in}{required}{type=scalar string}
11; the name of the ncdf_file
12;
[389]13; @param cdfid {in}{optional}{type=scalar}
[495]14; the ID of the ncdf_file, if the file is already open.
[389]15; if not provided, ncdf_gettime open the file defined by filename
[272]16;
17; @keyword TIMEVAR {type=string}
18; It define the name of the variable that
19; contains the time axis. This keyword can be useful if there
20; is no unlimited dimension or if the time axis selected by default
21; (the first 1D array with unlimited dimension) is not the good one.
22;
[370]23; @keyword CALLER {required}{type=string}
[272]24; Used to specify the error messages. Give the name of the calling
[370]25; procedure. It can be only '<pro>read_ncdf</pro>' or '<pro>scanfile</pro>'.
[272]26;
[401]27; @keyword CALTYPE
[493]28; Used to specify (or overwrite) the type of calendar that should be
[401]29; used. We accept only 'noleap', '360d', 'greg' and 'gregorian'. By
[493]30; default, we use the type of calendar defined in the attribute
[401]31; calendar. if not, we define it as gregorian.
32;
[272]33; @keyword ERR
34; Set this keyword to a named variable in which the value of the error
35; message will be returned
36;
37; @keyword _EXTRA
38; _EXTRA to be able to call ncdf_getmask with _extra keyword
39;
40; @returns
41; a double 1D array of IDL Julian days
42; In case of error return -1 if the time dimension was not found
[297]43;               or return -jpt if it as been found that the time dimension size is jpt
[272]44;
45; @restrictions
46; the calendar variable must have the units attribute
[358]47; following the syntax below:
[272]48;
49; time_counter:units = "seconds since 0001-01-01 00:00:00" ;
[444]50; time_counter:units = "minutes since 0001-01-01 00:00:00" ;
[272]51; time_counter:units = "hours since 0001-01-01 00:00:00" ;
52; time_counter:units = "days since 1979-01-01 00:00:00" ;
53; time_counter:units = "months since 1979-01-01 00:00:00" ;
54; time_counter:units = "years since 1979-01-01 00:00:00" ;
55;
56; @history
57; August 2007: Sebastien Masson (smasson\@lodyc.jussieu.fr)
58;
59; @version
60; $Id$
61;-
[401]62FUNCTION ncdf_gettime, filename, cdfid, CALTYPE = caltype $
[389]63                       , TIMEVAR = timevar, CALLER = caller, ERR = err, _EXTRA = ex
[272]64;
65  compile_opt idl2, strictarrsubs
66;
67  @cm_4cal                      ;   needed for key_caltype
68;
[389]69  IF n_elements(cdfid) EQ 0 THEN BEGIN
[396]70    cdfid = ncdf_open(isafile(filename, title = 'which file must be open by ncdf_gettime?', IODIRECTORY = iodir, _extra = ex))
[389]71    tobeclosed = 1
72  ENDIF
[474]73  IF n_elements(caller) EQ 0 THEN caller = 'read_ncdf'
[272]74  inq = ncdf_inquire(cdfid)
75;----------------------------------------------------
76;`find the variable containing the time axis
77;----------------------------------------------------
78; we get its name through the keyword timevar
79  IF keyword_set(timevar) THEN BEGIN
80    timeid = ncdf_varid(cdfid, timevar)
[389]81    IF timeid EQ -1 THEN BEGIN  ;   the variable is not found
[272]82      CASE caller OF
83        'read_ncdf':err = 'No variable ' + timevar + 'found in '+filename+'. Use the TIMESTEP keyword'
84        'scanfile':err = 'No variable ' + timevar + 'found in '+filename+'. We create a fake calendar'
85      ENDCASE
[389]86      IF keyword_set(tobeclosed) THEN ncdf_close, cdfid
[272]87      return, -1
88    ENDIF
89    timeinq = ncdf_varinq(cdfid, timeid)
90    inq.recdim = timeinq.dim[0]
91    ncdf_diminq, cdfid, inq.recdim, timedimname, jpt
92  ENDIF ELSE BEGIN
93; we try to find the time axis automatically
94; we look for the infinite dimension
95    IF inq.recdim EQ -1 THEN BEGIN
96      CASE caller OF
97        'read_ncdf':err = 'the file '+filename+' as no infinite dimension. !C Use TIMESTEP or TIMEVAR keyword'
98        'scanfile':err = 'the file '+filename+' as no infinite dimension. We create a fake calendar'
99      ENDCASE
[389]100      IF keyword_set(tobeclosed) THEN ncdf_close, cdfid
[272]101      return, -1
102    ENDIF
103    ncdf_diminq, cdfid, inq.recdim, timedimname, jpt
104; we look for the variable containing the time axis
105; we look for the first variable having for only dimension inq.recdim
106    timeid = 0
[389]107    REPEAT BEGIN                           ; As long as we have not find a variable having only one dimension: the infinite one
[272]108      timeinq = ncdf_varinq(cdfid, timeid) ; that the variable contain.
[438]109      tstok = n_elements(timeinq.dim) EQ 1 AND timeinq.dim[0] EQ inq.recdim
[272]110      timeid = timeid+1
[438]111    ENDREP UNTIL tstok OR timeid EQ inq.nvars
[439]112    IF NOT tstok THEN BEGIN
[272]113      CASE caller OF
114        'read_ncdf':err = 'the file '+filename+' as no time axis variable. !C Use the TIMESTEP keyword'
[407]115        'scanfile':err = 'the file '+filename+' has no time axis.!C we create a fake calendar ...'
[272]116      ENDCASE
[389]117      IF keyword_set(tobeclosed) THEN ncdf_close, cdfid
[272]118      return, -jpt
119    ENDIF
120    timeid = timeid-1
121  ENDELSE
122;----------------------------------------------------
123; look for attribute units and calendar to know how to compte the calendar
124;----------------------------------------------------
125; no attribute for time variable...
126  IF timeinq.natts EQ 0 then begin
127    CASE caller OF
128      'read_ncdf':err = 'the variable '+timeinq.name+' has no attribute.!C Use the TIMESTEP keyword'
129      'scanfile':err = 'the variable '+timeinq.name+' has no attribute.!C we create a fake calendar ...'
130    ENDCASE
[389]131    IF keyword_set(tobeclosed) THEN ncdf_close, cdfid
[272]132    return, -jpt
133  ENDIF
134; get attributes names
135  attnames = strarr(timeinq.natts)
136  for attiq = 0, timeinq.natts-1 do attnames[attiq] = strlowcase(ncdf_attname(cdfid, timeid, attiq))
137; do we find units attribute?
138  IF (where(attnames EQ 'units'))[0] EQ -1 then BEGIN
139    CASE caller OF
140      'read_ncdf':err = 'Attribute ''units'' not found for the variable '+timeinq.name+' !C Use the TIMESTEP keyword'
141      'scanfile':err = 'Attribute ''units'' not found for the variable '+timeinq.name+'!C we create a fake calendar ...'
142    ENDCASE
[389]143    IF keyword_set(tobeclosed) THEN ncdf_close, cdfid
[272]144    return, -jpt
145  ENDIF
146; Is attribute "calendar" existing?
147; If no, we suppose that the calendar is gregorian calendar
148;
[344]149  ncdf_getatt, cdfid, timeid, calendar = calendar, units = value
[401]150  IF keyword_set(caltype) THEN calendar = strlowcase(caltype)
[344]151  CASE calendar OF
152    'noleap':key_caltype = 'noleap'
[470]153    '365day':key_caltype = 'noleap'
154    '365days':key_caltype = 'noleap'
155    '365_day':key_caltype = 'noleap'
156    '365_days':key_caltype = 'noleap'
[344]157    '360d':key_caltype = '360d'
[470]158    '360day':key_caltype = '360d'
159    '360days':key_caltype = '360d'
160    '360_day':key_caltype = '360d'
161    '360_days':key_caltype = '360d'
162    'standard':key_caltype = 'greg'
[344]163    'greg':key_caltype = 'greg'
[401]164    'gregorian':key_caltype = 'greg'
[495]165    ELSE:BEGIN
[493]166      dummy = report( ['unknown calendar type: '+calendar, 'we use gregorian calendar'] )
[401]167      key_caltype = 'greg'
168    END
[344]169  ENDCASE
[272]170;----------------------------------------------------
171; decode units attribute
172;----------------------------------------------------
173;
[396]174  value = strlowcase(value)
[495]175  IF value NE 'true julian day' THEN BEGIN
[272]176; time_counter:units = "seconds since 0001-01-01 00:00:00" ;
[444]177; time_counter:units = "minutes since 0001-01-01 00:00:00" ;
[272]178; time_counter:units = "hours since 0001-01-01 00:00:00" ;
179; time_counter:units = "days since 1979-01-01 00:00:00" ;
180; time_counter:units = "months since 1979-01-01 00:00:00" ;
181; time_counter:units = "years since 1979-01-01 00:00:00" ;
182;
183; we decript the "units" attribute to find the time origin
[396]184    words = str_sep(value, ' ')
185    units = words[0]
186    IF strpos(units, 's', strlen(units)-1) NE -1 THEN units = strmid(units, 0, strlen(units)-1)
187    IF strpos(units, 'julian_') NE -1 THEN units = strmid(units, 7)
[444]188    IF units NE 'second' AND units NE 'minute' AND units NE 'hour' AND units NE 'day' $
[396]189       AND units NE 'month' AND units NE 'year' THEN BEGIN
190      CASE caller OF
[444]191        'read_ncdf':err = 'time units does not start with seconds/minutes/hours/days/months/years !C Use the TIMESTEP keyword'
192        'scanfile':err = 'time units does not start with seconds/minutes/hours/days/months/years !C we create a fake calendar ...'
[396]193      ENDCASE
194      IF keyword_set(tobeclosed) THEN ncdf_close, cdfid
195      return, -jpt
196    ENDIF
197    IF stregex(value, '[^ ]* since ([0-9]){1,4}-([0-9]){1,2}-([0-9]){1,2}.*', /boolean) EQ 0 THEN BEGIN
198      CASE caller OF
199        'read_ncdf':err = 'attribute units of time has not the good format: [^ ]* since ([0-9]){1,4}-([0-9]){1,2}-([0-9]){1,2}.*!C Use the TIMESTEP keyword'
200        'scanfile':err = 'attribute units of time has not the good format: [^ ]* since ([0-9]){1,4}-([0-9]){1,2}-([0-9]){1,2}.*!C we create a fake calendar ...'
201      ENDCASE
202      IF keyword_set(tobeclosed) THEN ncdf_close, cdfid
203      return, -jpt
204    ENDIF
205    start = str_sep(words[2], '-')
[474]206    IF stregex(value, '[^ ]* since ([0-9]){1,4}-([0-9]){1,2}-([0-9]){1,2} ([0-9]){1,2}:([0-9]){1,2}:([0-9]){1,2}', /boolean) EQ 0 THEN BEGIN
207      print, 'hh:mm:ss of the calendar origin not found... -> start calendar at 00:00:00'
208      start = [start, '0', '0', '0']
209    ENDIF ELSE start = [start, str_sep(words[3], ':')]
[396]210  ENDIF ELSE units = value
[272]211;----------------------------------------------------
212; compute time axis
213;----------------------------------------------------
214  ncdf_varget, cdfid, timeid, time
215  time = double(time)
[396]216  case units OF
217    'true julian day':
[474]218    'second':time = julday(start[1], start[2], start[0], start[3], start[4], start[5])+time/86400.d
219    'minute':time = julday(start[1], start[2], start[0], start[3], start[4], start[5])+time/1440.d
220    'hour':time = julday(start[1], start[2], start[0], start[3], start[4], start[5])+time/24.d
221    'day':time = julday(start[1], start[2], start[0], start[3], start[4], start[5])+time
[272]222    'month':BEGIN
223      if total(fix(time) NE time) NE 0 then $ ; we switch to days with 30d/m
[474]224         time = julday(start[1], start[2], start[0], start[3], start[4], start[5]) + round(time*30) $
225      ELSE time = julday(start[1]+fix(time), replicate(start[2], jpt), replicate(start[0], jpt), start[3], start[4], start[5])
[272]226    END
227    'year':BEGIN
228      if total(fix(time) NE time) NE 0 then $ ; we switch to days with 365d/y
[474]229         time = julday(start[1], start[2], start[0], start[3], start[4], start[5]) + round(time*365) $
230      ELSE time = julday(replicate(start[1], jpt), replicate(start[2], jpt), start[0]+fix(time), start[3], start[4], start[5])
[272]231    END
232  ENDCASE
233  time = double(time)
234;
[389]235  IF keyword_set(tobeclosed) THEN ncdf_close, cdfid
[272]236  return, time
237END
Note: See TracBrowser for help on using the repository browser.