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