!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!!                                                                   !!
!!                   GNU General Public License                      !!
!!                                                                   !!
!! This file is part of the Flexible Modeling System (FMS).          !!
!!                                                                   !!
!! FMS is free software; you can redistribute it and/or modify       !!
!! it and are expected to follow the terms of the GNU General Public !!
!! License as published by the Free Software Foundation.             !!
!!                                                                   !!
!! FMS is distributed in the hope that it will be useful,            !!
!! but WITHOUT ANY WARRANTY; without even the implied warranty of    !!
!! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the     !!
!! GNU General Public License for more details.                      !!
!!                                                                   !!
!! You should have received a copy of the GNU General Public License !!
!! along with FMS; if not, write to:                                 !!
!!          Free Software Foundation, Inc.                           !!
!!          59 Temple Place, Suite 330                               !!
!!          Boston, MA  02111-1307  USA                              !!
!! or see:                                                           !!
!!          http://www.gnu.org/licenses/gpl.txt                      !!
!!                                                                   !!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
program main
!  
!<CONTACT EMAIL="Matthew.Harrison@noaa.gov"> Matt Harrison
!</CONTACT>
!
!<REVIEWER EMAIL="V.Balaji@noaa.gov"> V. Balaji
!</REVIEWER>
!
!<REVIEWER EMAIL="Stephen.Griffies@noaa.gov"> Stephen Griffies 
!</REVIEWER>
!
!<OVERVIEW>
! Driver for ocean-only simulations.
!</OVERVIEW>
!
!<DESCRIPTION>
! Driver for the ocean-only simulations. Similar to the FMS coupler, but 
! allows one to run the ocean model without compiling  other models. 
! Much simpler than the full FMS coupler. 
! </DESCRIPTION>
!
! <NAMELIST NAME="ocean_solo_nml">
!
!   <DATA NAME="date_init"  TYPE="integer, dimension(6)"  DEFAULT="0">
!     The date that the current integration starts with. If the restart file
!      ocean_solo.res is present, date_init will be taken from there.
!   </DATA>
!   <DATA NAME="calendar"  TYPE="character(maxlen=17)"  DEFAULT="''">
!     The calendar type used by the current integration. Valid values are consistent 
!     with the time_manager module: 'julian', 'noleap', or 'thirty_day'. The value 
!     'no_calendar' can not be used because the time_manager's date  function are used. 
!     
!   </DATA>
!   <DATA NAME="months "  TYPE="integer"  DEFAULT="0">
!     The number of months that the current integration will be run for. 
!   </DATA>
!   <DATA NAME="days "  TYPE="integer"  DEFAULT="0">
!     The number of days that the current integration will be run for. 
!   </DATA>
!   <DATA NAME="hours"  TYPE="integer"  DEFAULT="0">
!     The number of hours that the current integration will be run for. 
!   </DATA>
!   <DATA NAME="minutes "  TYPE="integer"  DEFAULT="0">
!     The number of minutes that the current integration will be run for. 
!   </DATA>
!   <DATA NAME="seconds"  TYPE="integer"  DEFAULT="0">
!     The number of seconds that the current integration will be run for. 
!   </DATA>
!   <DATA NAME="dt_ocean"  TYPE="integer"  DEFAULT="0">
!     Ocean model time step in seconds. 
!   </DATA>
!   <DATA NAME="dt_cpld"  TYPE="integer"  DEFAULT="0">
!     Time step in seconds for coupling between ocean and atmospheric models: 
!     must be an integral multiple of dt_ocean. This is the "slow" timestep.
!     Note that for an ocean_solo model, the coupling to an "atmosphere" is the coupling 
!     to some data files.  In this case, dt_cpld represents the time which data is updated.
!     For example, if data is "daily", then dt_cpld=86400 should be chosen.  
!     If data is fixed, then dt_cpld of any integer of dt_ocean is fine, with
!     dt_cpld=86400 the default. 
!   </DATA>
!
! </NAMELIST>
!
!   <NOTE>
!     <PRE>
!     1.The actual run length will be the sum of months, 
!       days, hours, minutes, and seconds. A run length of zero
!       is not a valid option. 
!     2.The run length must be an integral multiple of the coupling 
!       timestep dt_cpld. 
!     </PRE>
!   </NOTE>
!
  use constants_mod,            only: constants_init
  use data_override_mod,        only: data_override_init, data_override
  use diag_manager_mod,         only: diag_manager_init, register_diag_field, diag_manager_end
  use field_manager_mod,        only: field_manager_init
  use fms_mod,                  only: fms_init, fms_end, open_namelist_file, check_nml_error
  use fms_mod,                  only: close_file, file_exist, uppercase
  use fms_io_mod,               only: fms_io_exit
  use mpp_domains_mod,          only: domain2d, mpp_get_compute_domain
  use mpp_io_mod,               only: mpp_open, MPP_RDONLY, MPP_ASCII, MPP_OVERWR, MPP_APPEND, mpp_close, MPP_SINGLE
  use mpp_mod,                  only: mpp_error, FATAL, mpp_pe, mpp_npes, mpp_set_current_pelist
  use mpp_mod,                  only: stdlog, stdout, mpp_root_pe, mpp_clock_id
  use mpp_mod,                  only: mpp_clock_begin, mpp_clock_end, MPP_CLOCK_SYNC
  use mpp_mod,                  only: MPP_CLOCK_DETAILED, CLOCK_COMPONENT
  use time_interp_external_mod, only: time_interp_external_init
  use time_manager_mod,         only: set_calendar_type, time_type, increment_time, increment_date
  use time_manager_mod,         only: set_time, set_date, get_time, get_date, month_name
  use time_manager_mod,         only: JULIAN, NOLEAP, THIRTY_DAY_MONTHS, NO_CALENDAR
  use time_manager_mod,         only: operator( <= ), operator( < ), operator( >= )
  use time_manager_mod,         only: operator( + ),  operator( - ), operator( / )

  use ocean_model_mod,          only: ocean_model_init , update_ocean_model, ocean_model_end
  use ocean_types_mod,          only: ocean_data_type, ice_ocean_boundary_type
