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

Last change on this file since 401 was 401, checked in by smasson, 15 years ago

minor adds

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