Skip to content

Commit f309fc9

Browse files
committed
Handle NetCDF time var units correctly for both JRA55 and ERA5. COSIMA/access-om2#242
1 parent 4d482fe commit f309fc9

File tree

2 files changed

+20
-14
lines changed

2 files changed

+20
-14
lines changed

libforcing/src/ncvar.F90

+17-11
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ module ncvar_mod
2020
type(datetime) :: start_date
2121
integer :: nx, ny
2222
integer :: dt
23+
integer :: units_as_seconds
2324
character(len=9) :: calendar
2425

2526
integer :: idx_guess
@@ -32,7 +33,7 @@ module ncvar_mod
3233
procedure, pass(self), public :: refresh => ncvar_refresh
3334
procedure, pass(self), public :: read_data => ncvar_read_data
3435
procedure, pass(self) :: get_index_for_datetime
35-
procedure, pass(self) :: get_start_date_and_calendar
36+
procedure, pass(self) :: get_time_metadata
3637
endtype ncvar
3738

3839
contains
@@ -120,9 +121,10 @@ subroutine ncvar_refresh(self, filename, &
120121
call ncheck(nf90_get_var(self%ncid, time_varid, self%times), &
121122
'ncvar get_var time in: '//trim(self%filename))
122123

123-
self%dt = int((self%times(2) - self%times(1))*3600)
124124
! Initialise start date and calendar
125-
call self%get_start_date_and_calendar(time_varid, self%start_date, self%calendar)
125+
call self%get_time_metadata(time_varid, self%start_date, self%calendar, &
126+
self%units_as_seconds)
127+
self%dt = int((self%times(2) - self%times(1))*self%units_as_seconds)
126128

127129
status = nf90_get_att(self%ncid, time_varid, "bounds", time_bnds_name)
128130
if (status == nf90_noerr) then
@@ -147,35 +149,39 @@ subroutine ncvar_refresh(self, filename, &
147149

148150
endsubroutine
149151

150-
subroutine get_start_date_and_calendar(self, time_varid, start_date, calendar)
152+
!> Return the start_date, calendar and time dimenstion units
153+
subroutine get_time_metadata(self, time_varid, start_date, calendar, units_as_seconds)
151154
class(ncvar), intent(in) :: self
152155
integer, intent(in) :: time_varid
153156
type(datetime), intent(out) :: start_date
154157
character(len=9), intent(out) :: calendar
158+
integer, intent(out) :: units_as_seconds
155159

156160
character(len=256) :: time_str
157161
type(tm_struct) :: ctime
158162
integer :: rc, idx
159163

160164
! Getcalendar
161165
call ncheck(nf90_get_att(self%ncid, time_varid, "calendar", calendar), &
162-
'get_start_date_and_calendar: nf90_get_att: '//calendar)
166+
'get_time_metadata: nf90_get_att: '//calendar)
163167
if (trim(calendar) == 'NOLEAP') then
164168
calendar = 'noleap'
165169
endif
166170
call assert(trim(calendar) == 'noleap' .or. trim(calendar) == 'gregorian', &
167-
'get_start_date_and_calendar: unrecognized calendar type')
171+
'get_time_metadata: unrecognized calendar type')
168172

169173
! Get start date
170174
call ncheck(nf90_get_att(self%ncid, time_varid, "units", time_str), &
171-
'get_start_date_and_calendar: nf90_get_att: '//time_str)
175+
'get_time_metadata: nf90_get_att: '//time_str)
172176

173177
! See whether it has the expected format
174178
idx = index(trim(time_str), "days since")
175179
time_str = replace_text(time_str, "days since ", "")
180+
units_as_seconds = 86400
176181
if (idx <= 0) then
177182
idx = index(trim(time_str), "hours since")
178183
time_str = replace_text(time_str, "hours since ", "")
184+
units_as_seconds = 3600
179185
endif
180186
call assert(idx > 0, "ncvar invalid time format")
181187

@@ -189,7 +195,7 @@ subroutine get_start_date_and_calendar(self, time_varid, start_date, calendar)
189195
call assert(rc /= 0, 'strptime in get_start_date_and_calendar failed on '//time_str)
190196
start_date = tm2date(ctime)
191197

192-
endsubroutine get_start_date_and_calendar
198+
endsubroutine get_time_metadata
193199

194200
!> Return the time index of a particular date.
195201
function get_index_for_datetime(self, target_date, from_beginning, guess)
@@ -218,11 +224,11 @@ function get_index_for_datetime(self, target_date, from_beginning, guess)
218224
! Must convert to days _and_ seconds rather than just days to avoid
219225
! integer overflow.
220226
hours = floor(self%time_bnds(1, i))
221-
seconds = nint((self%time_bnds(1, i) - hours)*3600)
227+
seconds = nint((self%time_bnds(1, i) - hours)*self%units_as_seconds)
222228
td_before = timedelta(hours=hours, seconds=seconds)
223229

224230
hours = floor(self%time_bnds(2, i))
225-
seconds = nint((self%time_bnds(2, i) - hours)*3600)
231+
seconds = nint((self%time_bnds(2, i) - hours)*self%units_as_seconds)
226232
td_after = timedelta(hours=hours, seconds=seconds)
227233

228234
if (target_date >= (self%start_date + td_before) .and. &
@@ -235,7 +241,7 @@ function get_index_for_datetime(self, target_date, from_beginning, guess)
235241
else
236242
do i=self%idx_guess, size(self%times)
237243
hours = floor(self%times(i))
238-
seconds = nint((self%times(i) - hours)*3600)
244+
seconds = nint((self%times(i) - hours)*self%units_as_seconds)
239245
td = timedelta(hours=hours, seconds=seconds)
240246

241247
if (target_date == (self%start_date + td)) then

libforcing/src/util.F90

+3-3
Original file line numberDiff line numberDiff line change
@@ -184,9 +184,9 @@ function filename_for_date(filename_template, date)
184184
year = date%getYear()
185185
month = date%getMonth()
186186

187-
write(year_str, "(I4)") year
188-
write(yearp1_str, "(I4)") year+1
189-
write(month_str, "(I2)") month
187+
write(year_str, "(I4.4)") year
188+
write(yearp1_str, "(I4.4)") year+1
189+
write(month_str, "(I2.2)") month
190190

191191
start_day = 1
192192
end_day = DAYS_IN_MONTH(month)

0 commit comments

Comments
 (0)