! $Id: ice_calendar.F90 56 2007-03-15 14:42:35Z dbailey $
!=======================================================================
!BOP
!
! !MODULE: ice_calendar - calendar routines for managing time
!
! !DESCRIPTION:
!
! Calendar routines for managing time
!
! !REVISION HISTORY:
!
! authors: Elizabeth C. Hunke, LANL
! Tony Craig, NCAR
!
! 2006 ECH: Removed 'w' option for history; added 'h' and histfreq_n.
! Converted to free form source (F90).
!
! !INTERFACE:
!
module ice_calendar 39,3
!
! !USES:
!
use ice_constants
use ice_domain_size
, only: max_nstrm
use ice_exit
, only: abort_ice
!
!EOP
!
implicit none
save
integer (kind=int_kind) :: &
days_per_year , & ! number of days in one year
daymo(12) , & ! number of days in each month
daycal(13) ! day number at end of month
! 360-day year data
integer (kind=int_kind) :: &
daymo360(12) , & ! number of days in each month
daycal360(13) ! day number at end of month
data daymo360 / 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30/
data daycal360/ 0,30, 60, 90,120,150,180,210,240,270,300,330,360/
! 365-day year data
integer (kind=int_kind) :: &
daymo365(12) , & ! number of days in each month
daycal365(13) ! day number at end of month
data daymo365 / 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31/
data daycal365/ 0,31, 59, 90,120,151,181,212,243,273,304,334,365/
! 366-day year data (leap year)
integer (kind=int_kind) :: &
daymo366(12) , & ! number of days in each month
daycal366(13) ! day number at end of month
data daymo366 / 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31/
data daycal366/ 0,31, 60, 91,121,152,182,213,244,274,305,335,366/
integer (kind=int_kind) :: &
istep , & ! local step counter for time loop
istep0 , & ! counter, number of steps taken in previous run
istep1 , & ! counter, number of steps at current timestep
mday , & ! day of the month
hour , & ! hour of the year
month , & ! month number, 1 to 12
monthp , & ! last month
year_init, & ! initial year
nyr , & ! year number
idate , & ! date (yyyymmdd)
idate0 , & ! initial date (yyyymmdd)
sec , & ! elapsed seconds into date
npt , & ! total number of time steps (dt)
stop_now , & ! if 1, end program execution
write_restart, & ! if 1, write restart now
diagfreq , & ! diagnostic output frequency (10 = once per 10 dt)
dumpfreq_n , & ! restart output frequency (10 = once per 10 d,m,y)
nstreams , & ! number of history output streams
histfreq_n(max_nstrm) ! history output frequency
real (kind=dbl_kind) :: &
dt , & ! thermodynamics timestep (s)
dt_thm , & ! thermodynamics timestep (s)
dt_dyn , & ! dynamics/transport/ridging timestep (s)
time , & ! total elapsed time (s)
time_forc , & ! time of last forcing update (s)
yday , & ! day of the year
nextsw_cday , & ! next day for sw calculation
tday , & ! absolute day number
xndt_dyn , & ! reduced timestep for dynamics: xndt_dyn=dt/dt_dyn
dayyr ! number of days per year
logical (kind=log_kind) :: &
new_year , & ! new year = .true.
new_month , & ! new month = .true.
new_day , & ! new day = .true.
new_hour , & ! new hour = .true.
write_ic , & ! write initial condition now
write_history(max_nstrm) ! write history now
character (len=1) :: &
histfreq(max_nstrm) , & ! history output frequency, 'y','m','d','h','1'
dumpfreq ! restart frequency, 'y','m','d'
character (len=char_len) :: calendar_type
integer :: nleaps = 0 ! The number of leap days *before* the current year
! This is set by ice_comp_mct and used there & here (must be consistent)
!=======================================================================
contains
!=======================================================================
!BOP
!
! !IROUTINE: init_calendar - initialize calendar variables
!
! !INTERFACE:
!
subroutine init_calendar 5,10
!
! !DESCRIPTION:
!
! Initialize calendar variables
!
! !REVISION HISTORY:
!
! authors: Elizabeth C. Hunke, LANL
! Tony Craig, NCAR
!
! !USES:
!
! !INPUT/OUTPUT PARAMETERS:
!
!EOP
!
integer (kind=int_kind) :: &
k , &
istep = 0 ! local timestep number
time=istep0*dt ! s
#ifdef CCSMCOUPLED
time_forc = c0 ! for coupled runs
#endif
yday=c0 ! absolute day number
mday=0 ! day of the month
month=0 ! month
nyr=0 ! year
idate=00000101 ! date
sec=0 ! seconds into date
istep1 = istep0 ! number of steps at current timestep
! real (dumped) or imagined (use to set calendar)
stop_now = 0 ! end program execution if stop_now=1
dt_thm = dt ! convenience copy of thermodynamic timestep
dt_dyn = dt/xndt_dyn ! dynamics et al timestep
dayyr = real(days_per_year, kind=dbl_kind) ! days_per_year set by ice_init
! determine initial date (assumes namelist year_init, istep0 unchanged)
sec = mod(time,secday) ! elapsed seconds into date at
! end of dt
tday = (time-sec)/secday + c1 ! absolute day number
!(The following leap-year code is repeated in the calendar subroutine below)
if (calendar_type == "GREGORIAN") then
! divide the number of days by the number of days in 400 years (the length of a leap-year cycle)
nyr = int((tday-c1)*real(400.,kind=dbl_kind)/(400*365 + 97 )) + 1
else
nyr = int((tday-c1)/dayyr) + 1 ! year number
endif
! get the daycal variable, which is dependant on calendar and days_per_year
call get_daycal
(year=nyr+year_init-1,days_per_year_in=days_per_year,&
daycal_out=daycal,daymo_out=daymo)
! subtract the number of days in prior years from the number of days to get the number of days this year
yday = tday-nleaps - (nyr-1)*dayyr ! days that have passed this year
do k = 1, 12
if (yday > real(daycal(k),kind=dbl_kind)) month = k
enddo
mday = int(yday) - daycal(month) ! day of the month
idate0 = (nyr+year_init-1)*10000 + month*100 + mday ! date (yyyymmdd)
end subroutine init_calendar
!=======================================================================
!BOP
!
! !IROUTINE: calendar - computes date at the end of the time step
!
! !INTERFACE:
!
subroutine calendar(ttime) 6,5
!
! !DESCRIPTION:
!
! Determine the date at the end of the time step
!
! !REVISION HISTORY:
!
! authors: Elizabeth C. Hunke, LANL
! Tony Craig, NCAR
!
! !USES:
use ice_fileunits
use ice_communicate
, only: my_task, master_task
!
! !INPUT/OUTPUT PARAMETERS:
!
real (kind=dbl_kind), intent(in) :: &
ttime ! time variable
!
!EOP
!
integer (kind=int_kind) :: &
k, ns , &
nyrp,mdayp,hourp , & ! previous year, day, hour
elapsed_days , & ! since beginning this run
elapsed_months , & ! since beginning this run
elapsed_hours ! since beginning this run
nyrp=nyr
monthp=month
mdayp=mday
hourp=hour
new_year=.false.
new_month=.false.
new_day=.false.
new_hour=.false.
write_history(:)=.false.
write_restart=0
sec = mod(ttime,secday) ! elapsed seconds into date at
! end of dt
tday = (ttime-sec)/secday + c1 ! absolute day number
!(The following leap-year code is repeated in the init_calendar subroutine above)
if (calendar_type == "GREGORIAN") then
! divide the number of days by the number of days in 400 years (the length of a leap-year cycle)
nyr = int((tday-c1)*real(400.,kind=dbl_kind)/(400*365 + 97 )) + 1
else
nyr = int((tday-c1)/dayyr) + 1 ! year number
endif
! reset the number of leap days: this is necessary to add one one
! the year turns from a leap-year to a non-leap year
nleaps = leap_year_count
(nyr+year_init-1)
! get the daycal variable, depending on calendar and days_per_year
call get_daycal
(year=nyr+year_init-1,days_per_year_in=days_per_year,&
daycal_out=daycal)
! subtract the number of days in prior years from the number of days to get the number of days this year
yday = tday-nleaps - (nyr-1)*dayyr ! days that have passed this year
do k = 1, 12
if (yday > real(daycal(k),kind=dbl_kind)) month = k
enddo
mday = int(yday) - daycal(month) ! day of the month
hour = int((ttime-dt)/c3600) + c1 ! hour
elapsed_months = (nyr - 1)*12 + month - 1
elapsed_days = int(tday) - 1
elapsed_hours = int(ttime/3600)
idate = (nyr+year_init-1)*10000 + month*100 + mday ! date (yyyymmdd)
#ifndef CCSMCOUPLED
if (istep >= npt+1) stop_now = 1
#endif
if (nyr /= nyrp) new_year = .true.
if (month /= monthp) new_month = .true.
if (mday /= mdayp) new_day = .true.
if (hour /= hourp) new_hour = .true.
do ns = 1, nstreams
if (histfreq(ns)=='1' .and. histfreq_n(ns)/=0) then
if (mod(istep1, histfreq_n(ns))==0) &
write_history(ns)=.true.
endif
enddo
if (istep > 1) then
do ns = 1, nstreams
select case (histfreq(ns))
case ("y", "Y")
if (new_year .and. histfreq_n(ns)/=0) then
if (mod(nyr, histfreq_n(ns))==0) &
write_history(ns) = .true.
endif
case ("m", "M")
if (new_month .and. histfreq_n(ns)/=0) then
if (mod(elapsed_months,histfreq_n(ns))==0) &
write_history(ns) = .true.
endif
case ("d", "D")
if (new_day .and. histfreq_n(ns)/=0) then
if (mod(elapsed_days,histfreq_n(ns))==0) &
write_history(ns) = .true.
endif
case ("h", "H")
if (new_hour .and. histfreq_n(ns)/=0) then
if (mod(elapsed_hours,histfreq_n(ns))==0) &
write_history(ns) = .true.
endif
end select
enddo ! nstreams
select case (dumpfreq)
case ("y", "Y")
if (new_year .and. mod(nyr, dumpfreq_n)==0) &
write_restart = 1
case ("m", "M")
if (new_month .and. mod(elapsed_months,dumpfreq_n)==0) &
write_restart=1
case ("d", "D")
if (new_day .and. mod(elapsed_days, dumpfreq_n)==0) &
write_restart = 1
case default
call abort_ice
('ice_calendar: Invalid dumpfreq: '//dumpfreq)
end select
endif
if (my_task == master_task .and. mod(istep,diagfreq) == 0 &
.and. stop_now /= 1) then
write(nu_diag,*) ' '
write(nu_diag,'(a7,i10,4x,a6,i10,4x,a4,i10)') &
'istep1:', istep1, 'idate:', idate, 'sec:', sec
endif
end subroutine calendar
!=======================================================================
subroutine get_daycal(year,days_per_year_in,daycal_out,daymo_out) 3,6
! Input/output paramters
integer, intent(in), optional :: year ! year
integer, intent(in), optional :: days_per_year_in ! 360 or 365
integer, intent(out), optional :: daycal_out(13) ! cumumulative days per month
integer, intent(out), optional :: daymo_out(12) ! days per month
! 360-day year data
integer (kind=int_kind) :: &
daymo360(12) , & ! number of days in each month
daycal360(13) ! day number at end of month
data daymo360 / 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30/
data daycal360/ 0,30, 60, 90,120,150,180,210,240,270,300,330,360/
! 365-day year data
integer (kind=int_kind) :: &
daymo365(12) , & ! number of days in each month
daycal365(13) ! day number at end of month
data daymo365 / 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31/
data daycal365/ 0,31, 59, 90,120,151,181,212,243,273,304,334,365/
! 366-day year data (leap year)
integer (kind=int_kind) :: &
daycal366(13) ! day number at end of month
data daycal366/ 0,31, 60, 91,121,152,182,213,244,274,305,335,366/
if ( present(daymo_out) ) then
if ( .not. present(days_per_year_in)) &
call abort_ice
('ice: get_daycal needs days_per_year_in to return daymo_out')
if (days_per_year_in.eq.360) then
daymo_out = daymo360
elseif (days_per_year_in.eq.365) then
daymo_out = daymo365
else
call abort_ice
('ice: year must have 360 or 365 days')
endif
endif ! daymo_out
if ( present(daycal_out) ) then
! initialize to check for non-setting
daycal_out(:) = 0
! calculate from days_per_year_in
if ( present(days_per_year_in) ) then
if (days_per_year_in.eq.360) then
daycal_out = daycal360
elseif (days_per_year_in.eq.365) then
daycal_out = daycal365
else
call abort_ice
('ice: year must have 360 or 365 days')
endif
endif ! present(days_per_year_in)
if (calendar_type == "GREGORIAN") then
if ( .not. present(year) ) &
call abort_ice
('ice: get_daycal needs year to return daycal_out for Gregorian calendar')
if ( is_leap_year
(year) ) then
daycal_out = daycal366
else
daycal_out = daycal365
endif
endif ! calendar_type GREGORIAN
if ( daycal_out(13) .eq. 0 ) call abort_ice
('ice: get_daycal failed to set daycal_out')
endif ! daycal_out
end subroutine get_daycal
!=======================================================================
logical function is_leap_year(year) 1
! returns .true. if year is a leap year
! Input/output paramters
integer, intent(in) :: year
is_leap_year = .false.
if (mod(year, 4) == 0) is_leap_year = .true.
if (mod(year,100) == 0) is_leap_year = .false.
if (mod(year,400) == 0) is_leap_year = .true.
end function is_leap_year
!=======================================================================
integer function leap_year_count(Y) 2
! counts the number of leap years since year 1
! Input/output paramters
integer, intent(in) :: Y
if (calendar_type == "GREGORIAN") then
! count the number of leap years before Y
if ( Y .lt. 0 ) then
leap_year_count = 0
write(6,*) 'WARNING: leap_year_count for year ',Y,'assumes no leap years before year 0'
else
leap_year_count = ( (Y-1)/4 - (Y-1)/100 + (Y-1)/400 ) + 1 ! +1 for year 0
endif
else
leap_year_count = 0
endif
! set module variable
nleaps = leap_year_count
return
end function leap_year_count
end module ice_calendar
!=======================================================================