! ================================================================================================================================
!  MODULE       : time
!
!  CONTACT      : orchidee-help _at_ ipsl.jussieu.fr
!
!  LICENCE      : IPSL (2006)
!  This software is governed by the CeCILL licence see ORCHIDEE/ORCHIDEE_CeCILL.LIC
!
!>\BRIEF   This module contians the time information for ORCHIDEE
!!
!!\n DESCRIPTION: This module contains the time information for ORCHIDEE.
!! Time variables are calculated and updated at each time step. The variables are public and can be used from other modules.
!! The time variables must not be modified outside this module. 
!!
!! Time variables in this module are given for the interval corresponding to current time-step. 
!! The variables xxx_start and xxx_end are given to describe the time interval, either on julian(julian_start, julian_end) or 
!! yymmddsec format (year_start/end, month_start/end, day_start/end, sec_start/end). The variables can be used in all other modules. 
!! Logical variables telling if it's the last or first time-step of the day, of the month or of the year are also available.  
!!
!! Subroutines in module time : 
!!   time_initialize : To initialize time variables. 
!!                     Public subroutine called from intersurf_initialize_2d, intersurf_initialize_gathered or orchideedriver.
!!                     This subroutine is called before the first call to sechiba.
!!   time_nextstep   : Update time variables in the beginning at each new time step.
!!                     Public subroutine called from intersurf_main_2d, intersurf_main_gathered or orchideedriver.
!!   time_interval   : Calculate the interval for a given time step. Local subroutine, called from time_nextstep. 
!!
!! REFERENCE(S)	: None
!!
!! SVN          :
!! $HeadURL: svn://forge.ipsl.fr/orchidee/trunk/ORCHIDEE/src_global/time.f90 $
!! $Date: 2023-07-04 15:51:03 +0200 (mar. 04 juil. 2023) $
!! $Revision: 8070 $
!! \n
!_ ================================================================================================================================
MODULE time

  USE defprec
  USE constantes_var
  USE mod_orchidee_para_var, ONLY : numout
  USE ioipsl
  USE ioipsl_para
  USE function_library,  ONLY: get_printlev
  
  IMPLICIT NONE
  PRIVATE

  PUBLIC :: time_initialize, time_nextstep

  REAL(r_std), PUBLIC                 :: dt_sechiba         !! Lenght of time step in sechiba (s)
!$OMP THREADPRIVATE(dt_sechiba)
  REAL(r_std), PUBLIC                 :: dt_stomate         !! Length of time step in slow processes in stomate (s)
!$OMP THREADPRIVATE(dt_stomate)
  CHARACTER(LEN=20), PUBLIC           :: calendar_str       !! The calendar type
!$OMP THREADPRIVATE(calendar_str)
  INTEGER(i_std), SAVE, PUBLIC        :: year_start         !! Year at beginng of current time step
!$OMP THREADPRIVATE(year_start)
  INTEGER(i_std), SAVE, PUBLIC        :: month_start        !! Month at beginng of current time step
!$OMP THREADPRIVATE(month_start)
  INTEGER(i_std), SAVE, PUBLIC        :: day_start          !! Day in month at beginng of current time step
!$OMP THREADPRIVATE(day_start)
  REAL(r_std), SAVE, PUBLIC           :: sec_start          !! Seconds in the day at beginng of current time step
!$OMP THREADPRIVATE(sec_start)
  INTEGER(i_std), SAVE, PUBLIC        :: year_end           !! Year at end of current time step
!$OMP THREADPRIVATE(year_end)
  INTEGER(i_std), SAVE, PUBLIC        :: month_end          !! Month at end of current time step
!$OMP THREADPRIVATE(month_end)
  INTEGER(i_std), SAVE, PUBLIC        :: day_end            !! Day in month at end of current time step
!$OMP THREADPRIVATE(day_end)
  REAL(r_std), SAVE, PUBLIC           :: sec_end            !! Seconds in the day at end of current time step
!$OMP THREADPRIVATE(sec_end)
  CHARACTER(LEN=6), SAVE, PUBLIC      :: tstepint_type      !! Position of time step in the time interval
!$OMP THREADPRIVATE(tstepint_type)
  INTEGER(i_std), PUBLIC              :: month_len          !! Lenght of current month (d)
!$OMP THREADPRIVATE(month_len)
  REAL(r_std), PUBLIC                 :: one_day            !! Lenght of one day in seconds (s)
!$OMP THREADPRIVATE(one_day)
  REAL(r_std), PUBLIC                 :: one_year           !! Length of current year in days (d)
