LCOV - code coverage report
Current view: top level - configuration/driver - icedrv_calendar.F90 (source / functions) Hit Total Coverage
Test: 200624-002105:0a37e99f7c:3:base,travis,quick Lines: 132 144 91.67 %
Date: 2020-06-23 18:30:56 Functions: 5 5 100.00 %

          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          42 :       subroutine init_calendar
     112             :       character(len=*), parameter :: subname='(init_calendar)'
     113             : 
     114             :       !-----------------------------------------------------------------
     115             :       ! query Icepack values
     116             :       !-----------------------------------------------------------------
     117             : 
     118          42 :       call icepack_query_parameters(secday_out=secday)
     119          42 :       call icepack_warnings_flush(nu_diag)
     120          42 :       if (icepack_warnings_aborted()) call icedrv_system_abort(string=subname, &
     121           0 :           file=__FILE__,line= __LINE__)
     122             : 
     123             :       !-----------------------------------------------------------------
     124             : 
     125          42 :       istep = 0         ! local timestep number
     126          42 :       time=istep0*dt    ! s
     127          42 :       yday=c0           ! absolute day number
     128          42 :       mday=0            ! day of the month
     129          42 :       month=0           ! month
     130          42 :       nyr=0             ! year
     131          42 :       idate=00000101    ! date
     132          42 :       sec=0             ! seconds into date
     133          42 :       istep1 = istep0   ! number of steps at current timestep
     134             :                         ! real (dumped) or imagined (use to set calendar)
     135          42 :       stop_now = 0      ! end program execution if stop_now=1
     136          42 :       dt_dyn = dt/real(ndtd,kind=dbl_kind) ! dynamics et al timestep
     137          42 :       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          42 :       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          42 :       calendar_type = ' '
     148          42 :       if (use_leap_years .and. days_per_year == 365) calendar_type = 'Gregorian'
     149             :       
     150          42 :       dayyr = real(days_per_year, kind=dbl_kind)
     151          42 :       if (days_per_year == 360) then
     152           3 :          daymo  = daymo360
     153           3 :          daycal = daycal360
     154          39 :       elseif (days_per_year == 365) then
     155          39 :          daymo  = daymo365
     156          39 :          daycal = daycal365
     157             :       endif
     158             : 
     159             :       ! Get the time in seconds from calendar zero to start of initial year
     160          42 :       call time2sec(year_init,1,1,basis_seconds)
     161             : 
     162             :       ! determine initial date (assumes namelist year_init, istep0 unchanged)     
     163          42 :       sec = mod(time,secday)            ! elapsed seconds into date at
     164             :                                         ! end of dt
     165          42 :       tday = (time-sec)/secday + c1     ! absolute day number
     166             : 
     167             :       ! Convert the current timestep into a calendar date
     168          42 :       call sec2time(nyr,month,mday,basis_seconds+sec)
     169             : 
     170          42 :       yday = mday + daycal(month)  ! day of the year
     171          42 :       nyr = nyr - year_init + 1    ! year number
     172             : 
     173          42 :       idate0 = (nyr+year_init-1)*10000 + month*100 + mday ! date (yyyymmdd) 
     174             : 
     175          42 :       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      318506 :       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      318506 :       nyrp=nyr
     201      318506 :       monthp=month
     202      318506 :       mdayp=mday
     203      318506 :       hourp=hour
     204      318506 :       new_year=.false.
     205      318506 :       new_month=.false.
     206      318506 :       new_day=.false.
     207      318506 :       new_hour=.false.
     208      318506 :       write_restart=0
     209             : 
     210      318506 :       sec = mod(ttime,secday)           ! elapsed seconds into date at
     211             :                                         ! end of dt
     212      318506 :       tday = (ttime-sec)/secday + c1    ! absolute day number
     213             : 
     214             :       ! Deterime the current date from the timestep
     215      318506 :       call sec2time(nyr,month,mday,basis_seconds+ttime)
     216             : 
     217      318506 :       yday = mday + daycal(month)   ! day of the year
     218      318506 :       nyr = nyr - year_init + 1     ! year number
     219             :       
     220      318506 :       hour = int((ttime)/c3600) + c1 ! hour
     221             : 
     222      318506 :       idate = (nyr+year_init-1)*10000 + month*100 + mday ! date (yyyymmdd) 
     223             : 
     224      318506 :       if (istep >= npt+1)  stop_now = 1
     225      318506 :       if (nyr   /= nyrp)   new_year = .true.
     226      318506 :       if (month /= monthp) new_month = .true.
     227      318506 :       if (mday  /= mdayp)  new_day = .true.
     228      318506 :       if (hour  /= hourp)  new_hour = .true.
     229             : 
     230      318506 :       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      302808 :           if (new_month) &
     238      302808 :                 write_restart = 1
     239             :         case ("d", "D")
     240        8760 :           if (new_day) &
     241      327168 :                 write_restart = 1
     242             :         end select
     243             : 
     244      318408 :         if (force_restart_now) write_restart = 1
     245      318408 :         if (dump_last .and. istep == npt) write_restart = 1
     246             :       
     247             :       endif !  istep > 1
     248             : 
     249      318506 :       if (mod(istep,diagfreq) == 0 .and. stop_now /= 1) then
     250      182215 :         do ns = 1, nx
     251      145772 :           write(nu_diag_out+ns-1,*) ' '
     252             :           write(nu_diag_out+ns-1,'(a7,i10,4x,a6,i10,4x,a4,i10)') &
     253      182215 :               'istep1:', istep1, 'idate:', idate, 'sec:', sec
     254             :         end do
     255             :       endif
     256             : 
     257      318506 :       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          42 :       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          15 :       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          42 :       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          39 :          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          38 :             days_since_calz = c365*year + daycal365(month) + day - c1
     319          38 :             tsec = secday * days_since_calz
     320             : 
     321             :          end if
     322             : 
     323             :       end if
     324             : 
     325          42 :       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      318548 :       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      109858 :       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      318548 :       days_since_calz = int(tsec/secday)
     347             : 
     348      318548 :       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      294406 :          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      285643 :             year = int(days_since_calz/c365)
     399      285643 :             days_since_calz = days_since_calz - year*365 + 1
     400             :       
     401             :             ! Calculate the month
     402      285643 :             month = 1
     403     3713359 :             do k = 1, 12
     404     3713359 :                if (days_since_calz > daycal365(k)) month = k
     405             :             enddo
     406             : 
     407             :             ! Calculate the day of the month
     408      285643 :             day = days_since_calz - daycal365(month)
     409             : 
     410             :          end if
     411             : 
     412             :       end if
     413             : 
     414      318548 :       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             : !=======================================================================

Generated by: LCOV version 1.14-6-g40580cd