#ifdef PRISM
  use ocean_prism_mod,          only: ocean_prism_init, localComm, ocean_prism_terminate
#endif
  implicit none

  type (ocean_data_type)                 :: Ocean_sfc          
  type(ice_ocean_boundary_type), target  :: Ice_ocean_boundary 

  ! define some time types 
  type(time_type) :: Time_init    ! initial time for experiment
  type(time_type) :: Time_start   ! start time for experiment
  type(time_type) :: Time_end     ! end time for experiment (as determined by dtts)
  type(time_type) :: Run_len      ! length of experiment 
  type(time_type) :: Time        
  type(time_type) :: Time_step_ocean    
  type(time_type) :: Time_step_coupled

  character(len=17) :: calendar = 'julian'

  integer :: dt_ocean = 3600
  integer :: dt_cpld  = 86400
  integer :: num_cpld_calls  = 0
  integer :: num_ocean_calls = 0
  integer :: nc, no
  integer :: calendar_type=-1

  integer :: date_init(6)=0, date(6)
  integer :: years=0, months=0, days=0, hours=0, minutes=0, seconds=0
  integer :: yr, mon, day, hr, min, sec

  integer :: isc,iec,jsc,jec
  integer :: unit, log_unit, io_status, ierr

  integer :: memuse
  integer :: flags=0, override_clock
  integer :: nfields 
  
  character(len=256) :: version = ''
  character(len=256) :: tag = ''

  logical :: ocean_seg_start
  logical :: ocean_seg_end

  character(len=9) :: month
  
  namelist /ocean_solo_nml/ date_init, calendar, months, days, hours, minutes, seconds, dt_cpld, dt_ocean

! initialize shared modules
#ifdef PRISM
  call ocean_prism_init(ierr)
  call fms_init(localComm)
#else
  call fms_init()