!$OMP THREADPRIVATE(one_year)
  REAL(r_std), PARAMETER, PUBLIC      :: one_hour = 3600.0  !! Lenght of hour in seconds (s)  

  LOGICAL, PUBLIC                     :: FirstTsYear        !! Flag is true for the first sechiba time step on the year.
!$OMP THREADPRIVATE(FirstTsYear)
  LOGICAL, PUBLIC                     :: LastTsYear         !! Flag is true for the last sechiba time step of the year, previously named EndOfYear
!$OMP THREADPRIVATE(LastTsYear)
  LOGICAL, PUBLIC                     :: FirstTsMonth       !! Flag is true for the first sechiba time step of the month. 
!$OMP THREADPRIVATE(FirstTsMonth)
  LOGICAL, PUBLIC                     :: LastTsMonth        !! Flag is true for the last sechiba time step of the month. 
!$OMP THREADPRIVATE(LastTsMonth)
  LOGICAL, PUBLIC                     :: FirstTsDay         !! Flag is true for the first sechiba time step of the day. 
!$OMP THREADPRIVATE(FirstTsDay)
  LOGICAL, PUBLIC                     :: LastTsDay          !! Flag is true for the last sechiba time step of the day. 
!$OMP THREADPRIVATE(LastTsDay)
  LOGICAL, PUBLIC                     :: FirstDayYear       !! Flag is true during the whole time step for the first day of the year
!$OMP THREADPRIVATE(FirstDayYear)
  LOGICAL, PUBLIC                     :: annual_proc_end_of_year !! Flag to determine when the annual processes should be done
!$OMP THREADPRIVATE(annual_proc_end_of_year)
  LOGICAL, PUBLIC                     :: ts_annual_proc     !! Flag is true when it is the time-step for the annual processes to be done.
                                                            !! By default this equals to last time-step of the year but it can be changed from run.def
!$OMP THREADPRIVATE(ts_annual_proc)
  REAL(r_std), SAVE, PUBLIC           :: date0_save         !! Start date of simulation, in juilan calendar
!$OMP THREADPRIVATE(date0_save)
  REAL(r_std), PUBLIC                 :: julian_diff        !! Days since the beginning of current year
!$OMP THREADPRIVATE(julian_diff)
  REAL(r_std), PUBLIC                 :: julian_start       !! Beginning of the interval for current time step, in juilan calendar
!$OMP THREADPRIVATE(julian_start)
  REAL(r_std), PUBLIC                 :: julian_end         !! End of the interval for current time step, in juilan calendar
!$OMP THREADPRIVATE(julian_end)
  REAL(r_std), SAVE, PUBLIC           :: julian0            !! First day of this year in julian caledrier
!$OMP THREADPRIVATE(julian0)
  INTEGER(i_std), SAVE, PRIVATE       :: printlev_loc       !! Local level of text output for current module
!$OMP THREADPRIVATE(printlev_loc)
  

CONTAINS

