Line data Source code
1 : !=======================================================================
2 :
3 : ! Calendar routines for managing time
4 : !
5 : ! authors: Elizabeth C. Hunke, LANL
6 :
7 : module icedrv_calendar
8 :
9 : use icedrv_kinds
10 : use icepack_intfc, only: icepack_query_parameters
11 : use icepack_intfc, only: icepack_warnings_flush, icepack_warnings_aborted
12 : use icedrv_constants, only: c0, c1, c100, c30, c360, c365, c3600
13 : use icedrv_constants, only: c4, c400, nu_diag, nu_diag_out
14 : use icedrv_system, only: icedrv_system_abort
15 :
16 : implicit none
17 : private
18 :
19 : public :: init_calendar, calendar, time2sec, sec2time
20 :
21 : integer (kind=int_kind), public :: &
22 : days_per_year , & ! number of days in one year
23 : daymo(12) , & ! number of days in each month
24 : daycal(13) ! day number at end of month
25 :
26 : ! 360-day year data
27 : integer (kind=int_kind) :: &
28 : daymo360(12) , & ! number of days in each month
29 : daycal360(13) ! day number at end of month
30 : data daymo360 / 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30/
31 : data daycal360/ 0,30, 60, 90,120,150,180,210,240,270,300,330,360/
32 :
33 : ! 365-day year data
34 : integer (kind=int_kind) :: &
35 : daymo365(12) , & ! number of days in each month
36 : daycal365(13) ! day number at end of month
37 : data daymo365 / 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31/
38 : data daycal365/ 0,31, 59, 90,120,151,181,212,243,273,304,334,365/
39 :
40 : ! 366-day year data (leap year)
41 : integer (kind=int_kind) :: &
42 : daymo366(12) , & ! number of days in each month
43 : daycal366(13) ! day number at end of month
44 : data daymo366 / 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31/
45 : data daycal366/ 0,31, 60, 91,121,152,182,213,244,274,305,335,366/
46 :
47 : real (kind=dbl_kind), parameter :: &
48 : days_per_4c = 146097.0_dbl_kind, &
49 : days_per_c = 36524.0_dbl_kind, &
50 : days_per_4y = 1461.0_dbl_kind, &
51 : days_per_y = 365.0_dbl_kind
52 :
53 : integer (kind=int_kind), public :: &
54 : istep , & ! local step counter for time loop
55 : istep0 , & ! counter, number of steps taken in previous run
56 : istep1 , & ! counter, number of steps at current timestep
57 : mday , & ! day of the month
58 : hour , & ! hour of the year
59 : month , & ! month number, 1 to 12
60 : monthp , & ! last month
61 : year_init, & ! initial year
62 : nyr , & ! year number
63 : idate , & ! date (yyyymmdd)
64 : sec , & ! elapsed seconds into date
65 : npt , & ! total number of time steps (dt)
66 : ndtd , & ! number of dynamics subcycles: dt_dyn=dt/ndtd
67 : stop_now , & ! if 1, end program execution
68 : write_restart , & ! if 1, write restart now
69 : diagfreq ! diagnostic output frequency (once per diagfreq*dt)
70 :
71 : real (kind=dbl_kind), public :: &
72 : dt , & ! thermodynamics timestep (s)
73 : dt_dyn , & ! dynamics/transport/ridging timestep (s)
74 : time0 , & ! total elapsed time at istep0 for idate0 (s)
75 : time , & ! total elapsed time (s)
76 : time_forc , & ! time of last forcing update (s)
77 : yday , & ! day of the year
78 : tday , & ! absolute day number
79 : dayyr , & ! number of days per year
80 : basis_seconds , & ! Seconds since calendar zero
81 : secday ! seconds per day
82 :
83 : logical (kind=log_kind), public :: &
84 : new_year , & ! new year = .true.
85 : new_month , & ! new month = .true.
86 : new_day , & ! new day = .true.
87 : new_hour , & ! new hour = .true.
88 : use_leap_years , & ! use leap year functionality if true
89 : write_ic , & ! write initial condition now
90 : dump_last , & ! write restart at end
91 : force_restart_now ! force a restart now
92 :
93 : character (len=1), public :: &
94 : dumpfreq ! restart frequency, 'y','m','d'
95 :
96 : character (len=char_len), public :: &
97 : calendar_type ! differentiates Gregorian from other calendars
98 : ! default = ' '
99 :
100 : !=======================================================================
101 :
102 : contains
103 :
104 : !=======================================================================
105 :
106 : ! Initialize calendar variables
107 : !
108 : ! authors: Elizabeth C. Hunke, LANL
109 :
110 83 : subroutine init_calendar
111 : character(len=*), parameter :: subname='(init_calendar)'
112 :
113 : !-----------------------------------------------------------------
114 : ! query Icepack values
115 : !-----------------------------------------------------------------
116 :
117 83 : call icepack_query_parameters(secday_out=secday)
118 83 : call icepack_warnings_flush(nu_diag)
119 83 : if (icepack_warnings_aborted()) call icedrv_system_abort(string=subname, &
120 0 : file=__FILE__,line= __LINE__)
121 :
122 : !-----------------------------------------------------------------
123 :
124 83 : istep = 0 ! local timestep number
125 83 : time0=istep0*dt ! start time
126 83 : time=istep0*dt ! s
127 83 : yday=c0 ! absolute day number
128 83 : mday=0 ! day of the month
129 83 : month=0 ! month
130 83 : nyr=0 ! year
131 83 : idate=00000101 ! date
132 83 : sec=0 ! seconds into date
133 83 : istep1 = istep0 ! number of steps at current timestep
134 : ! real (dumped) or imagined (use to set calendar)
135 83 : stop_now = 0 ! end program execution if stop_now=1
136 83 : dt_dyn = dt/real(ndtd,kind=dbl_kind) ! dynamics et al timestep
137 83 : force_restart_now = .false.
138 :
139 : ! Check that the number of days per year is set correctly when using
140 : ! leap years. If not, set days_per_year correctly and warn the user.
141 83 : if (use_leap_years .and. days_per_year /= 365) then
142 0 : days_per_year = 365
143 0 : write(nu_diag,*) 'Warning: days_per_year has been set to 365', &
144 0 : ' because use_leap_years = .true.'
145 : end if
146 :
147 83 : calendar_type = ' '
148 83 : if (use_leap_years .and. days_per_year == 365) calendar_type = 'Gregorian'
149 :
150 83 : dayyr = real(days_per_year, kind=dbl_kind)
151 83 : if (days_per_year == 360) then
152 3 : daymo = daymo360
153 3 : daycal = daycal360
154 80 : elseif (days_per_year == 365) then
155 80 : daymo = daymo365
156 80 : daycal = daycal365
157 : endif
158 :
159 : ! Get the time in seconds from calendar zero to start of initial year
160 83 : call time2sec(year_init,1,1,basis_seconds)
161 :
162 : ! determine initial date (assumes namelist year_init, istep0 unchanged)
163 83 : sec = mod(time,secday) ! elapsed seconds into date at
164 : ! end of dt
165 83 : tday = (time-sec)/secday + c1 ! absolute day number
166 :
167 : ! Convert the current timestep into a calendar date
168 83 : call sec2time(nyr,month,mday,basis_seconds+time)
169 :
170 83 : yday = mday + daycal(month) ! day of the year
171 83 : nyr = nyr - year_init + 1 ! year number
172 :
173 83 : end subroutine init_calendar
174 :
175 : !=======================================================================
176 :
177 : ! Determine the date at the end of the time step
178 : !
179 : ! authors: Elizabeth C. Hunke, LANL
180 : ! Tony Craig, NCAR
181 : ! Craig MacLachlan, UK Met Office
182 :
183 657565 : subroutine calendar(ttime)
184 :
185 : use icedrv_domain_size, only: nx
186 :
187 : real (kind=dbl_kind), intent(in) :: &
188 : ttime ! time variable
189 :
190 : ! local variables
191 :
192 : integer (kind=int_kind) :: &
193 : ns , & ! loop index
194 : nyrp,mdayp,hourp ! previous year, day, hour
195 :
196 : character(len=*), parameter :: subname='(calendar)'
197 :
198 657565 : nyrp=nyr
199 657565 : monthp=month
200 657565 : mdayp=mday
201 657565 : hourp=hour
202 657565 : new_year=.false.
203 657565 : new_month=.false.
204 657565 : new_day=.false.
205 657565 : new_hour=.false.
206 657565 : write_restart=0
207 :
208 657565 : sec = mod(ttime,secday) ! elapsed seconds into date at
209 : ! end of dt
210 657565 : tday = (ttime-sec)/secday + c1 ! absolute day number
211 :
212 : ! Deterime the current date from the timestep
213 657565 : call sec2time(nyr,month,mday,basis_seconds+ttime)
214 :
215 657565 : yday = mday + daycal(month) ! day of the year
216 657565 : nyr = nyr - year_init + 1 ! year number
217 :
218 657565 : hour = int((ttime)/c3600) + c1 ! hour
219 :
220 657565 : idate = (nyr+year_init-1)*10000 + month*100 + mday ! date (yyyymmdd)
221 :
222 657565 : if (istep >= npt+1) stop_now = 1
223 657565 : if (nyr /= nyrp) new_year = .true.
224 657565 : if (month /= monthp) new_month = .true.
225 657565 : if (mday /= mdayp) new_day = .true.
226 657565 : if (hour /= hourp) new_hour = .true.
227 :
228 657565 : if (istep > 1) then
229 :
230 14568 : select case (dumpfreq)
231 : case ("y", "Y")
232 14568 : if (new_year) &
233 0 : write_restart = 1
234 : case ("m", "M")
235 634044 : if (new_month) &
236 0 : write_restart = 1
237 : case ("d", "D")
238 8760 : if (new_day) &
239 657737 : write_restart = 1
240 : end select
241 :
242 657372 : if (force_restart_now) write_restart = 1
243 657372 : if (dump_last .and. istep == npt) write_restart = 1
244 :
245 : endif ! istep > 1
246 :
247 657565 : if (mod(istep,diagfreq) == 0 .and. stop_now /= 1) then
248 420970 : do ns = 1, nx
249 336776 : write(nu_diag_out+ns-1,*) ' '
250 : write(nu_diag_out+ns-1,'(a7,i10,4x,a6,i10,4x,a4,i10)') &
251 420970 : 'istep1:', istep1, 'idate:', idate, 'sec:', sec
252 : end do
253 : endif
254 :
255 657565 : end subroutine calendar
256 :
257 : !=======================================================================
258 :
259 : ! Convert the date to seconds since calendar zero.
260 : ! ** This is based on the UM routine TIME2SEC **
261 : !
262 : ! authors: Craig MacLachlan, UK Met Office
263 :
264 83 : subroutine time2sec(year,month,day,tsec)
265 :
266 : integer (kind=int_kind), intent(in) :: year ! year
267 : integer (kind=int_kind), intent(in) :: month ! month
268 : integer (kind=int_kind), intent(in) :: day ! year
269 : real (kind=dbl_kind), intent(out) :: tsec ! seconds since calendar zero
270 :
271 : ! local variables
272 :
273 : real (kind=dbl_kind) :: days_since_calz ! days since calendar zero
274 : integer (kind=int_kind) :: years_since_calz ! days since calendar zero
275 : character(len=*), parameter :: subname='(time2sec)'
276 :
277 83 : if (dayyr == 360) then
278 3 : days_since_calz = c360*year + c30*(month-1) + day - c1
279 3 : tsec = secday * days_since_calz
280 :
281 : else
282 :
283 80 : if (use_leap_years) then
284 :
285 1 : call set_calendar(year)
286 :
287 : ! Add on the days from this year
288 1 : days_since_calz = day + daycal(month) - c1
289 :
290 : ! Subtract a year because we only want to count whole years
291 1 : years_since_calz = year - 1
292 :
293 : ! Add days from preceeding years
294 : days_since_calz = days_since_calz &
295 1 : + int(years_since_calz/c400)*days_per_4c
296 : years_since_calz = years_since_calz &
297 1 : - int(years_since_calz/c400)*400
298 :
299 : days_since_calz = days_since_calz &
300 1 : + int(years_since_calz/c100)*days_per_c
301 : years_since_calz = years_since_calz &
302 1 : - int(years_since_calz/c100)*100
303 :
304 : days_since_calz = days_since_calz &
305 1 : + int(years_since_calz/c4)*days_per_4y
306 : years_since_calz = years_since_calz &
307 1 : - int(years_since_calz/c4)*4
308 :
309 : days_since_calz = days_since_calz &
310 1 : + years_since_calz*days_per_y
311 :
312 1 : tsec = secday * days_since_calz
313 :
314 : else ! Using fixed 365-day calendar
315 :
316 79 : days_since_calz = c365*year + daycal365(month) + day - c1
317 79 : tsec = secday * days_since_calz
318 :
319 : end if
320 :
321 : end if
322 :
323 83 : end subroutine time2sec
324 :
325 : !=======================================================================
326 :
327 : ! Convert the time in seconds since calendar zero to a date.
328 : !
329 : ! authors: Craig MacLachlan, UK Met Office
330 :
331 657648 : subroutine sec2time(year,month,day,tsec)
332 :
333 : integer (kind=int_kind), intent(out) :: year ! year
334 : integer (kind=int_kind), intent(out) :: month ! month
335 : integer (kind=int_kind), intent(out) :: day ! year
336 : real (kind=dbl_kind), intent(in) :: tsec ! seconds since calendar zero
337 :
338 : ! local variables
339 :
340 : real (kind=dbl_kind) :: days_since_calz ! days since calendar zero
341 : integer (kind=int_kind) :: k ! counter
342 : character(len=*), parameter :: subname='(sec2time)'
343 :
344 657648 : days_since_calz = int(tsec/secday)
345 :
346 657648 : if (dayyr == 360) then
347 :
348 24142 : year = int(days_since_calz/c360)
349 24142 : month = mod(int(days_since_calz/c30),12) + 1
350 24142 : day = mod(int(days_since_calz),30) + 1
351 :
352 : else
353 :
354 633506 : if (use_leap_years) then
355 :
356 8763 : year = int(days_since_calz/days_per_4c)*400
357 : days_since_calz = days_since_calz &
358 8763 : - int(days_since_calz/days_per_4c)*days_per_4c
359 :
360 8763 : if (days_since_calz == 4*days_per_c) then
361 0 : year = year + 400
362 0 : days_since_calz = days_per_y + 1
363 : else
364 8763 : year = year + int(days_since_calz/days_per_c)*100
365 : days_since_calz = days_since_calz &
366 8763 : - int(days_since_calz/days_per_c)*days_per_c
367 :
368 8763 : year = year + int(days_since_calz/days_per_4y)*4
369 : days_since_calz = days_since_calz &
370 8763 : - int(days_since_calz/days_per_4y)*days_per_4y
371 :
372 8763 : if (days_since_calz == 4*days_per_y) then
373 0 : year = year + 4
374 0 : days_since_calz = days_per_y + 1
375 : else
376 8763 : year = year + int(days_since_calz/days_per_y) + 1
377 : days_since_calz = days_since_calz &
378 8763 : - int(days_since_calz/days_per_y)*days_per_y + c1
379 : endif
380 : endif
381 :
382 : ! Ensure the calendar variables are correct for this year.
383 8763 : call set_calendar(year)
384 :
385 : ! Calculate the month
386 8763 : month = 1
387 113919 : do k = 1, 12
388 113919 : if (days_since_calz > daycal(k)) month = k
389 : enddo
390 :
391 : ! Calculate the day of the month
392 8763 : day = days_since_calz - daycal(month)
393 :
394 : else ! Using fixed 365-day calendar
395 :
396 624743 : year = int(days_since_calz/c365)
397 624743 : days_since_calz = days_since_calz - year*365 + 1
398 :
399 : ! Calculate the month
400 624743 : month = 1
401 8121659 : do k = 1, 12
402 8121659 : if (days_since_calz > daycal365(k)) month = k
403 : enddo
404 :
405 : ! Calculate the day of the month
406 624743 : day = days_since_calz - daycal365(month)
407 :
408 : end if
409 :
410 : end if
411 :
412 657648 : end subroutine sec2time
413 :
414 : !=======================================================================
415 :
416 : ! Set the "days per month", "days per year", etc variables for the
417 : ! current year.
418 : !
419 : ! authors: Craig MacLachlan, UK Met Office
420 :
421 8764 : subroutine set_calendar(year)
422 :
423 : integer (kind=int_kind), intent(in) :: year ! current year
424 :
425 : ! Internal variable
426 : logical (kind=log_kind) :: isleap ! Leap year logical
427 : character(len=*), parameter :: subname='(set_calendar)'
428 :
429 8764 : isleap = .false. ! not a leap year
430 8764 : if (mod(year, 4) == 0) isleap = .true.
431 8764 : if (mod(year,100) == 0) isleap = .false.
432 8764 : if (mod(year,400) == 0) isleap = .true.
433 :
434 : ! Ensure the calendar is set correctly
435 8764 : if (isleap) then
436 0 : daycal = daycal366
437 0 : daymo = daymo366
438 0 : dayyr=real(daycal(13), kind=dbl_kind)
439 0 : days_per_year=int(dayyr)
440 : else
441 8764 : daycal = daycal365
442 8764 : daymo = daymo365
443 8764 : dayyr=real(daycal(13), kind=dbl_kind)
444 8764 : days_per_year=int(dayyr)
445 : endif
446 :
447 8764 : end subroutine set_calendar
448 :
449 : !=======================================================================
450 :
451 : end module icedrv_calendar
452 :
453 : !=======================================================================
|