#endif
  call constants_init

  flags = MPP_CLOCK_SYNC

  ! provide for namelist over-ride
  unit = open_namelist_file('input.nml')
  read  (unit, ocean_solo_nml,iostat=io_status)
  write (stdout(),'(/)')
  write (stdout(),'(/47x,a/)') '======== MODEL BEING DRIVEN BY OCEAN_SOLO_MOD ========'
  write (stdout(), ocean_solo_nml)  
  write (stdlog(), ocean_solo_nml)
  ierr = check_nml_error(io_status,'ocean_solo_nml')
  call close_file (unit)

  write (stdlog(),'(/,80("="),/(a))') trim(version), trim(tag)

  ! set the calendar 

  select case( uppercase(trim(calendar)) )
  case( 'JULIAN' )
     calendar_type = JULIAN
  case( 'NOLEAP' )
     calendar_type = NOLEAP
  case( 'THIRTY_DAY' )
     calendar_type = THIRTY_DAY_MONTHS
  case( 'NO_CALENDAR' )
     calendar_type = NO_CALENDAR
  case default
     call mpp_error( FATAL, 'ocean_solo: ocean_solo_nml entry calendar must be one of JULIAN|NOLEAP|THIRTY_DAY|NO_CALENDAR.' )
  end select 

  ! get ocean_solo restart : this can override settings from namelist
  if (file_exist('INPUT/ocean_solo.res')) then
      call mpp_open(unit,'INPUT/ocean_solo.res',form=MPP_ASCII,action=MPP_RDONLY)
      read(unit,*) calendar_type 
      read(unit,*) date_init
      read(unit,*) date
      call close_file(unit)
  endif
      
  call set_calendar_type (calendar_type)

!!$ initialize pelists for ocean ensembles set current pelist to ensemble member
!!$ need to call prior to diagnostics_init
!!$ code presently not supported (mjh)
!!$  call ocean_ensemble_init() 
                             
  call field_manager_init(nfields)

  call diag_manager_init()

  call time_interp_external_init()

  if (sum(date_init) <= 0) then
      call mpp_error(FATAL,'==>Error from ocean_solo_mod: date_init must be set either in ocean_solo.res or in ocean_solo_nml')
  else
      Time_init  = set_date(date_init(1),date_init(2), date_init(3), &
           date_init(4),date_init(5),date_init(6))
  endif

  if (file_exist('INPUT/ocean_solo.res')) then
      Time_start =  set_date(date(1),date(2),date(3),date(4),date(5),date(6))
  else
      Time_start = Time_init
      date = date_init
  endif

  Time_end          = increment_date(Time_start, years, months, days, hours, minutes, seconds)
  Run_len           = Time_end - Time_start
  Time_step_ocean   = set_time(dt_ocean, 0)
  Time_step_coupled = set_time(dt_cpld, 0)
  num_cpld_calls    = Run_len / Time_step_coupled
  num_ocean_calls   = Time_step_coupled / Time_step_ocean
  Time = Time_start

  call mpp_open (unit, 'time_stamp.out', form=MPP_ASCII, action=MPP_APPEND,threading=MPP_SINGLE)

  month = month_name(date(2))
  if ( mpp_pe() == mpp_root_pe() ) write (unit,'(6i4,2x,a3)') date, month(1:3)

  call get_date (Time_end, date(1), date(2), date(3), date(4), date(5), date(6))
  month = month_name(date(2))
  if ( mpp_pe() == mpp_root_pe() ) write (unit,'(6i4,2x,a3)') date, month(1:3)

  call close_file (unit)  
  
  call ocean_model_init(Ocean_sfc, Time_init, Time, Time_step_ocean )

  call data_override_init(Ocean_domain_in = Ocean_sfc%domain)

  override_clock = mpp_clock_id('Override', flags=flags,grain=CLOCK_COMPONENT)
  
  call mpp_get_compute_domain(Ocean_sfc%domain, isc, iec, jsc, jec)
  
  allocate ( Ice_ocean_boundary% u_flux (isc:iec,jsc:jec), &
             Ice_ocean_boundary% v_flux (isc:iec,jsc:jec), &
             Ice_ocean_boundary% t_flux (isc:iec,jsc:jec), &
             Ice_ocean_boundary% q_flux (isc:iec,jsc:jec), &
             Ice_ocean_boundary% salt_flux (isc:iec,jsc:jec), &
             Ice_ocean_boundary% lw_flux (isc:iec,jsc:jec), &
             Ice_ocean_boundary% sw_flux (isc:iec,jsc:jec), &
             Ice_ocean_boundary% lprec (isc:iec,jsc:jec), &
             Ice_ocean_boundary% fprec (isc:iec,jsc:jec), &
             Ice_ocean_boundary% runoff (isc:iec,jsc:jec), &
             Ice_ocean_boundary% calving (isc:iec,jsc:jec), &
             Ice_ocean_boundary% p (isc:iec,jsc:jec))

  Ice_ocean_boundary%u_flux    = 0.0
  Ice_ocean_boundary%v_flux    = 0.0
  Ice_ocean_boundary%t_flux    = 0.0
  Ice_ocean_boundary%q_flux    = 0.0
  Ice_ocean_boundary%salt_flux = 0.0
  Ice_ocean_boundary%lw_flux   = 0.0
  Ice_ocean_boundary%sw_flux   = 0.0
  Ice_ocean_boundary%lprec     = 0.0
  Ice_ocean_boundary%fprec     = 0.0
  Ice_ocean_boundary%runoff    = 0.0
  Ice_ocean_boundary%calving   = 0.0
  Ice_ocean_boundary%p         = 0.0

  ! loop over the coupled calls 
  do nc=1, num_cpld_calls
     
     call mpp_clock_begin(override_clock)
     call ice_ocn_bnd_from_data(Ice_ocean_boundary)
     call mpp_clock_end(override_clock)
     
     ! loop over the ocean calls 
     do no=1, num_ocean_calls
        ocean_seg_start = ( no .eq. 1 )     
        ocean_seg_end   = ( no .eq. num_ocean_calls )
        call update_ocean_model(Ice_ocean_boundary, Ocean_sfc, ocean_seg_start, ocean_seg_end, num_ocean_calls)
        Time = Time + Time_step_ocean
     enddo

  enddo

  ! close some of the main components 

  call ocean_model_end(Ocean_sfc)

  call diag_manager_end(Time)

  ! need to reset pelist before calling mpp_clock_end
  call mpp_set_current_pelist() 

    ! write restart file
    call mpp_open( unit, 'RESTART/ocean_solo.res', nohdrs=.TRUE. )
    if ( mpp_pe().EQ.mpp_root_pe() )then
        write( unit, '(i6,8x,a)' )calendar_type, &
             '(Calendar: no_calendar=0, thirty_day_months=1, julian=2, gregorian=3, noleap=4)'

        call get_date(Time_init,yr,mon,day,hr,min,sec)
        write( unit, '(6i6,8x,a)' )yr,mon,day,hr,min,sec, &
             'Model start time:   year, month, day, hour, minute, second'
        call get_date(Time_end ,yr,mon,day,hr,min,sec)
        write( unit, '(6i6,8x,a)' )yr,mon,day,hr,min,sec, &
             'Current model time: year, month, day, hour, minute, second'
    end if
    call mpp_close(unit)
    call fms_io_exit
    call fms_end    