!!  =============================================================================================================================
!! SUBROUTINE:    time_initialize()
!!
!>\BRIEF	  Initalize time information
!!
!! DESCRIPTION:	  Initialize time information. This subroutine is called only in the intialization phase of the model and gives
!!                the basic information on the calendar and time interval.
!!
!! \n
!_ ==============================================================================================================================

  SUBROUTINE time_initialize(kjit, date0_loc, dt_sechiba_loc, tstepint)

    !! 0.1 Input arguments
    INTEGER(i_std), INTENT(in)   :: kjit           !! Time step of the restart file
    REAL(r_std), INTENT(in)      :: date0_loc      !! The date at which kjit=0
    REAL(r_std), INTENT(in)      :: dt_sechiba_loc !! Time step of sechiba component
    CHARACTER(LEN=*), INTENT(in) :: tstepint       !! Position of the time stamp: beginning, centre or end of time step 
                                                   !! Possible values for tstepint : START, CENTER, END

    !! Initialize local printlev variable
    printlev_loc=get_printlev("time")

    !! Save length of sechiba time step in module variable
    !! Time step for sechiba comes from the atmospheric model or from the 
    !! offline driver which reads it from parameter DT_SECHIBA
    dt_sechiba = dt_sechiba_loc

    !! Save tstepint in global variable
    tstepint_type = tstepint
    IF (tstepint_type /= "START" .AND. tstepint_type /= "END") THEN
       WRITE(numout,*) 'Unknown option for time interval, tstepint_type=', tstepint_type
       CALL ipslerr_p(3,'time_initialize', 'Unknown time iterval type.',&
            'The time stamp given can have 2 position on the interval :',' START or END')
    END IF

    !! Save the start date in the module
    date0_save = date0_loc

    !! Get the calendar from IOIPSL, it is already initialized
    CALL ioget_calendar(calendar_str)

    !! Get year lenght in days and day lenght in seconds
    CALL ioget_calendar(one_year, one_day)

    !Config Key   = DT_STOMATE
    !Config Desc  = Time step of STOMATE and other slow processes
    !Config If    = OK_STOMATE
    !Config Def   = one_day
    !Config Help  = Time step (s) of regular update of vegetation
    !Config         cover, LAI etc. This is also the time step of STOMATE.
    !Config Units = [seconds]
    dt_stomate = one_day
    CALL getin_p('DT_STOMATE', dt_stomate)

 
    IF (printlev_loc >=1) THEN
       WRITE(numout,*) "time_initialize : calendar_str= ",calendar_str
       WRITE(numout,*) "time_initialize : dt_sechiba(s)= ",dt_sechiba," dt_stomate(s)= ", dt_stomate
       WRITE(numout,*) "time_initialize : date0_save= ",date0_save," kjit= ",kjit
    ENDIF


    !Config Key   = ANNUAL_PROC_END_OF_YEAR
    !Config Desc  = If true the annual processes are done at the last time-step of the year(recommanded), otherwise it is done the last time-step of June
    !Config If    = OK_STOMATE
    !Config Def   = y
    !Config Help  = Setting this option to false is only done to test restartability for annual processes in stomate
    !Config Units = [flag]
    annual_proc_end_of_year=.TRUE.
    CALL getin_p('ANNUAL_PROC_END_OF_YEAR', annual_proc_end_of_year)
    
    
    CALL time_nextstep(kjit)
    
  END SUBROUTINE time_initialize
  
!!  =============================================================================================================================
!! SUBROUTINE:    time_nextstep()
!!
!>\BRIEF	  Update the time information for the next time step.
!!
!! DESCRIPTION:	  This subroutine will place in the public variables of the module all the time information
!!                needed by ORCHIDEE for this new time step.
!!
!! \n
!_ ==============================================================================================================================
  SUBROUTINE time_nextstep(kjit)
    
    !! 0.1 Input variables
    INTEGER(i_std), INTENT(in)   :: kjit       !! Current time step
    LOGICAL                      :: LastTsJune !! Last time step in June

    !! Calculate the new time interval for current time step
    CALL time_interval(kjit, year_start, month_start, day_start, sec_start, julian_start, &
                             year_end,   month_end,   day_end,   sec_end,   julian_end)
    
    !! Calculate julian0: the julian date for the 1st of January in current year
    IF ( kjit == 0 ) then
       CALL ymds2ju(year_end, 1, 1, zero, julian0)
    ELSE
       CALL ymds2ju(year_start, 1, 1, zero, julian0)
    END IF

    !! Caluclate julian_diff: The diffrence of the end of current time-step and the beginning of the year in julian days
    julian_diff = julian_end - julian0

    !! Update variables for year length
    CALL ioget_calendar(one_year, one_day)

    !! Calculate number of days in the current month, using the start of the time-interval for current time-step
    month_len = ioget_mon_len(year_start,month_start)


    !! Calculate logical variables true if the current time-step corresponds to the end or beggining of a day, month or year
    FirstTsDay = .FALSE.
    FirstTsMonth = .FALSE.
    FirstTsYear = .FALSE.
    LastTsDay = .FALSE.
    LastTsMonth = .FALSE.
    LastTsYear = .FALSE.
    LastTsJune = .FALSE.
    FirstDayYear = .FALSE.
 
    IF (sec_start >= -1 .AND. sec_start < dt_sechiba-1 ) THEN
       FirstTsDay = .TRUE.
       IF ( day_start == 1 ) THEN
          FirstTsMonth = .TRUE.
          IF ( month_start == 1) THEN
             FirstTsYear = .TRUE.
          END IF
       END IF
    ELSE IF (sec_start >= one_day-dt_sechiba-1 .AND. sec_start < one_day-1 ) THEN
       LastTsDay = .TRUE.
       IF ( day_start == month_len ) THEN
          LastTsMonth = .TRUE.
          IF ( month_start == 12) THEN
             LastTsYear = .TRUE.
          ELSEIF ( month_start == 6) THEN
             LastTsJune = .TRUE.
          END IF
       END IF
    END IF

    IF (day_start ==1 .AND. month_start ==1) THEN
       FirstDayYear = .TRUE.
    END IF

    !! Set ts_annual_proc
    IF (annual_proc_end_of_year) THEN
       ! By default, the last time-step of the year is set
       ts_annual_proc=LastTsYear
    ELSE
       ! Else, the last time-step of June is set
       ts_annual_proc=LastTsJune
    END IF
    
    

    !! Write debug information depending on printlev_loc.
    IF ( ((printlev_loc >= 4) .OR. (printlev_loc >=2 .AND. FirstTsMonth)) .OR. (printlev_loc>=1 .AND. FirstTsYear)) THEN
       WRITE(numout,*) "time_nextstep: Time interval for time step :", kjit
       WRITE(numout,"(' time_nextstep: Start of interval         ', I4.4,'-',I2.2,'-',I2.2,' ',F12.4)") &
            year_start, month_start, day_start, sec_start
       WRITE(numout,"(' time_nextstep: End of interval           ', I4.4,'-',I2.2,'-',I2.2,' ',F12.4)") &
            year_end, month_end, day_end, sec_end
       WRITE(numout,*) "time_nextstep: month_len=",month_len, " one_year=",one_year
       WRITE(numout,*) ""
    END IF
    IF (printlev_loc >= 4) THEN
       WRITE(numout,*) "time_nextstep: FirstTsDay=", FirstTsDay," FirstTsMonth=",FirstTsMonth," FirstTsYear=", FirstTsYear
       WRITE(numout,*) "time_nextstep: LastTsDay=", LastTsDay," LastTsMonth=",LastTsMonth," LastTsYear=", LastTsYear
       WRITE(numout,*) "time_nextstep: julian0=",julian0, " julian_diff=",julian_diff
       WRITE(numout,*) "time_nextstep: ts_annual_proc=",ts_annual_proc
       WRITE(numout,*) ""
    ELSEIF ((printlev_loc >= 2) .AND. ts_annual_proc) THEN
       WRITE(numout,*) "time_nextstep: ts_annual_proc=TRUE"
    END IF

    IF ((printlev_loc >= 2) .AND. FirstTsDay) THEN
       WRITE(numout,"(' Date: ', I4.4,'-',I2.2,'-',I2.2,' ',F8.4,'sec at timestep ',I12.4)") &
            year_start, month_start, day_start, sec_start, kjit
    END IF
    
  END SUBROUTINE time_nextstep

