LCOV - code coverage report
Current view: top level - configuration/driver - icedrv_calendar.F90 (source / functions) Coverage Total Hit
Test: 250115-224328:3d8b76b919:4:base,io,travis,quick Lines: 90.14 % 142 128
Test Date: 2025-01-15 16:24:29 Functions: 100.00 % 5 5

            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              : !=======================================================================
        

Generated by: LCOV version 2.0-1