#ifdef PRISM
    call ocean_prism_terminate
#endif
  contains


!====================================================================
! get forcing data from data_overide 
  subroutine ice_ocn_bnd_from_data(x)

      type (ice_ocean_boundary_type) :: x
      integer                        :: i,j
      type(time_type)                :: Time_next

      Time_next = Time + Time_step_ocean      
      call data_override('OCN', 't_flux',    x%t_flux   , Time_next)
      call data_override('OCN', 'u_flux',    x%u_flux   , Time_next)
      call data_override('OCN', 'v_flux',    x%v_flux   , Time_next)
      call data_override('OCN', 'q_flux',    x%q_flux   , Time_next)
      call data_override('OCN', 'salt_flux', x%salt_flux, Time_next)
      call data_override('OCN', 'lw_flux',   x%lw_flux  , Time_next)
      call data_override('OCN', 'sw_flux',   x%sw_flux  , Time_next)
      call data_override('OCN', 'lprec',     x%lprec    , Time_next)
      call data_override('OCN', 'fprec',     x%fprec    , Time_next)
      call data_override('OCN', 'runoff',    x%runoff   , Time_next)
      call data_override('OCN', 'calving',   x%calving  , Time_next)
      call data_override('OCN', 'p',         x%p        , Time_next)
            
  end subroutine ice_ocn_bnd_from_data


end program main