!!  =============================================================================================================================
!! SUBROUTINE:    time_interval()
!!
!>\BRIEF	  Computes the interval corresponging to the given time step.
!!
!! DESCRIPTION:	  This subroutine will compute the interval of time for the given time step.
!!                It will use the tstepint_type variable which was set at initilisation. 
!!
!! \n
!_ ==============================================================================================================================

  SUBROUTINE time_interval(kjit, year_s, month_s, day_s, sec_s, julian_s, &
                                 year_e, month_e, day_e, sec_e, julian_e)

    !! 0.1 Input variables
    INTEGER(i_std), INTENT(in)                  :: kjit      !! Current time step

    !! 0.2 Output variables
    INTEGER(i_std), INTENT(out)                 :: year_s, month_s, day_s
    INTEGER(i_std), INTENT(out)                 :: year_e, month_e, day_e
    REAL(r_std), INTENT(out)                    :: sec_s, julian_s
    REAL(r_std), INTENT(out)                    :: sec_e, julian_e
    

    !! Calculate the interval for current time step
    !! tstepint_type is used to know how the interval is defined around the time-stamp of the time-step 
    SELECT CASE (TRIM(tstepint_type))
       CASE ("START ")
          !! Calculate the start date of the interval
          julian_s = itau2date(kjit, date0_save, dt_sechiba)
          !! Calculate the end date of the interval using kjti+1
          julian_e = itau2date(kjit+1, date0_save, dt_sechiba)
       CASE("END")
          !! Calculate the start date of the interval
          julian_s = itau2date(kjit-1, date0_save, dt_sechiba)
          !! Calculate the end date of the interval
          julian_e = itau2date(kjit, date0_save, dt_sechiba)
       CASE DEFAULT
          WRITE(numout,*) "time_interval: tstepint_type = ", tstepint_type
          CALL ipslerr_p(3,'time_interval', 'Unknown time iterval type.', &
               'The time stamp given can have 3 position on the interval :',' START, CENTER or END')
       END SELECT

       !! Calculate year, month, day and sec for julian_s date
       CALL ju2ymds (julian_s, year_s, month_s, day_s, sec_s)

       !! Calculate year, month, day and sec for julian_e date
       CALL ju2ymds (julian_e, year_e, month_e, day_e, sec_e)

    
  END SUBROUTINE time_interval

END MODULE time
